Timberborn

Timberborn

Automation
 This topic has been pinned, so it's probably important
ihsoft  [developer] 13 May @ 12:38pm
HELP! Automation scripting questions and answers
If you have troubles setting up automation rules, you can ask questions here.
< >
Showing 1-15 of 24 comments
ihsoft  [developer] 13 May @ 1:08pm 
And the first question from a player:
Originally posted by Psigh:
the discord link doesn't seem to be working for me, so I'll ask here: is it actually possible to stop a pump when a water tank has more than x water and resume when it has less than y? if so, what's the quickest and dirtiest way to do it? from what I can see the only thing a tank can do is output a value to the log, but even then I can't figure out how to make the pump read from the log, and even then if I have anything else writing in the log every other automation that reads from it should get messed up, yet i've seen someone tell a flood gate what to do based on information from a water gauge, so it should be possible
please help lol I'm not a programmer (if you can direct me to the actual discord server that's actually even better)

The Discord link

This link[discord.com] works just fine for me. You can also use this invite link[discord.gg] to join the Timberborn Discord server. There, you can find "mod-creators" channel. You can find me by name "@Igor". There is a dedicated sub-thread for Automation mod where all questions are welcome and being answered quick.

Setting up the pump rule based on the tank water level

I assume, you have already read about the scripting principles[github.com].

To be able to execute action on a building, based on values from another building, you need to first "export" those values. If all buildings were exporting all their values, it would be a mess, so you need to tell explicitly what you need. There is a tool in the "signals" tool group that exports the currently selected good from a building (Tank, in our case). Once you applied it, the water reserve in the tank will be exported as signal "Stockpile.yellow1". You can change the name if you want via the rules editor dialog. Now, you need to add rules on the pump that would react on this signal and do the logic. E.g. rule "IF (gt (sig Signals.Stockpile.yellow1) 10000), THEN (act Pausable.Pause)" will pause the pump when the water reserve in the tank goes above 100. You would need a counterpart rule that will resume the pump when the reserve drops below the lower threshold.

That being said, the values are exported as "signals". They are not written into the log, but the logs may have tracking info for the debugging purpose (if you enable the verbose logging). Keep in mind, that the signals name is globally unique. So, if you want two tanks to export their values, you would need different names, or else there will be a conflict that would introduce undetermined behavior in the conditions.

To summarize, you would need the following setup:

ON THE TANK WITH THE WATER GOOD SELECTED

If (eq (sig Inventory.OutputGood.Water) (sig Inventory.OutputGood.Water)) Then (act Signals.Set 'Stockpile.yellow1' (sig Inventory.OutputGood.Water))

ON THE PUMP (a medium tank - 300 water units reserve)
If (ge (sig Signals.Stockpile.yellow1) 25000) Then (act Pausable.Pause) If (lt (sig Signals.Stockpile.yellow1) 10000) Then (act Pausable.Unpause)

This will pause the pump when the reserve reaches 250, and resumes the pump when it drops below 100.

For the better readability, you can rename the signal to something more clear. Like "MainTank.water", or whatever.
Last edited by ihsoft; 13 May @ 1:16pm
Psigh 13 May @ 7:26pm 
perfect thank you, I think I managed to give my own spin to it (tanks output a value of 1 if they're full and 0 if they're almost empty, it just feels tidier to me, and then the pump will run if either of them are 0 and stop if all of them are 1), we'll see if it does what I want
a couple more questions: you mention a "rules editor dialog", do you simply mean the interface you get when you're editing in script mode rather than constructor? just want to make sure I'm not missing any tools the mod provides
also, yes I did read the scripting principles page, but for instance I didn't find the line "act Signals.Set 'Stockpile.yellow1'" to allow the script to output a global signal anywhere on that page, did I simply miss it? or have you made a list of possible commands to be used in the scripts?
ihsoft  [developer] 14 May @ 1:10am 
Originally posted by Psigh:
perfect thank you, I think I managed to give my own spin to it (tanks output a value of 1 if they're full and 0 if they're almost empty, it just feels tidier to me, and then the pump will run if either of them are 0 and stop if all of them are 1), we'll see if it does what I want
a couple more questions: you mention a "rules editor dialog", do you simply mean the interface you get when you're editing in script mode rather than constructor? just want to make sure I'm not missing any tools the mod provides
also, yes I did read the scripting principles page, but for instance I didn't find the line "act Signals.Set 'Stockpile.yellow1'" to allow the script to output a global signal anywhere on that page, did I simply miss it? or have you made a list of possible commands to be used in the scripts?
The rules dialog is what opens when you click "add rules" or "edit rules". Not all things can be done via the constructor mode, but the script mode can do anything.

The Wiki is always behind the trunk. So far I updated it with the very basic stuff only. Eventually, it will cover all supported actions and signals. For now, use Wiki to understand the main idea, and use the rules editor and template tools to learn what signals/actions exist.
Last edited by ihsoft; 14 May @ 1:10am
Is there a way to delay actions once the conditions are satisfied? I am trying to use signals to automate wheatflour production using a small warehouse, but as soon as the warehouse runs empty due to beavers are removing the wheat, the signal pauses the gristmill which starts a loop.
If there was a delay function, I could use conditional script to check both the warehouse as well as the gristmill input properly.
ihsoft  [developer] 14 May @ 8:02pm 
Originally posted by Deadpool8912:
Is there a way to delay actions once the conditions are satisfied? I am trying to use signals to automate wheatflour production using a small warehouse, but as soon as the warehouse runs empty due to beavers are removing the wheat, the signal pauses the gristmill which starts a loop.
If there was a delay function, I could use conditional script to check both the warehouse as well as the gristmill input properly.
You can use "and" operator to achieve it: in the same condition check for both the gristmill input and warehouse output. Or you can check for the sum.
Option #1: (and (gt (sig Inventory.InputGood.Wheat) 0) (gt (sig Signals.Warehouse1) 0)) Option #2: (gt (add (sig Inventory.InputGood.Wheat) (sig Signals.Warehouse1)) 0)

Or, you can (and almost always should) add hysteresis to prevent the oscillation. E.g. stop gristmill at 0, but start at, say, 20. The value at which you start should exceed the input of the workshop.

In general, your case matches a pattern when the building must not pause, but temporarily suspend. Pausing causes the ingredients removal, and it's almost never is a good thing. I have a plan to introduce an action that would remove workers without stopping the building.
Last edited by ihsoft; 14 May @ 8:04pm
BoNes 14 May @ 10:17pm 
Is there a way to set sluices current mode (Auto, Open, Closed) using scripts? Then you can read your current water levels and set a sluice to auto or closed based on it (auto to keep bad water away).
Last edited by BoNes; 14 May @ 10:19pm
ihsoft  [developer] 15 May @ 1:08pm 
Originally posted by BoNes:
Is there a way to set sluices current mode (Auto, Open, Closed) using scripts? Then you can read your current water levels and set a sluice to auto or closed based on it (auto to keep bad water away).
Not in v2.1.0, but this feature is in pre-release.

v2.1.1 (pre-release)
  • [Feature] Add settings to control how to show the rules on the building's panel.
  • [Feature] Add new scripting component `FlowControl` to allow scripting the water flow on sluices and badwater domes.
  • [Feature] The dynamite drilldown templates are now scripted. Such rules can be created and edited via the rules' editor.
  • [Change] The "Open water regulator" template can now be applied to the sluices as well.
So I'm gonna start with the fact that my brain is SMOL xD so I just about barely understand how this all works, and managed to implement on some buildings, in a way that makes me happy :) Question though, is there a way to make a script which either pauses or removes workers from either gatherer flag or lumberjack flag when no resources can be currently harvested in range? this is so that my beavers aren't literally sat there watching trees grow etc. I guess this type of function would also be useful for the Forester, where it could be paused when no plants in range currently need planting / replanting.
ihsoft  [developer] 22 May @ 2:30pm 
Originally posted by LittleTofoo:
So I'm gonna start with the fact that my brain is SMOL xD so I just about barely understand how this all works, and managed to implement on some buildings, in a way that makes me happy :) Question though, is there a way to make a script which either pauses or removes workers from either gatherer flag or lumberjack flag when no resources can be currently harvested in range? this is so that my beavers aren't literally sat there watching trees grow etc. I guess this type of function would also be useful for the Forester, where it could be paused when no plants in range currently need planting / replanting.
Alas, tracking for the "resources available for gathering" is not that straightforward. The game runs a pretty complex logic per worker to realize if something can be gathered or not. So far, I didn't find a way to efficiently detect "nothing can be gathered" case. However, it's a good idea to make a condition for the "no work" case - this is signalled by the game at the building, so I can react on it. I created a feature request for this: https://github.com/ihsoft/TimberbornMods/issues/82. Btw, feel free to add you ideas too.
BoNes 23 May @ 1:05am 
Instead of trying to detect if "resources available for gathering"... this method would work (although it still requires at least 1 worker assigned to the building):
Loop though all beavers currently assigned to the building, if they're all idle then there's no work to be done. This check could be done every so often (not every frame) to help performance, once per second would still be very responsive, and also only run this check if the building is actually using the condition.

To be more user friendly, instead of "Resources available for gathering", I'd call it "All workers idle". You could even go a step further and add "At least X workers idle" too.

Admittedly, I do use the Configure Workplace with a Max Worker Multiplier of 4, so I can have 4 workers in single worker buildings, like the Gatherer, Forester and Lumberjack. So the requirement of still having a single worker in the building wouldn't hurt so much.
It would still be useful though (even with the default worker limits), because then you could go "If all workers are idle, then pause the workplace" "If Logs below a certain amount resume"... every time you use a log, it'd try to resume the workplace, if there's still no trees to be harvested it'd pause it again.
Last edited by BoNes; 23 May @ 1:16am
welp, now I just have to figure out how to do that xD
eliptus 24 May @ 6:29am 
I'm trying to setup a voting system for resources:

If (ge (sig Inventory.OutputGood.<Item>) (div (getnum Inventory.Capacity) 100)) Then (act Signals.Set 'Need<Item>' 0) If (and (eq (sig Signals.Need<Item>) 0) (lt (sig Inventory.OutputGood.<Item>) (div (getnum Inventory.Capacity) 100))) Then (act Signals.Set 'Need<Item>' 100)

Based on the understanding that "(sig Inventory.OutputGood.<Item>)" should only be evaluated when inventory count changes, the signal"Need<Item>" should at most transition from 1 -> 0 -> 1 each time a consumer fills up.

However, this seems to trip your circular execution detector:

[SmallTank.Folktails@(135, 56, 5)] Circular execution of signal 'Signals.NeedWater'. Execution log: [SmallTank.Folktails@(135, 56, 5)]:Signals.NeedWater [SmallTank.Folktails@(135, 56, 5)]:Signals.NeedWater [SmallTank.Folktails@(135, 56, 5)] Automation error reported by: IgorZ.Automation.Actions.ScriptedAction(Expr="(act Signals.Set 'NeedWater' 100)";Condition=IgorZ.Automation.Conditions.ScriptedCondition(Pre="";Expr="(and (eq (sig Signals.NeedWater) 0) (lt (sig Inventory.OutputGood.Water) (div (getnum Inventory.Capacity) 100)))")) [SmallTank.Folktails@(135, 56, 5)] Automation error reported by: IgorZ.Automation.Conditions.ScriptedCondition(Pre="";Expr="(and (eq (sig Signals.NeedWater) 0) (lt (sig Inventory.OutputGood.Water) (div (getnum Inventory.Capacity) 100)))") [SmallTank.Folktails@(136, 56, 5)] Automation error reported by: IgorZ.Automation.Actions.ScriptedAction(Expr="(act Signals.Set 'NeedWater' 0)";Condition=IgorZ.Automation.Conditions.ScriptedCondition(Pre="";Expr="(ge (sig Inventory.OutputGood.Water) (div (getnum Inventory.Capacity) 100))")) [SmallTank.Folktails@(136, 56, 5)] Automation error reported by: IgorZ.Automation.Conditions.ScriptedCondition(Pre="";Expr="(ge (sig Inventory.OutputGood.Water) (div (getnum Inventory.Capacity) 100))") [SmallTank.Folktails@(136, 56, 5)] SyncState failed: Circular execution of signal 'Signals.NeedWater'
ihsoft  [developer] 24 May @ 3:40pm 
Originally posted by eliptus:
I'm trying to setup a voting system for resources:

If (ge (sig Inventory.OutputGood.<Item>) (div (getnum Inventory.Capacity) 100)) Then (act Signals.Set 'Need<Item>' 0) If (and (eq (sig Signals.Need<Item>) 0) (lt (sig Inventory.OutputGood.<Item>) (div (getnum Inventory.Capacity) 100))) Then (act Signals.Set 'Need<Item>' 100)

Based on the understanding that "(sig Inventory.OutputGood.<Item>)" should only be evaluated when inventory count changes, the signal"Need<Item>" should at most transition from 1 -> 0 -> 1 each time a consumer fills up.

However, this seems to trip your circular execution detector:

[SmallTank.Folktails@(135, 56, 5)] Circular execution of signal 'Signals.NeedWater'. Execution log: [SmallTank.Folktails@(135, 56, 5)]:Signals.NeedWater [SmallTank.Folktails@(135, 56, 5)]:Signals.NeedWater [SmallTank.Folktails@(135, 56, 5)] Automation error reported by: IgorZ.Automation.Actions.ScriptedAction(Expr="(act Signals.Set 'NeedWater' 100)";Condition=IgorZ.Automation.Conditions.ScriptedCondition(Pre="";Expr="(and (eq (sig Signals.NeedWater) 0) (lt (sig Inventory.OutputGood.Water) (div (getnum Inventory.Capacity) 100)))")) [SmallTank.Folktails@(135, 56, 5)] Automation error reported by: IgorZ.Automation.Conditions.ScriptedCondition(Pre="";Expr="(and (eq (sig Signals.NeedWater) 0) (lt (sig Inventory.OutputGood.Water) (div (getnum Inventory.Capacity) 100)))") [SmallTank.Folktails@(136, 56, 5)] Automation error reported by: IgorZ.Automation.Actions.ScriptedAction(Expr="(act Signals.Set 'NeedWater' 0)";Condition=IgorZ.Automation.Conditions.ScriptedCondition(Pre="";Expr="(ge (sig Inventory.OutputGood.Water) (div (getnum Inventory.Capacity) 100))")) [SmallTank.Folktails@(136, 56, 5)] Automation error reported by: IgorZ.Automation.Conditions.ScriptedCondition(Pre="";Expr="(ge (sig Inventory.OutputGood.Water) (div (getnum Inventory.Capacity) 100))") [SmallTank.Folktails@(136, 56, 5)] SyncState failed: Circular execution of signal 'Signals.NeedWater'
Are you on the latest version? I cannot reproduce this error on a tank with 300 water items in it.

(ge (sig Inventory.OutputGood.Water) (div (getnum Inventory.Capacity) 100)) (act Signals.Set 'test' 0) (and (eq (sig Signals.test) 0) (lt (sig Inventory.OutputGood.Water) (div (getnum Inventory.Capacity) 100))) (act Signals.Set 'test' 100)

Which building you attach the rules to? What is its inventory?

Btw, number "100" in the script means value "1" (one). Division by one always gives the original value.
Last edited by ihsoft; 24 May @ 3:41pm
eliptus 24 May @ 4:37pm 
Are you on the latest version? I cannot reproduce this error on a tank with 300 water items in it.

On v2.2.1. The error is reported when you have two storage containers and one reaches maximum capacity while the other still has spare capacity.

Which building you attach the rules to? What is its inventory?

Two small water tanks. The goal is that the signal should be 1 if either has spare capacity and 0 if both are full. I'm trying to solve the multi-producer/multi-consumer problem without needing a signal for each producer/consumer.

Btw, number "100" in the script means value "1" (one). Division by one always gives the original value.

I started doing this because I saw a script description showing the value in 100x. I can't recall when this happened and can't reproduce it. I'll be sure to report it if I see it again. Thanks.
Last edited by eliptus; 24 May @ 4:38pm
Psayne 25 May @ 9:40pm 
Would it be possible to implement an action of "set recipe to {recipe}" for buildings that have more than one? I was thinking about setting up the grill to switch when output is full or input is empty, and pause if all three are full, resume if sufficiently low. the latter two scripts are possible, but recipe changes is outside the scope of this mod at the moment and would be an amazing addition
< >
Showing 1-15 of 24 comments
Per page: 1530 50