On the basics of controllers


I’m trying to get workers to craft things. @Wouter_Sikkema as kindly allowed my to peek inside his norlingmod. And while that gives me lots of confidence into what is needed to make my goal work, I am still in the process of trying to understand how stuff works under the hood.

I first put my attention to the worker.lua file, which I have to adapt to mix in the basic crafting functionality into it. It should be declared in the manifest under controllers, as wouter as done and as I gathered that the file actually describes a controller. I have a question that the modding guide pae on controllers doesn’t seem to answer: given that I am changing a controller already in the game, does my file need to contain only the changes (like a mixin) or everything (like an override).

1 Like

are you making a new job, or modifying an existing one? an if its an existing one, is it for all kingdoms? as im reading it, just making ALL workers able to craft stuff right?

if you want to change a job, for all kingdoms, it depends on how you do it, you have options!
as you may know the index in jobs tells the game what jobs exist, and points at their descriptions.
in those description files it tells the game where to look for their controller.

now you had already figured out that if you make a custom controller it needs to be declared in your manifest. two options now present themselves(and a third hidden one but i dont know that one)

one: overwrite the existing controller with an override in your manifest with a copied and modified one. its already declared in the original stonehearths manifest so it should be fine (and if not, sommeone will shout this in this thread im sure)
the slightly cleaner way would be to have a copied and modified one (with a different name etc, see my nordlingmod since i also have a different one there than for instance the normal worker) and point from the jobs description to your version instead of the default one. that way, if another mod messes with the controller (see option 3 in a sec) your mod wont fight with those changes but will blatantly ignore them. this may or may not be a good idea.

3rd option i know exists but dont know how to do:
SOMEHOW you are allowed to mix into a .lua, with something called monkey patching. ask paul/dani/bruno/pawel. i havent seen or heared how this eldritch magic works. you probably have to know more lua than holding up a wet finger to see where the wind blows and guessing. (a.k.a my level)

so TLDR: copy the controller from the default game and have a modified version in your mod, overwriting the default one is easiest, but maybe not cleanest option. cleanest is probably making a new one like i did and changing it in the jobs description. but a third mythical option exists but i dont know how.

1 Like

As you said, mixing into a .lua file in the simple way does not work. I just experimentally verified that the game does not like it. Little anticlimactic though, it just gives an error: “this isn’t really fun for me”, and then goes on with its business. No crashing or weird behaviour, and no UI button to force it. Ah well, it was worth a try.

doing some research into monkey patcching (if only because I am now curious) I found this on a python-forum.

so what i gather is that it is a way to replace signle functions in the class that describes the controller that is worker.lua. I’m not sure this works exactly since I either want to change the mixin function inside the code-file, which isn’t part of a function per se, or I want to redo what the mixin-function does (add in all the class functions from crafting_job.lua) which is adding not necessarily replacing functions. So far I’m not sure if it would even work, but hey, I’m still researching.

Yeah so the overwrite or pointing at a new lua might still be easiest

1 Like

More research:

upon closer thought, there is one way that would be ideal, if it works:

  • stonehearth has it’s own worker.lua controller. It uses the radiant.mixin function to mix in a library into the class that is the controller.
  • this library, alias stonehearth.jobs.crafting_job is actually a different worker class controller that lives inside stonehearth/jobs. So radiant has a built in mixin-function.

So the strategy would be to

  1. make a new empty class controller say, new_worker.lua.
  2. Instead of mixin in the crafting job, we mix in the old stonehearth controller worker.lua
  3. we make additions as normal
  4. we somehow monkey patch the old controller class to be disguised as the simple worker.lua class that the game knows and loves
  5. so that other mods can do successive alterations to the controller that stonehearth asks for.

there are a few nuances I can see currently:

  1. monkey patching, from what I’ve seen in python examples, is as easy as old_variable = new_variable where old_variable was an object from a library that you weren’t supposed to touch. However where do you need to put that line of code in such a way that the game will execute it before it ever starts dealing with the content of the altered controller.
  2. if two additions try to add the same function, but contain different behaviour, we again have that one wins and one loses. This, and alterations themselves would need to be monkey-patched in, or dealth with in manually written mixed code, and then, depending on circumstance, monkey-patched in.
  3. In every way, whether through overrides, controller recreations or monkey patching, modders need to know of the changes of other modders and be able to resolve differences. Maybe this monkey patching mixin technique can make that process easier to perform or easier to reverse-engineer by others or easier to load for the game, but the need to resolve differences by modders remains. Maybe community plugins would be a good way to deal with that, if it is sufficiently neccessary. Or maybe a technique to resolve alterations can be found within the radiant-API

TLDR: Monkey patching can be used to 1) successively add functions (multiple mods can do this) or 2) rewrite certain functions once (multiple mods con only do this as long as they don’t interfere with each other). As soon as two mods want to mess with the same function, coordination is needed, as it would be with overrides or recreations.

How much do you know about inheritance?
radiant.mixin() is basically that. One class inheriting another.

You can see that both worker.lua and crafting_job.lua inherits base_job.lua
That mean that whatever base_job has, these child classes will also have.

All you need to do is make the worker.lua a child of crafting_job.lua instead and call it a day.

When a child has the same function of the parent, it overrides it. But you can still run the parent code if needed. For example, both parents and childs have the initialize() method. Just changing the contents inside would indeed overwrite it, but you can see that both childs have a BaseJob.initialize(self) inside it, which effectively runs the code from the parent, then whatever other code you want too (those classes have no other lines in that function, but they could if needed)

To effectively replace a function in a class, you need to get that class and simple add new content to that variable.
For example: Class.function = new_function

Yes, worded differently that is what is going on. I don’t have much experience with classes and inheritance in general, but I know how it works on a high level. I did however expect that lua had it’s own standardized way to deal with inheritance, instead of radiant having to write a custom function that does it.