itch.io is community of indie game creators and players

Devlogs

Using Iron Python, json, and Unity3d to make a modular game!

Infinite Progression
A downloadable game for Windows, Linux, and Android

Why would I even find this important?

So here I was programming a game years ago, and I realized how flawed the concept of a fully random idle game was, it would never be feasible for one person, so I decided I would add modding support, and release the source.

So how did I even do it

As I said, the source is going to be open so ill just put in a few snippets of code, and other changes I made to do this.

Adding a Mod Manager

at first, I was going to use Mod Tool to create a modding system, but I ended up ruling this out do to the fact I couldn’t figure out how to create a mod for my own game.

A ton of research later I found Iron Python, this was exactly what I needed, a simpler language that was, so I thought, easier to implement.

Iron Python

So once I found Iron python I went straight to work, finding This Repo and adding it to my unity assets. Then did some research and got to the point where I could load a python file like this.

// create a scope and enging
engine = Python.CreateEngine();
scope = engine.CreateScope();
// load the engine, and import some libraries automatically
engine.CreateScriptSourceFromString("import clr\nclr.AddReference(\'IP.Lib\')\nclr.AddReference('IP.Game')").Execute();
// get the source of the python file
source = engine.CreateScriptSourceFromFile(mainFile);

// execute the script
// NOTE: this does nothing, except for define functions in the python scope
source.Execute(scope);

But where did I go from here, well I made a json class to define mod properties, and and files. this was to make it easier to figure out what python files I needed to source. And implemented a way of reading this and initializing prefabs in a vertical layout group.

public class JSONModData
{
    public string name;
    public string description;
    public string main_file;
    public string ui_file;
    public List<string> requires;
    public int chance;
}

This is all good, but how do i even call functions defined in the python file. after some googling, and getting annoyed because i couldn’t import assemblies I filially realized you need to import classes defined in the c# assembly in the python file. After that annoyance I wrote a quick function to run a function in the python file.

public dynamic Tick(dynamic data)
{
    data = scope.GetVariable<Func<object, object>>("Tick")(data);
    Debug.Log(engine.Operations.GetMember(data, "result"));
    return data;
}

public dynamic BulkTick(dynamic data, BigNumber ticks)
{
    data = scope.GetVariable<Func<object, object, object>>("bulkTick")(data, ticks);
    return data;
}

note that i create data object when a module in my game is created, which can occur multiple times. Now thats enough of the csharp code, how do i create a ui using this method. Answer: JSON, i created a few classes to define some basic ui elements: button; sliders; and text. Heres an example of a ui json file this one is the discount module.

{
  "buttons": [
    {
      "x": 214,
      "y": -3,
      "w": 50,
      "h": 25,
      "onClick": "upgradeClick",
      "enable": "upgradeAvail"
    }
  ],
  "sliders": [],
  "text": [
    {
      "x": 164,
      "y": -3,
      "w": 50,
      "h": 25,
      "dynamic_text": "discountText"
    },
    {
      "x": 5,
      "y": -3,
      "w": 159,
      "h": 25,
      "dynamic_text": "nameText"
    }
  ]
}

And respectively heres the code that loads the ui and returns the root game object:

    public GameObject ConstructUI(ModUI ui)
    {
        // the sliders in the ui
        sliders = new Dictionary<Slider, string>();
        // the text in the ui that can change
        dyntext = new Dictionary<Text, string>();
        // the buttons in the ui
        btns = new Dictionary<Button, string>();
        GameObject result = Instantiate(panelPrefab, transform);

        foreach (ModUIButton btn in ui.buttons)
        {
            GameObject button = Instantiate(ButtonPrefab, result.transform);
            button.GetComponent<RectTransform>().anchoredPosition = new Vector2(btn.x, btn.y);
            button.GetComponent<RectTransform>().sizeDelta = new Vector2(btn.w, btn.h);
            button.GetComponent<Button>().onClick.AddListener(() => mod.onClick(data, btn.onClick));
            btns.Add(button.GetComponent<Button>(), btn.enable);
        }

        foreach (ModUISlider sl in ui.sliders)
        {
            GameObject slider = Instantiate(sliderPrefab, result.transform);
            slider.GetComponent<RectTransform>().anchoredPosition = new Vector2(sl.x, sl.y);
            slider.GetComponent<RectTransform>().sizeDelta = new Vector2(sl.w, sl.h);
            sliders.Add(slider.GetComponent<Slider>(), sl.variable);
        }

        foreach (ModUIText txt in ui.text)
        {
            GameObject slider = Instantiate(textPrefab, result.transform);
            slider.GetComponent<RectTransform>().anchoredPosition = new Vector2(txt.x, txt.y);
            slider.GetComponent<RectTransform>().sizeDelta = new Vector2(txt.w, txt.h);
            if (txt.dynamic_text != null)
                dyntext.Add(slider.GetComponent<Text>(), txt.dynamic_text);
            else
                slider.GetComponent<Text>().text = txt.static_text;
        }

        return result;
    }

And finally the code that updates the ui:

    public override void UpdateDisplay()
    {
        foreach (Slider slider in sliders.Keys)
        {
            slider.value = mod.GetVar(data, sliders[slider]).mantissa;
        }

        foreach (Text textf in dyntext.Keys)
        {
            textf.text = mod.GetVar(data, dyntext[textf]);
        }

        foreach (Button btn in btns.Keys)
        {
            btn.interactable = mod.GetFunc(data, btns[btn]);
        }
    }

What Next

I plan on adding UI Popups, and a few other things. But the main thing i plan on doing is testing to see if this system is even as intuitive as i thought, if you would like to help please do. There is a source repo for an example mod Here, if you have any suggestions with it please comment them. The game will be available soon.

Download Infinite Progression
Leave a comment