#Advanced Automation
1 messages · Page 2 of 1
I guess, it's due to there was no way to put/remove workers based on the water level at the dump? But there is such an option now 🙂 The worker comes only to fill up the reservoir.
This would be a bit more complex setup, thought (gauge + custom signals).
I know floodgate triggers had something like it. I don't remember the details.
well gauges is often late game for me and fluid dump can be in mid to early game 😛
Maybe add a signal to the fluid dump then...
Hmm. I didn't know it. So, you want to only keep the wonder as "a happiness regulator"? 🙂
that's the idea ... but there is probably other thing that we can drive with only a timer
i just left a message on workshop page saying that my gatherer flags are suddenly giving me parse errors and at the same time the output constructer bricks are not showing
Have you checked the logs? If you didn't, please share them here. I'm pretty sure it's the range checking error. If my memory doesn't confuse me, the flag storage max capacity is 10.
when i click test it says signal not supported inventory.outputgood.berries
i have not written any scripts myself as i do not understand how. i have only been using the constructor
"at the same time the output constructer bricks are also not showing"
as you can see its not showing in dropdown
I need logs to figure it out.
where would i find said logs
Here thge logs is:
%appdata%\..\LocalLow\Mechanistry\Timberborn\
Log: Player.log
C:\Documents and Settings<YOURNAME>\AppData\LocalLow\Mechanistry\Timberborn
ps from pinned message in Mod users
This seems to be "just a log". We need it at the moment you had the problem.
It's how the log works: it records what happens.
it did have:
[GathererFlag.Folktails@(90, 103, 5)] Failed to parse condition: (ge (sig Inventory.OutputGood.Berries) 2000)
Error: Signal not supported: Inventory.OutputGood.Berries
[GathererFlag.Folktails@(90, 103, 5)] Automation error reported by: IgorZ.Automation.Conditions.ScriptedCondition(Pre="";Expr="(ge (sig Inventory.OutputGood.Berries) 2000)")
[GathererFlag.Folktails@(90, 103, 5)] Signal change triggered, but the condition was broken: (ge (sig Inventory.OutputGood.Berries) 2000)
[GathererFlag.Folktails@(90, 103, 5)] Failed to parse condition: (le (sig Inventory.OutputGood.Berries) 1900)
Error: Signal not supported: Inventory.OutputGood.Berries
[GathererFlag.Folktails@(90, 103, 5)] Automation error reported by: IgorZ.Automation.Conditions.ScriptedCondition(Pre="";Expr="(le (sig Inventory.OutputGood.Berries) 1900)")
[GathererFlag.Folktails@(90, 103, 5)] Signal change triggered, but the condition was broken: (le (sig Inventory.OutputGood.Berries) 1900)
Load time: 52941ms (scene index: 2)
[GathererFlag.Folktails@(90, 103, 5)] Failed to parse condition: (ge (sig Inventory.OutputGood.Berries) 2000)
Error: Signal not supported: Inventory.OutputGood.Berries
[GathererFlag.Folktails@(90, 103, 5)] Failed to parse condition: (le (sig Inventory.OutputGood.Berries) 1900)
Error: Signal not supported: Inventory.OutputGood.Berries
from what i can understand, which isnt much at all, but im thinking it thinks that Inventory.OutputGood.Berries or any Inventory.OutputGood.resourcefor that matter doesn't exist
where do you have to mod from? tried verify gamefiles to force mods to update?
Ive verified files since and it hasn’t fixed, i could try verifying again, ill even unsubscribe from the mod and resubscribe if I have to
unsub resub and verify has not fixed the issue
well then we need a log where you have loaded a save and try set a new flag using constructor and an image of it
(so when photo is taken drag the log here)
made a new save and i dont even see the option in the constructor to add output items
ok then drag a log here
only thing i have done since this screenshot is closed to desktop
one thing noted you have a mod called:
NameThatBeaver
in
C:\Users\marcu\Documents\Timberborn\Mods\NameThatBeaver
that is not a valid mod and should be removed
checking more if i find anything wrong from my side
unused config file path for a disabled mod, ill delete it and see if it does anything anyway
hmm i would sugest to try with only and see if it still is the same
- Harmony
- Mod settings
- Timberapi
- automation
could be a incompatible mod with automation mod
again no option to add output items
weird reinstall it?
mod.io remove it and download again
Steam unsubscribe and subscribe again
done multiple times already, and i just did it again after you said that, still the exact same
though adding a path instantly makes output:berries show up on the constructor, i havent checked if its(the script) showing as valid tho, im going to visit my save where i first encountered the error now and replace the path and see if it does anything
edit, save where i encountered error is still not fixed, even after replacing path
edit2, i can't be bothered trying to figure out why its showing no output:berries on my gatherer flag, as long as the issue doesnt happen to any other buildings... i just hope next content update to the mod somehow fixes the issue, or it just fixes itself somehow...
thanks for trying.
Poor man's "sluice":
Stream Gauge "RiverPool"
broadcast depth
IF: (ge (sig StreamGauge.Depth) 0)
THEN: (act Signals.Set 'Gauge.RiverPool' (sig StreamGauge.Depth))
Stream Gauge "RiverNearPool"
broadcast depth
IF: (ge (sig StreamGauge.Depth) 0)
THEN: (act Signals.Set 'Gauge.RiverNearPool' (sig StreamGauge.Depth))
broadcast contamination
IF: (ge (sig StreamGauge.Contamination) 0)
THEN: (act Signals.Set 'Gauge.RiverNearPool.Contamination' (sig StreamGauge.Contamination))
Floodgate:
close on bad weather
IF: (ne (sig Weather.Season) 'temperate')
THEN: (act Floodgate.SetHeight 100)
open on good weather when the water level in the pool is lower than in the river and contamination in the river less than 2%
IF: (and (eq (sig Weather.Season) 'temperate') (le (sig Signals.Gauge.RiverPool) (sig Signals.Gauge.RiverNearPool)) (lt (sig Signals.Gauge.RiverNearPool.Contamination) 2))
THEN: (act Floodgate.SetHeight 0)
any way for using Access operators to query a building to know what property names are available to use?
create a constructor rule and edit it as code?
You can see the default ones that way.. but not all of them I think
Ie the ones in the pulldown
This is a bug. Thanks for reporting. Will fix it today.
A good idea for the debug component. I think, I can add it.
Cool 🙂
Okay, you are already on it...
I just had the same issue come up.
Two scrap flags right next to each other; one has the bug, the other is fine.
A workaround for the gatherer flags. Wait till at least one item of the good appears in the stock. Then, create the rule. The flags have a tricky logic on how they set inventory. Still need to understand it.
Hey @Igor, I commented on your pinned help comment on Steam about the circular execution error. Just thought I'd let you know I'm on the Discord server now in case you preferred to follow-up here. I already replied to your recent follow-up there.
Here you get the answers faster 🙂
So, you apply that rule on two tanks? Hmm, why the eror comes then.
One tank sets the signal to 0 signaling it doesn't need water, then the second sees it set to zero and sets it back to 1 signaling it does need water. I'm not sure if it's the rapid change from the two tanks, or if it's the same tank seeing it's own signal even though it doesn't trigger again.
By the way, is there any forum of shared user scripts? I'm curious what others are doing.
The circular detection system should only trigger if the same rule gets executed twice in one call. But for now I donl't see how it happens.
If you have trouble reproducing from my description, I can try sharing a save file where it triggers on game load.
Not just yet. You can be the first to start it 🙂 The scripting feature is rather new.
This will help.
Cool. I'll need workings scripts first. Right now I just have failed experiments. 🙂
Do you need me to remove all mods requirements? Or can we give a modded save a try first?
As long as I can load without installing all the other mods, I'm fine. I don't think we have a mods conflict case here.
Alright. I'll try to get this to you soon... FYI: I'm in Japan so my day is just starting.
My day is in its middle 🙂 I'm working on automation right now anyway.
Just verified that my save loads with only Automation and it's advertised dependencies.
Just a random thought: If you could support list signals where consumers could add/remove themselves from the list signal (i.e. add/remove a string name) and producers could check how many entries are in the list, this would open up a lot of possibilities.
What is the use case?
Same use case: multi-producer/multi-consumer. However, with a list signal where consumers add/remove themselves you can quantify demand by looking at the size of list. You can have some producers unpause if there is any demand and others unpause only when there is high demand.
I have a plan to add mutli-signal feature. I.e. you set the same singal from multiple actions to different values. Then, you can get the value: last, min, max, sum, count. Will it solve you case?
Maybe. For example, if two containers set it, do you get a value of 2? If one container sets it and one clears it, do you get a value of 1?
For the count function - yes. sum/min/max will aggregate the values. And last is what we have today.
Ah, I see. Yes, sounds awesome!
It actually sounds more useful than my suggestion. If I understand it right, each container can set the signal to how much spare capacity it has, and then you can sum it to calculate the total spare capacity. I'm looking forward to this.
Yes, this was the idea. I was considering it from the beginning, but the initial system implementation took too much time, so I released a trimmed version.
@tribal canopy I'd appreciate any thoughts here: https://github.com/ihsoft/TimberbornMods/issues/86
I just gave a thumbs up since it sounds perfect just as you described it. If any feedback comes to mind as I play I'll be sure to share it.
I'm open for any suggestions. Not anything can be done, but all ideas deserve to be heard.
v2.2.2 (25 May 2025):
- [Fix #84] Output good signals are not shown on the gathering flags.
Bug: when editing long script rules that hang past the end of the box, the display of the line jumps to the start on anything other than the arrow keys, resulting in blind entry.
Also, my new monstrosity:
Scrap Pile (underground)
IF: (eq (sig Inventory.OutputGood.ScrapMetal) (sig Inventory.OutputGood.ScrapMetal))
THEN: (act Signals.Set 'Stockpile.Scrap' (sig Inventory.OutputGood.ScrapMetal))
Metal Pile (underground)
IF: (eq (sig Inventory.OutputGood.MetalBlock) (sig Inventory.OutputGood.MetalBlock))
THEN: (act Signals.Set 'Stockpile.MetalSupply' (sig Inventory.OutputGood.MetalBlock))
Log Pile (small)
IF: (le (sig Inventory.OutputGood.Log) 400)
THEN: (act Prioritizable.SetHaulers)
IF: (ge (sig Inventory.OutputGood.Log) 1600)
THEN: (act Prioritizable.ResetHaulers)
Scavenger Flag
IF: (and (gt (sig Signals.Stockpile.Scrap) 99000) (gt (sig Inventory.OutputGood.ScrapMetal) 1500))
THEN: (act Workplace.RemoveWorkers)
IF: (lt (sig Signals.Stockpile.Scrap) 10000)
THEN: (act Workplace.SetWorkers 100)
Smelter
IF: (or (and (ge (sig Signals.Stockpile.MetalSupply) 99000) (gt (sig Inventory.OutputGood.MetalBlock) 1100)) (and (eq (sig Signals.Stockpile.Scrap) 0) (lt (sig Inventory.InputGood.ScrapMetal) 200)))
THEN: (act Workplace.RemoveWorkers)
IF: (and (lt (sig Signals.Stockpile.MetalSupply) 75000) (ge (sig Inventory.InputGood.ScrapMetal) 200))
THEN: (act Workplace.SetWorkers 100)
Opening the panel for the smelter instantly drops the game from 60 FPS to 15 FPS
I should try using Workplace.RemoveWorkers. I tried using Pausable.Pause when input runs out, but it results in disappearing input when a hauler picks up the last of the input from the stockpile.
Yeah, pausing empties the building, removing the workers does not. Only the latter will work with input triggers.
Thanks for confirming!
For the flags, stopping is fine. They only give output, and with pause icon, you will see that the flag is not working.
@south wedge I created a feature request for manual signals. Piisfox's scripts present another potential use case: The hardcoded thresholds could be replaced with manual signal for easier management.
@reef widget Just wanted to share that instead of (eq (sig Inventory.OutputGood.MetalBlock) (sig Inventory.OutputGood.MetalBlock)) I use (ge (sig Inventory.OutputGood.MetalBlock) 0) for brevity.
Also, (act Signals.Set 'Stockpile.MetalSupply' (add (sig Inventory.OutputGood.MetalBlock) 0)) let's you see the value set which I find more useful.
Checking signal for itself allows introducing a better UI in the future. E.g. instead of showing the formula, simply say "when signal changes".
Or maybe just create another boolean operator (sigchange ...)?
A teaser. The next version will have import/export functionality.
And while working on this, I figured out we may want to have a "custom template" feature. That is, saving the rules and then applying them. Need to find a proper UI approach, though.
@reef widget @tribal canopy Folks, do you have GitHub accounts? I can add you as collaborators so that you could add things to Wiki.
A very first step to share he scripts: https://github.com/ihsoft/TimberbornMods/wiki/Automation:-Useful-scripts
Let me know if you have better ideas.
A localized version is ready now.
I do, same username. Happy to collaborate.
You are in.
Give me 30 mins, I'll make a preview build for import/export feature
Need to test two locales, lol.
Alas, its the normal Unity behavior. Nothing I can do here.
Maybe, I can detect multiline? 
v2.3.0 (pre-release):
- [Feature] Add import/export feature for the rules.
An undocumented function: you can save rules with errors if click "Save" with Ctrl hold. Don't ask me why you would need it. If you don't need it, you don't use it 🙂
More on the undocumented functions. Hold Ctrl while hovering over the buildings during the templates application. The logs will have a reason why the template was rejected.
And remember the first rule of Fight Club.
@south wedge Bad timing: today's experimental update broke something. I'll switch to stable for now.
As for Github: Piisfun
This is a good example for logistics:
condition:(le (sig Inventory.OutputGood.Berries) 600)
action:(act Prioritizable.SetHaulers)
condition:(ge (sig Inventory.OutputGood.Berries) 2400)
action:(act Prioritizable.ResetHaulers)
Small warehouse for berries, set to obtain.
If (berries <= 6.00) (20% capacity) then prioritize having haulers refill it.
if (berries >= 24.00) (80% capacity) then cancel the priority flag.
Fill when empty, stop when full.
The only problem is that you can only directly copy the rule to a warehouse set to berries.
condition:(le (sig Inventory.OutputGood.Berries) 600)
action:(act Prioritizable.ResetHaulers)
condition:(ge (sig Inventory.OutputGood.Berries) 2400)
action:(act Prioritizable.SetHaulers)
This is the supply version: the only difference is that the actions are swapped.
Empty when full, stop when empty.
Invite sent.
Feel free to add it to the Wiki.
Just did.
One note for editing: in a <details> collapsable tag, if there is not a blank line after <summary>, the whole page breaks.
Yeah, I know 🙂 I use this section a lot. GitHub markup is rather glitchy.
Moving from pause/unpause to remove/set workers has been a huge QoL improvement for me. Thanks again for the tip.
I'm still in the early game, but one thing I'm struggling to automate is the farmhouse. However, I imagine that will eventually become an always-on building once the food supply and population reach an equalibrium?
I don't even bother to automate them; same for foresters.
There isn't a good way to determine when they need to work, the work itself is incredibly sporadic, and to top it all off, they are both core to basic survival.
For that, permamently working with some downtime is fine; the only time where there would be a significant benefit is at the beginning of the first cycle when you lack workers.
Yeah, I'm currently at a stage where food storage is full and population is still low. Being able to lower the worker count to 2 or 1 helps, though.
The forester seemed easy enough to pause during the early growing period, but has been fairly busy since as you say.
The other buildings that I have decided aren't worth trying to automate are:
- Inventor
- Observatory
- Numbercruncher
- Engine
For the first 3, there is no way to check science from a script, you usually need them to run in the background anyway, and simply setting them to low priority is enough for employment control.
The Engine is similar: there is no variables for power or battery capacity, which are the main things you would want to toggle on, other than possibly fuel availability. Besides, Igor also made Smart Power, which does all that and is naturally fully compatible, even if the two mods can't talk to one another.
Appreciate the advice. Will probably save me some head scratching.
I've installed Smart Power, but at this stage I'm only using it to pause buildings when flow stops.
v2.3.1 (26 May 2025):
- [Change] Support Timberborn
0.7.9.0. Incompatible with the previous versions of Update 7. - [Feature] Add import/export feature for the rules.
- [Fix #90] The placement tools prematurely place the building after an automation tool was used.
Note, that for the stable branch, the v2.2.2 was the last version. From now on, the updates will be made for 0.7.9.x only (experimental).
hmm... I guess I'll give experimental a try... is it fairly stable?
I don't recall when last time I had game related issues there. The only problem of this branch is that it frequently breaks mods.
Any use power and not updated yesterday?
My power edition did break yesterday hopefully releases an update today
Which mod? Smart Power is the only power-related mod I'm using.
No modded buildings that use power? Like deepsea pump in water extention or its pipe?
No. I'm in early game and only have base-game buildings right now.
It matter if you have mods enabled, not if you have placed bukdings
Thanks, will keep that in mind. For now I just returned to stable so I can play. Will debug experimental later.
I have only seen the opposite once, and that was afer they changed the serializer.
@south wedge Any chance you'd consider porting the premature placement fix to the stable branch since it's a bug fix?
Adding the ability to inport and export rules is awesome, thanks!
I'm not sure if you've thought about comments or have plans for those, but I made some suggestions as github issues:
https://github.com/ihsoft/TimberbornMods/issues/91
https://github.com/ihsoft/TimberbornMods/issues/92
For common lisp: Single line comments start with ; (outside of string blocks) Multi-line comments start with #| and end with |# Even if they're stripped and not displayed in game anywhere it wo...
Also, is there any way to detect what a storage is set to store? E.g return 'Water' or 'Grease' etc.
Would be kind of cool if t here was a Debug window in game, where you could send values from scripts to a window to monitor whatever you wanted. I suppose the window could pull from the log file as an option but you would have to initially place variables to the logfile with Debug.LogStr,Debug.LogNum .
If the change will be compatible with experimental, then yes. In general, maintaining more then one branch of code is too much of a burden. So it's either always live on stable and forget about experimental, or keep outdated version in prod and focus on experimental.
Import already supports comments. Just add "#" at the start of the line. I don't think more advanced commenting syntax is worth the effort.
Check the storage template in the signals menu. It does exactly this.
If you used ; istead then the syntax highlighter for lisp will correctly comment and uncomment
with hotkeys etc
If you use lisp editor, you will get troubles with the other import stements. "#" is widley recognized notion which is supported by many editors.
I'm using vs code with a lisp extension
import/export format is not lisp-compliant.
ok
Save you files with .sh extention 🙂 VS editor should start recognizing the right comment notion.
This (eq (sig Inventory.OutputGood.Water) (sig Inventory.OutputGood.Water)) isn't what I'm after - I'm looking for something that will return 'Water'
Anyway, I can add ";" also.
Yeah IDK man, I was just going by the syntax being lisp like from where you said that - it doesn't matter, the language highlighter can be set or configured however
{% (getstr SingleGoodAllower.AllowedGood) %}
Oh, perfect!
Thanks!
I was just testing and (act Debug.LogStr '{% (getstr SingleGoodAllower.AllowedGood) %}') works
but (act Debug.LogStr (getstr SingleGoodAllower.AllowedGood)) gives Argument #1 must be of type string, but found: Number
I was hoping to be able to detect if the storage type was changed. Maybe it still will
Interesting. The argument is supposed to be string.
Maybe it's a parser issue. Ill check.
As for the checking the type change, it will likely not work. If the type has changed, but you still have references to the other good id, that rule will throw a runtime error and stop working.
Why checking for it anyway? And you won't get notified about the change, since it's not a signal.
Yeah, ok, thanks.
I wonder what a good way to be able to track the amount and capacity for various goods would be.
That new Count and Sum on singals looks promising. Perhaps that can help.
I'd sort of hoped I could set something up so that any tanks set to Water would contribute to a current water and total, and be able to repurpose them and have it smart enough to handle it.
Yeah, I realised abot the no update due to not being a singal also - I was going to run stuff off a amount trigger from elsewhere.
In case anyone is interested or can figure out what's wrong, this was what I was fiddling with.
It'll largely be redundant when the aggragate signals with Max etc come out though.
The idea is to have a controller script that you put on a district center that keeps a tally of the storage amound, capacity and level (calculated 0-100) of a certain good - in this case water.
The tanks all run a script that will increase a Dirty signal when their value changes.
The controller (district center) script listens for this and manages the update.
- sets buffer signals to 0
- toggles
updatesignal which thepumpstanks listen onpumpstanks add their content and capacity to buffer signals (nothing listens on them)
I tested and this interrupted rule excution of theDirtyrules - seemed single threaded
Dirtytriggers on controler continue to- clear
Dirtysignal (triggers require >0 so should not recurse)
- clear
- update actual amount, capacity and level (calculated) signals from buffers for Water which will have triggers later.
It all looks ok if you add the tank scripts first, but things start to error when you start changing stored water amount. IDK why.
## On Water Storage Tanks
# Add current contents and capacity to buffered totals when update is triggered
condition: (eq (sig Signals.A1.Inventory.Water.Update) (sig Signals.A1.Inventory.Water.Update))
action: (act Signals.Set 'A1.Inventory.Water.Buffer' (add (sig Inventory.OutputGood.Water) (sig Signals.A1.Inventory.Water.Buffer)))
condition: (eq (sig Signals.A1.Inventory.Water.Update) (sig Signals.A1.Inventory.Water.Update))
action: (act Signals.Set 'A1.Inventory.Water.Capacity.Buffer' (add (getnum Inventory.Capacity) (sig Signals.A1.Inventory.Water.Capacity.Buffer)))
# Set Dirty flag when amount changes
condition: (eq (sig Inventory.OutputGood.Water) (sig Inventory.OutputGood.Water))
action: (act Signals.Set 'A1.Inventory.Water.Dirty' (add 1 (sig Signals.A1.Inventory.Water.Dirty)))
That's it for me though. That import function is so handy, thankyou!
test save
Was asking if this one in particular could be ported to stable sooner rather than later since since it was a bugfix and was fixed at the branch point of your mod.
I was thinking 'I bet DeepSeek could make a vs code extension to do highlighting and comment toggling with just config files' and it turned out it could!
I used .bar file extension (beaver automation rules) because tar was taken and I didn't have any better ideas so feel free to suggest alternatives.
v2.2.3 (27 May 2025), patch for 0.7.8.9.
- [Fix #90] The placement tools prematurely place the building after an automation tool was used.
But in general I don't do it. There is no simple and easy way to switch between the versions. Not to mention the merging hell at the end.
Common, your mods are no so big. Imagine Water Beavers using multiple versions 🤣
Appreciate the exception. So, the next update we can expect for the mod on stable is when 0.7.9.0 lands?
As someone noted in the Workshop comments, I've noticed that I have to Unsubscribe and re-Subscribe to get updates to this mod, while other mods (at least some) update automatically.
The autoupdate doesn't always trigger for the experimental. Nothing I can do here. All the mods are released the same way, via the game's export dialog.
This is a steam problem and happens to alot of mods
2 ways to get around
- There is a steam update mod https://steamcommunity.com/sharedfiles/filedetails/?id=3358667560
- Verify gamefiles to force all mods to update
My experience was in stable.
The fact of the matter is it's still Steam that is the issue.
Auto-updates on Steam are notoriously unreliable for anything on the workshop, unless the games itself forces the update.
I currently have 3 stockpiles for logs.
They all output their storage levels to a signal but they don't get combined right?
How would I combine the signals?
I think Steam only checks for updates once a day. #1283367971280126087 checks every time the game is started.
(technically it checks every time the menu is shown, but I think it's cached somewhere. I've never seen it update while the game is running)
Use (add arg1 arg2). For 3 items (add arg3 (add arg1 arg2)). Here is a link to scripting language https://github.com/ihsoft/TimberbornMods/wiki/Automation-(scripting)
Yes, tried that. It will not add signals together. It does not allow string.
Thats weird as signals can be strings, or a number.
What does your output script looklike the sets the custom signal?
I finaly got it to work...
(act Signals.Set 'INV.Main.LogsTotal' (add (sig Signals.INV.Main.Logs1) (add (sig Signals.INV.Main.Logs2) (add (sig Signals.INV.Main.Logs3) (add (sig Signals.INV.Main.Logs4) (sig Signals.INV.Main.Logs5))))))
The signals are not combined. If you have only 3 stockpiles and don't plan to have more, you can create 3 signals and sum them up via (add ...). Signals aggregation is a big feature I'm working on now. Not sure when it will get online. A lot ot hings to be changed in the whole signals system.
What I can release quick, is making "add" multi-argument operator. Today, it only accepts two.
Custom signals can only be numbers. How did you get the strings error?
Set changes the signal value, but when you use sig on a custom signal, it must return a number.
This worked fine to me:
(act Debug.LogNum (add (sig Signals.test1) (sig Signals.test2)))
It prints value -0.02. The value seems awkward, and this will be changed soon. In the current version, non-existing signals return -1. They should return 0.
@reef widget @sand thunder The signals aggregation is added. It's a preliminary version. Probably unstable. Try it out. The supported suffixes: .Min, .Max, .Sum, and .Count. Works for custom signals only.
Logging may be a bit spammy. It's a debug build.
Is this for Experimental branch only? I'm just trying it now.
And noticed for stable it used the old version. I'll switch anyway.
Looks promising! Count etc worked great.
I'm getting a crash when loading a game however. It loads ok the first time after you start the game but the 2nd time you try and load there's an error:
Any of these trigger it. Experimental branch. I also had the Scrollable Entity Panel mod active but it also happened without that.
There's also a 'RUNTIME ERROR' on the 1st rule on the district center in those saves when you load.
action:(act Signals.Set 'A1.Inventory.Water.Level' (div (sig Signals.A1.Inventory.Water.Sum) (sig Signals.A1.Inventory.Water.Capacity.Sum)))
It worked fine when I set it up.
It also tests fine (when I go to edit to rule script in game and hit Test I mean), but if you save the rules it will crash.
I was running into a similar problem with this before: #1190169064383991858 message
Other than that everything worked great though! Will be super handy.
With the sluice, you can turn flow on and off but currently no option to set it back to Auto.
Thanks! I'll check out why the save is failing.
It's intentionally. Why would you need "auto" if you make scripts to operate the sluice?
It's either one or another.
Good point, I was thinking the contamination setings work on auto only but thats not the case 🙂
one question: what is the difference between sum and count?
Sum means adding value of items, count is about items occurrence
Basically, count tells you how many buildings can set the signal in question. Not how many actions, but how many unique buildings.
E.g. if you have a building with 3 Signals.Set actions in different rules, it will be count 1. Not 3.
Btw, for this reason saving a new rule with set action will trigger the signal update. I rpobabl need to change it and only update rules that depend specifically on "count".
So if I have 3 storages of 1000 broadcasting, Count would return 3 and Sum 3000. okay.
The "rules added" file loads with errors, but doesn't crash. Tbh, the trace log of the crash is rather strange.
Wow! I got the errer after installing scrollable panel mod. Thta's very strange
Nm, it wasn't the mod that caused it. The crash error happens if you reload the game, i.e. load it after you already had a game loaded/started. A dumb bug with static variable initalization.
I assume you could make (arithmetic) Mean with Sum/Count but it might be nice to have it as a dedicated function.
I can't think of any reason to have geometric mean, or median, or mode
Heh
Median would have more meaning than Average in terms of checking what's in the storages "in average".
Yea, mean is average, median is middle, mode is most frequent
Ooh, because storages could have different capacities too
If I have storage of 1000 and 10, then having average of 500 won't give the right picture
Mean = 505, yea
If you setup a rule to keep it full for 70%, you will be constantly refilling that small one.
So really you want Sum / Capacity
As that's the "overall percentage full"
Which is probably what the bars at the top-left are calculated with
Fixed loading issues. Fixed the crash. Temporarily adding helping function concat. It takes 2+ arguments and joins them as strings. E.g.: (act Debug.LogStr (concat 'A1.Count=' (sig Signals.A1.Inventory.Water.Count))). Don't get used to it, it's only for preview. I will extend log methods to accept multiple arguments.
fyi @sand thunder @reef widget
And speaking of resources counting in general. There is a gray area with the goods being held. While hauler carries the good, it's not accounted in any storage. This data is available in the target storage (reserved capacity), but for now there is no way to get it from the script. I wonder if it should be accounted as an available good amount? It won't be instant of the store stat, though.
I think it is fine to not have it; it is generally a very small percentage, and when it isn't, you have worse issues (namely, being out of that resource).
The one exception is an edge case with pausing/unpausing a building based on the quantity of resources in a warehouse containing raw materials. If the quantity is above the limit, but a hauler picks it up to move it to the building and drops it below that limit, it is possible to create an infinite loop where the hauler picks it up, pausing the building, causing them to put it back in the warehouse, unpausing the building...
Good point. Hmm. Need to think about it. Maybe add another set of signals for the "eventual capacity".
Or, there can be difference: for output signals always take an instant value (what's is in the storage rigth now), but for the input signals consider what's coming. What do you think?
It's not critical, but it would help. I was hitting this scenario before moving from pause/resume to remove/set workers. Now with remove/set workers, while operating with low inventory, when the worker picks up input from storage they get unassigned from their workplace because input supply is depleted, but when they finish delivery they get reassigned because there is now input available. This works fine so long as the same worker gets reassigned, but there's still a race condition where someone else could be assigned from who knows where on the map.
Could/should this instead be fixed by programming different levels for pause and unpause? E.g Pause when wood < 100 Unpause when wood > 150.
Perhaps not doing that is the underlying issue. There's always the chance someone picks up the same raw resource for another job too.
I'm not sure it's worth adding more complexity etc. when it can be solved like that, which is good practice to prevent excessive toggling anyway. - my thoughts
Thanks, will try it and let you know!
Hysteresis would solve it, in most cases.
In the specific case I was testing, dandelions going to the herbalist, it wouldn't have because the total storage inside the apothecary for dandelions was greater than supply for the warehouse. (herbalist: 40, small warehouse: 30)
Yeah, ok that's an interesting edge case - good point
I'm just wondering what the rules would look like. E.g on the apothecary 'unpause if (inbound + in storage) > 20' or something.
Btw, thanks for these saves! Very handy to do the tests 
Is it a question to me?
I would think if (reserved > 20). Input in storage and input on-route should have reserved space?
You're welcome! Thanks for new features!
No, I was just thinking aloud really
Above, I suggested an idea to always account the reserved items into input signlas. Only factories and workshops have input signals, and only there it really matters. For the output signals, we can leave it as it is.
So you check input >= 10 units, and even if the stock only has 5, but there are 5 enroute, the check will pass.
Got it.
What was causing that 'RUNTIME ERROR' and crash for that 1st rule in the save BTW, out of interest? I suspect I had the same issue before as well - with the script I did before the aggregate stuff.
During the load, the scripting system is not ready to handle signals, but there are cases when a signal is thrown (changing the number of providers). There is a setting flag that protects against it, but when you reload the game, the previous state was not reset. So, the loading process started triggering events.
Right that makes sense, that's great that's fixed then!
Create a feature request for the input goods. Feel free to chime in with your ideas and notes: https://github.com/ihsoft/TimberbornMods/issues/93
I also can't think of a time when you'd need the current storage amount where having the 'soon to be delivered' included would be a problem. Maybe if you were being super pedantic about only unpausing buildings that could work RIGHT NOW and were on a really large map I guess, but I'd imagine in a lot of cases it would take less time for the goods to arrive than for the beaver to get to another job.
I've been testing this and so far have been unable to find any problems. I tested if the aggregate triggers e.g Count could trigger other rules also and they did, they correctly update when you change triggers that use them also.
Also the concat debug option is really nice!
Surprisingly, AI gave the right solution. Too bad Copilot can't merge the proposed code changes itself.
Btw, guess what value will Avg give if the there are no signal providers registered?
(if you would make it yourself, sum/count could throw division by zero).
There might be another div by zero actually, I just had a crash (I wasn't even trying).
In that 'rules added' save above, or any probably, when you delete the last tank it crashes.
Also, I was thinking to try the Copilot as well
Div by zero should not crash. It should mark the rule "runtime error".
I wanted to add something to that extension I did and using the codespaces or whatever seemed like a good way...
Yeah, IDK what the cause is but its an uncaught exception
Hmm. So it's on structure deletion. Interesting.
yeah, just got it. Started randomly removing buildinsg with ruels and here we go.
Investigating.
Thanks!
Thank you! You helped finding it 🙂
I actually wondered how involved getting set up to be able to compile the mod on linux would be, you're using Windows for this right? And not a VM I could use by any chance?
If I could I would take a look myself...
@south wedge It looks like the error originates from the rule on the district center that uses the aggregate signal that had it's last 'setter' deleted.
div by zero triggered the bug, but wasn't the reason
The collection si being modified while I iterate.
A popular mistake 🤣
Damn. The issue is not that simple. The signals start traveling really complicted.
Haha. This is what happens.
- Removing all buildings that emit signal make the counter = 0.
- It results in div by zero in another building.
- The rule is marked as "failed", and it tried to be removed from the system.
Thing is, the removal happens in the middle of the process of the signal propagation. It's good it failed this way. Because the issue is much more deep. The failed rules can affect live signals - this is where the problem is.
Reliable way to reproduce: load the save ("running") and delete all three tanks. The order doesn't matter. The errors comes when the last one deleted.
Yeah I was thinking with everything being event driven and also effecting itself it might get messy haha. I was impressed it all just worked so far.
Well, it's the first time I'm making my own eventing system. I actually like seeing all these troubles. It's fun!
I have a question, is there any way currently or planned to make 2 (or more) actions in one rule?
E.g If X I pause AND set signal pumps.running =0
Just to make it a bit nearer than having 2 rules with the same trigger.
LOL good 🙂
I was thinking about. Technical side is simple: add another action actgroup. Some tweaks to the parser will be needed, but shouldn't be too hard. Concerns:
- Why not making two rules instead?
- UI becomes a mess. Even one big action may look bad, a groups would look just weird.
#2 is actually important. Most players like the game "with eyes".
Speaking about AI. Do you know what is its worsts "problem"? So far, no models can really realize they make code. They interpret your code as just another version of "human language". And it creates a problem: they can make a code that looks just right! Except, it doesn't work. And you can spend hours finding out why, because the code "looks right" to you too. The models were trained on the same code samples as you, not a surprise.
Well, I got the error improved:
250530T234932.451 [EXCEPTION] [IgorZ.Automation.ScriptingEngine.ScriptableComponents.SignalDispatcher.CheckifSytemLocked] InvalidOperationException: SignalDispatcher is locked for changes: Signal group update: Signals.A1.Inventory.Water
It's just the first step to have it fixed.
haha yeah it can be touch and go.
I'm not sure if Copilot has a deep think type feature. I've found that works much better, but I've only done stuff where I tell it what I want and copy and paste code and errors to get it right.
Yesterday I was surprised though, I asked DeepSeek to give me a ublock Origin (adblocker) filter rule to make the steam workshop preview image full screen. It took 3 goes to get something that half worked then it nailed it. It was so good. I had to give it some html from the inspector but that's it.
https://www.reddit.com/r/Steam/comments/zta646/why_so_small_preview_for_ants/
Fix is here for anyone interested.
Copilot is good. I use AI every day in Google (where I work). So I can compare. Microsoft trains the code AI better. At least, it knows the difference between HashSet and List.
- Why not make 2 rules? 1. I think 1 rule with longer action script would take less room in UI and editor. Also it makes more sense to me to group everything that should happen for a given action with that action.
2> UI a mess. Yeah, IDK, I guess it could. There's always the option to use multiple rules.
It's a pretty unimportant thing really, I was just wondering as I'd use it.
The other thing I was going to ask you for was to ignore newline characters when parsing the scripts so more complex rules could be formatted over several lines.
Again though it's just asthetics
Hmm. Isn't it there already? Well, maybe I cut some edges when making tokenizer, lol.
I tried it once and it gave me an error so I think it's not allowing it right now, but I'll check and let you know
Ah, wait. If you apply it in the import - it won't work. Obviously. There is no parser there. It doesn't know if the statement continues on the next lime or not.
Yeah in the import
Unlikely I even start on it. It's a full tokenizer/parser rework.
really! I thought maybe just alter a regex a little
Ok that's NP thanks for considering
Recently I was reading about CEL. May be, one day, I will give it a chance. It will cover many complains.
BTW this was what I was trying or similar:
condition: (eq (sig Signals.A1.Inventory.Water) (sig Signals.A1.Inventory.Water))
action:
(act Signals.Set 'A1.Inventory.Water.Level'
(div
(sig Signals.A1.Inventory.Water.Sum)
(sig Signals.A1.Inventory.Water.Capacity.Sum)
)
)
Ah ok, but don't worry if it is any work, thanks though.
CEL, I"ve not heard of that - just looked it up.
condition: (eq (sig Signals.A1.Inventory.Water) (sig Signals.A1.Inventory.Water))
action: |||mutliline
(act Signals.Set 'A1.Inventory.Water.Level'
(div
(sig Signals.A1.Inventory.Water.Sum)
(sig Signals.A1.Inventory.Water.Capacity.Sum)
)
)
|||
or such
I knew about it 2 days ago, lol
And there is C# port.
condition: (eq (sig Signals.A1.Inventory.Water) (sig Signals.A1.Inventory.Water))
action: <<<
(act Signals.Set 'A1.Inventory.Water.Level'
(div
(sig Signals.A1.Inventory.Water.Sum)
(sig Signals.A1.Inventory.Water.Capacity.Sum)
)
)
>>>
Maybe quote the multi line blocks like this? Replacing \n\r with spaces is trivial. Then, it's a regular import logic.
Yeah that would be nice - make long actions and calculations more readable.
Feel free to file a ticket 😉 I need to fix the crash now 
Done: https://github.com/ihsoft/TimberbornMods/issues/94
GL with the bug!
Thanks for your activity 🙂 It really inspires me to make things

Check it out: https://github.com/ihsoft/TimberbornMods/commit/3dea863464a35b0e3f0963c142c24d9868962434
All changes => AI. I was only copy/pasting (intentionally! it was a test).
Add Average function. Rationale: it needs extra logic to not have division by zero.
And the right answer to what will be "average" if there are no values. It will be 0.
Rationale: the custom signals in Automation have default value 0. "Default" means: the signal was not yet set by any provider.
That looks handy! I was wondering if the average would be simple, e.g 1 empty large tank and 1 full small tank would give 0.5 fill average, but it looks like it's going to take into acount the volumes or values, that's great!
BTW @south wedge did you see this: #1190169064383991858 message
Sorry, read and forgot to reply
No idea how it is under Linux. I work whole my day under it at work, but there we code in Java.
I'm a "windows" dude. My desktop is Windows.
I spent an hour an improved the error message!
(kidding). In fact I was playing another game 
Jokes aside, a proper error message is a halfway to the issue resolution when you meet it the first time. And given my memory is not good these days, I prefer to make the code so that it's "not me". Many times confirmed: it works!
A new preview release! v2.4.2
Main feature: .Avg suffix to the signal names. Guess what it means.
But in general, it's just another preview. Some here and there changes. The crash on the buildings demolishing is now nicely reported. You still crash, but with a nice error message! Isn't it cool? 
I'm going offline for 2 days for the family affairs. I'll be around in Discord (my phone is always with me!), but no coding.
So let me guess, now the error says "You've just crashed because you deleted the last building setting that signal. So how to get rid of it then? hmmmm. Bet you wish you didn't put it there now, don't you!" right?
Thanks, have a good trip or catchup etc.
It's nowhere documented, but if you avoid "runtime errors", you will be fine. The crash comes due to the system's (improper) reaction on the "div by zero" error. It can be any error, not only this one. Avoid errors!
Alright, thanks for the tip. 🤞
Hint on how to get troubles (just in case you wonder):
- Select a good on tank.
- Set a rule on this good.
- Change the good

- Reload or somehow trigger the rule => runtime error.
It may or may not crash your game 🤣
Oh well, sounds like progress was made, I call that a win.
Is CEL open source? Apparently. I did not know this. That's pretty cool.
It is. The original version is Java, though. C# is a port, which is maintained by some enthusiast.
FYI: I liked this idea! I'd love to migrate to C# CEL.
Sigh, there's both https://github.com/rayokota/cel.net and https://github.com/telus-oss/cel-net
I did only a brief searching. For now, all I need to know: we have a C# version!
In CEL, I like the main concept. "Let' make a COMMON language for the expressions". Damn, yeah!!!!
Btw, the link I gave is recognized by "our" AI (Gemini). If you ask Gemini to make a parser code, you get the code, referenced to this 3rd party.
(not an advertisement!)
I, honestly, like GPTv4 more.
Yea, I only found the other because it's on NuGet as Cel
You did?! I tried and failed.
It was the top hit for "common expression language c#"
I was looking for "cel". Lol
You could also just use some regex search and replace to format the input and remove whitespace. ChatGPT gave me this which when tested in an online test thingie (technical term) returned:
condition: (eq (sig Signals.A1.Inventory.Water) (sig Signals.A1.Inventory.Water))
action: (act Signals.Set 'A1.Inventory.Water.Level' (div (sig Signals.A1.Inventory.Water.Sum) (sig Signals.A1.Inventory.Water.Capacity.Sum)))
using System;
using System.Text.RegularExpressions;
public static class Formatter
{
public static string FormatText(string input)
{
// 1) Remove comments (“#” to end of line)
string noComments = Regex.Replace(
input,
@"#.*",
string.Empty,
RegexOptions.Multiline
);
// 2) Strip all whitespace around parentheses and braces
string noWS = Regex.Replace(
noComments,
@"\s*([()\{\}])\s*",
"$1"
);
// 3) Add a space before each '(' or '{'
string spaceBefore = Regex.Replace(
noWS,
@"([^\s])([({])",
"$1 $2"
);
// 4) Insert newline before every "condition:" or "action:", except if at the very start
string formatted = Regex.Replace(
spaceBefore,
@"(?<=.)(?=(?:condition:|action:))",
"\n"
);
return formatted.Trim();
}
}
class Program
{
static void Main()
{
string testInput = @"
# This is a full-line comment
condition: (eq (sig Signals.A1.Inventory.Water) (sig Signals.A1.Inventory.Water))
action:
(act Signals.Set 'A1.Inventory.Water.Level'
(div #tricky!
(sig Signals.A1.Inventory.Water.Sum)
(sig Signals.A1.Inventory.Water.Capacity.Sum)
)
)";
string result = Formatter.FormatText(testInput);
Console.WriteLine(result);
}
}
``` (IDK how to make that smaller... oh well)
This was the input string:
# This is a full-line comment
condition: (eq (sig Signals.A1.Inventory.Water) (sig Signals.A1.Inventory.Water))
action:
(act Signals.Set 'A1.Inventory.Water.Level'
(div #tricky!
(sig Signals.A1.Inventory.Water.Sum)
(sig Signals.A1.Inventory.Water.Capacity.Sum)
)
)
The regex based approach has a down side: you cannot report the line where the error happen at. And it's the reason why I parse the input without regexps.
Ah, damn, didn't think of that.
Sometime I see the "No available workers in district." flag on building with worker slots set to zero with Workplace.RemoveWorkers. My current workaround is to manually pause then resume the building to clear it. Would it be worthwhile for me to open a feature request to clear this flag as a part of Workplace.RemoveWorkers, or this obviously infeasible?
This would be a bug report 🙂 I have a code that specifically prevents the notification in this case. It seems you found a pattern when this code doesn't work. Any repeatable steps to reproduce?
The game's notification logic is blind simple: zero workers? => show the notification! When automation sets the counter to 0, it tries to block this notification.
Oh, good to know. No, I don't have repro steps yet. I'll try to pay attention to the conditions under which I see this and put it in a bug report.
Now, you can change the rules as you want. No crashes!
Out of curiosity, how regularly does stable get updated to exprimental?
You never know. I remember time when we had experimental for several months.
So every few months, maybe less often then?
It solely depends on what game developers do. Making of a new update usually takes months, but if they do only tweaks - it can be weeks.
Ah ok. And it would be a massive PITA to make this work for stable huh?
I remember a comment a while ago about merge hell - that's what that was about i take it
Yeah. it's not only code, it's also the whole process that eats time. You need to keep a totally isolated environment for the game. Or switch branches back and forth in Steam, wihc makes own troubles to the JetBrains (caches).
Yeah sounds like a headache. And you're not setup in a virual machine for this right?
We used to use those - VMWare for that exact reason - different VM and environment for different system.
They used to have a tool which you could run to turn a physical windows machine into a windows VM that worked pretty well - so if you were ever thinking to try it you could maybe use that. Also I think I saw their VMWare workstation product recently became free to use or something.
I know how to setup VM, but I'm really not that dedicated to modding 🙂 I make mods for fun, and this versioning stuff is what I do at work.
Looks like 0.7.9.0 landed on stable?
yup
Nice.
Do you anticipate multi-signal support to land on stable then, or the next experimental?
You can use the pre-release on stable now. Nothing special is needed. For the release, I 'd like to add a couple more features before publishing it.
Understood. I saw the issue closed emails and was curious how this all fit together. Thanks.
v2.4.4 (June 3rd, 2025):
- [Feature #86] Add multi-value support for the custom signals. Signal values can be aggregated via name suffix:
.Min,.Max,.Sum,.Avg, and.Count. Not available in constructor. - [Feature #88] Allow operator
addaccepting multiple arguments. - [Feature #91] Allow extra comment styles in rule importing: prefixes
;and//; and multi-line comments/* ... */and#| ... |#.
Thanks!
I was testing one of the older more complex scripts I did that always had unexplained issues to see if it now worked (#1190169064383991858 message) and got a crash when saving the rules on the district center.
It's saying there's a circular execution of a ...Dirty signal, but I don't think there is a problem with it.
This signal is meant to indicate when the water level is outdated and used to trigger an update. It's:
- incremented by tanks when their contents change
- set = 1 when district center rules are saved (on
Init) - reset=0 after an update is done
- this should not trigger recursion because rules require
...Dirty >= 1to fire
- this should not trigger recursion because rules require
To reproduce it add the following script to the district center in this save:
## Area A1 Controller (put on district center)
# Setup an Init signal that can be used as a trigger for other initialization rules
condition:(eq (sig District.Beavers) (sig District.Beavers))
action:(act Signals.Set 'Init' (sub 1 (sig Signals.Init)))
# Recalculate aggregated values by marking them as 'dirty'
condition: (eq (sig Signals.Init) (sig Signals.Init))
action:(act Signals.Set 'A1.Inventory.Water.Dirty' 1)
# When Water total is dirty clear the buffers and do an update
condition: (ge (sig Signals.A1.Inventory.Water.Dirty) 1)
action: (act Signals.Set 'A1.Inventory.Water.Buffer' 0)
condition: (ge (sig Signals.A1.Inventory.Water.Dirty) 1)
action: (act Signals.Set 'A1.Inventory.Water.Capacity.Buffer' 0)
# Toggle .Update to trigger tanks to recount their contents and capacity
condition: (ge (sig Signals.A1.Inventory.Water.Dirty) 1)
action: (act Signals.Set 'A1.Inventory.Water.Update' (sub 1 (sig Signals.A1.Inventory.Water.Update)))
# At this point all storage tank triggers will have completed and buffers contain updated values
# Clear the dirty flag prior to updating the actual value so listners see a clean value
condition: (ge (sig Signals.A1.Inventory.Water.Dirty) 1)
action:(act Signals.Set 'A1.Inventory.Water.Dirty' 0)
condition: (eq (sig Signals.A1.Inventory.Water.Dirty) 0)
action:(act Signals.Set 'A1.Inventory.Water.Level' (div (sig Signals.A1.Inventory.Water.Buffer) (sig Signals.A1.Inventory.Water.Capacity.Buffer)))
# Arbitary add to cause value to display in game UI
condition: (eq (sig Signals.A1.Inventory.Water.Dirty) 0)
action:(act Signals.Set 'A1.Inventory.Water.Capacity' (add 0 (sig Signals.A1.Inventory.Water.Capacity.Buffer)))
# Arbitary add to cause value to display in game UI
condition: (eq (sig Signals.A1.Inventory.Water.Dirty) 0)
action:(act Signals.Set 'A1.Inventory.Water' (add 0 (sig Signals.A1.Inventory.Water.Buffer)))
Also, do you prefer stuff like this here or would it be easier if I made an issue? IDM either way.
This was on the Stable Timberborn version with latest update 2.4.4 BTW (none for Beta in steam properties)
Issues are easier to track. Would be nice if you could post it there.
Alright, will put it there.
Why it fails I can tell right now. The circular detection doesn't verify the condition. It triggers if the same rule gets called. It would be tricky to verify the condition since the signal execution system, knows nothing about the rules. There is a listener that needs to be called if a signal changes, and this is what it does. And listener can be anything, not necessarily a scripted rule. I'll think if this can be handled at the rule side instead 
As for the crash, it's indeed a bug. The game should not crash.
Ok, interesting, thanks
I was just wondering if it would be possible to make a .Mine aggregate function to get the value of a signal which the building itself set. It would be a decent workaround for settings. https://github.com/ihsoft/TimberbornMods/issues/95
Not exactly in the concept of the signals, but makes sense to think about.
Yeah I know, it would be useful though. E.g to have a priority you set for stuff, so you can use the same rules but have a local signal that's different between buildings.
A local signal could also double a mechanism to perform multiple actions on a single condition.
Can you automate based on power consumption ?
Smart power is a better mod for that and do not think it can
I'm pretty much sure, SmartPower addresses 99% of the ideas you would like to implement via Automation. But let's give it a try: which rule would you like to compose for the power related condition?
When my factories are standing still I like to pause power plants/wheels
Was trying to play with https://discord.com/channels/558398674389172225/1379728375396040806 also enabled but got this crash, can it be fixed somehow or is it just plain incompatible?
GetIsHazardousWeather is being called before WeatherService is loaded.
FYI: https://github.com/ihsoft/TimberbornMods/issues/102 is a big issue. I;m making significant changes to how the rules work and loaded on unfinished buuidlings. There will be a preview soon.
v2.4.5 (pre-release, 3 June 2025):
- [Feature] Special shor description for the rules that check signal value to itself: "signal change condition."
- [Change] Rules that cannot execute on unfinished buildings are now grayed in the rule list.
- [Fix #101] Crash from circular execution of rule.
- [Fix #104] Game crashes with ModdableWeather mod.
- [Fix #102] NullReferenceException: Object reference not set to an instance of an object.
I did pretty big changes to the save and rules activation system. In smoke tests, it looks good.
The unfinished buildings rules thing was always there (do not execute some rules if the building is unfinished). It just was never exposed. Now, it's exposed: UI explicitly shows if the rules not being executed (disabled).
@sand thunder @reef widget
And now, it's time got me to dig some resources on Moon 🙂
HF! Will try it out later or tomorrow.
And thanks
What game is this? Not Beavers on the Moon, right?
The Crust. I like the mood. It's more like Factorio than TB. But it has a scene driven play mode.
Plus, it's Space! I came to TB from KSP (Kerbal Space Program).
Cool. Will have to watch some YouTube videos. Thanks for sharing.
I'm not familiar with installing mods outside of Steam, though I'm sure I'll figure it out, but if anyone has recommendations on how to manage the installation of pre-release mods please share.
Ha! You have asked it from the beginning.
Let me make a quick wiki
It can wait. Enjoy Crust!
Alongside Saves there's a Mods folder in a Timberborn folder. In my case (linux) it's /home/username/.local/share/Steam/steamapps/compatdata/1062090/pfx/drive_c/users/steamuser/Documents/Timberborn/Mods
Extract the archive so that Automation folder is in mods, unsub from steam and run - it should show up.
Looks like on windows it would be My Doccuments/Timberborn/Mods
https://github.com/ihsoft/TimberbornMods/wiki/Mod-in-TImberborn
Any thoughts or changes to it are welcome.
there is also this guide you may link or use stuff from it if needed
https://mod.io/g/timberborn/r/troubleshooting-mod-setup
there is also:
https://mod.io/g/timberborn/r/how-to-install-mods
Folks, if anyone knows how GOG works: https://github.com/ihsoft/TimberbornMods/wiki/Mod-in-TImberborn#gog
Let me know, I will give you access to Wiki.
You do know all 3 steam gog and epic have the local mods in the same location on windows?
%userprofile%/Documents/Timberborn/Mods
Linux has it in some other location as of wine not sure of mac
mac is /Users/<name>/Documents/Timberborn/Mods
Thanks for this info! I dind't know 🙂
v2.5.0 (June 5th, 2025):
- [Feature] Special short description for the rules that check signal value to itself: "signal change condition."
- [Feature #150] Add Modulo (
mod) Operator. - [Change] Rules that cannot execute on unfinished buildings are now grayed in the rule list.
- [Fix #101] Crash from circular execution of rule.
- [Fix #104] Game crashes with ModdableWeather mod.
- [Fix #102] NullReferenceException: Object reference not set to an instance of an object.
The eror is gone (thankyou) however there is still something not working like I'd expected.
On the district center, the Signals.A1.Water.Capacity should be 420 (300+30+30+30+30) but it's 3x that - 1260.
My assumptions are:
Sent too soon. My assumptions are:
- rules on a building with the same trigger execute in the order they appear
- if a rule changes a signal any rules that trigger on that signal change will fire and complete before continuing to execute/trigger the next rule on the building that changed it
- signal values are global and updated instantly (I guess this is obvious)
There's still something not right. Maybe one of those assumptions are not true.
rules on a building with the same trigger execute in the order they appear
This cannot be guaranteed. All rules are executed by a callback when a value has changed. In a group of the same listeners withing the same building, you can expect some ordering. But otherwise, there is none.
In fact, I would strongly discourage implementing logic that assumes the order in which signals are executed.
If you feel you need to know the signals "order", let me know what is the use case. We probaly can have it worked around.
And just in case you are trying to make the "district capacity" counter. Don't 🙂 It's my next feature. I'm going to make a signal that returns district capacities on a good.
(but please, keep trying to make my mod failing!!! It's very important to make it stable)
Haha yeah ok sounds good.
I'm just trying to figure out the rules - like what I want to do is more like a script, and being able to take only 1 action per trigger means order matters
I put things on the same building with same trigger hoping that would give deterministic order
Will do!
So do you think it's the rules with same trigger on the same building executing out of defined order that's causing issues with that save?
Once, I had an idea to disallow handling signals on the same building which changed it. Silently. I ended up with a decision it's not needed. Your thoughts?
Need to check.
I think recursion is a useful feature and I was planning to make use of it with priority stuff - reduce requested start priority untill enough buildings are running. Sounds like that wouldn't work with that limitation though.
I meant to reply to this
And BTW, I know I can use Sum to do the stuff in that save, I use it now more as a proof of concept for testing execution order etc.
The more failing case you find, the better! Thanks a lot for your efforts.
Well, something is failing in that save. I think it should work.
make sure you have verbose logging enabled. And all the other options too. It makes a lot of noise in the logs, but when a problem happens - it helps.
Ok, I'll check that, and try a simpler version. I'd hoped you could tell me why it wouldn't work.
This is on the tanks (5)
condition:(eq (sig Signals.A1.Inventory.Water.Update) (sig Signals.A1.Inventory.Water.Update))
action:(act Signals.Set 'A1.Inventory.Water.Buffer' (add (sig Inventory.OutputGood.Water) (sig Signals.A1.Inventory.Water.Buffer)))
condition:(eq (sig Signals.A1.Inventory.Water.Update) (sig Signals.A1.Inventory.Water.Update))
action:(act Signals.Set 'A1.Inventory.Water.Capacity.Buffer' (add (getnum Inventory.Capacity) (sig Signals.A1.Inventory.Water.Capacity.Buffer)))
condition:(eq (sig Inventory.OutputGood.Water) (sig Inventory.OutputGood.Water))
action:(act Signals.Set 'A1.Inventory.Water.Dirty' (add 1 (sig Signals.A1.Inventory.Water.Dirty)))
This on the district center
condition:(eq (sig District.Beavers) (sig District.Beavers))
action:(act Signals.Set 'Init' (sub 1 (sig Signals.Init)))
condition:(eq (sig Signals.Init) (sig Signals.Init))
action:(act Signals.Set 'A1.Inventory.Water.Dirty' 1)
condition:(ge (sig Signals.A1.Inventory.Water.Dirty) 1)
action:(act Signals.Set 'A1.Inventory.Water.Buffer' 0)
condition:(ge (sig Signals.A1.Inventory.Water.Dirty) 1)
action:(act Signals.Set 'A1.Inventory.Water.Capacity.Buffer' 0)
condition:(ge (sig Signals.A1.Inventory.Water.Dirty) 1)
action:(act Signals.Set 'A1.Inventory.Water.Update' (sub 1 (sig Signals.A1.Inventory.Water.Update)))
condition:(ge (sig Signals.A1.Inventory.Water.Dirty) 1)
action:(act Signals.Set 'A1.Inventory.Water.Dirty' 0)
condition:(eq (sig Signals.A1.Inventory.Water.Dirty) 0)
action:(act Signals.Set 'A1.Inventory.Water.Level' (div (sig Signals.A1.Inventory.Water.Buffer) (sig Signals.A1.Inventory.Water.Capacity.Buffer)))
condition:(eq (sig Signals.A1.Inventory.Water.Dirty) 0)
action:(act Signals.Set 'A1.Inventory.Water.Capacity' (add 0 (sig Signals.A1.Inventory.Water.Capacity.Buffer)))
condition:(eq (sig Signals.A1.Inventory.Water.Dirty) 0)
action:(act Signals.Set 'A1.Inventory.Water' (add 0 (sig Signals.A1.Inventory.Water.Buffer)))
I'll write psudocode
# On all water tanks
if update, set water.buffer += my.water
if update, set capacity.buffer += my.capacity
if my.water changed, set dirty += 1
# On district center
if Init (rules saved), set dirty = 1
if dirty >= 1, set water.buffer = 0
if dirty >= 1, set capacity.buffer = 0
if dirty >= 1, toggle update
if dirty >= 1, set dirty = 0
if dirty = 0, set level = water.buffer / capacity.buffer
if dirty = 0, set capacity = capacity.buffer
if dirty = 0, set water = water.buffer
However capacity.buffer is 3x more than it should be
So it looks like the buffers aren't set to 0 before the tanks add their own water amount and capacity to them. In the log the actions appear in the correct order - you can see the action to set the buffer to 0
But following that the action to add to that same buffer shows adding to a non-zero value if I'm reading it right.
I'll double check signal names
They look right. Not sure why
Executing signal callback: SignalCallback(Host=IgorZ.Automation.Conditions.ScriptedCondition(Pre="";Expr="(eq (sig Signals.A1.Inventory.Water.Update) (sig Signals.A1.Inventory.Water.Update))"),OwnerBuilding=[SmallTank.IronTeeth@(29, 24, 4)], Name=Signals.A1.Inventory.Water.Update)
[SmallTank.IronTeeth@(29, 24, 4)] Setting signal value: source=SignalSource(Value=87000, HasFirstValue=True, ProvidersCount=1), value=129000
# Actually, I'm confused. This should be alternating adding own water and adding 30000 to a zeroed signal.
``` isn't adding to a zero value signal - it should be.
I wish I could debug this, step through and see everything.
From what I can tell from the log the 3rd assumption is failing and 1 and 2 hold true:
- rules on a building with the same trigger execute in the order they appear
- if a rule changes a signal any rules that trigger on that signal change will fire and complete before continuing to execute/trigger the next rule on the building that changed it
- signal values are global and updated instantly (I guess this is obvious)
I added an issue for this: https://github.com/ihsoft/TimberbornMods/issues/107
Please let me know if there's anything else I can do to help.
Also, @south wedge , I watched a video recently about building on the moon. It was about casting regolith. It, like basalt (IIRC), is in fact perfect for casting as it's constituents all have a very similar melting point (you don't end up with different substances solidifying in pockets as it cools due to having vastly different melting points like some minerals or soils).
You can actually make a bunch of mirrors which could be just aluminium foil, also available from regolith, and point them at a crucible, dump a bunch of 'dirt' in it then when it's molten, pour it into a mold to make bricks or any shape you want really and have a high quality strong outcome.
My home town (Adelaide, Australia) turned out the have the only university that had put out papers on casting regolith where many other places had focused on 3D printing structures etc that required additional materials and water to be shipped in (huge cost and limitations).
No need. Just get dirt, melt it like you did the ants when you were a child and make your house, roads or whatever else from it. Done.
IDK if this helps in your Crust endevours but there it is. GL 🙂
And that's actual real science - true facts so to speak. I love that stuff.
Hmmm...
Would there be any point to an automation flag for "building flooded"?
Buildings are inoperable when flooded, right? So it would have to be used to set a custom signal that's used by another building?
Or possibly an emergency drain.
@reef widget @tribal canopy did either of you ever try something like the script I posted above?
Or something that relied on #1190169064383991858 message to work?
Nothing quite as complex... This is something I tried to do. However, I did run into this issue
On Small Tank: condition:(ge (sig Inventory.OutputGood.Water) 0) action:(act Signals.Set 'D1.Have.Water' (add 0 (sig Inventory.OutputGood.Water))) condition:(ge (sig Inventory.OutputGood.Wa...
Mods for Timberborn game. Contribute to ihsoft/TimberbornMods development by creating an account on GitHub.
The most I did was try to have a centralized start/stop threshold managed by the District Center. It listens to storages advertising their size, and it sets a start/stop threshold as a percentage of district capacity, which are used by water pumps.
Did it work?
At runtime yes, but on game load there were missing signals.
From my analysis, the signals aren't being restored on game load, but the aggregate signals (i.e. .Sum) are.
Igor has yet to confirm my observations.
What I did didn't work on load or runtime. I think it may be much the same, except perhaps I had an update singnal as well in the mix
That does sound like a load issue though and in my case it never worked
Say you set the signal Test: action: (act Signals.Set 'Test' 100)
Then you save the game and reload it.
Signals.Test will read as 0 until the action is triggered again, but Signals.Test.Sum will correctly read as 1.
Yeah, that's a definite load issue
My problem was not related to saving or loading - it just didnt function as I'd expected
Yeah, I've avoided potential circular dependencies after a very early issue: #1190169064383991858 message
I wondered if maybe you or @reef widget could see an error in my code/logic or could confirm it 'should' work
Sure, if you just want a second set of eyes on it, I'll take a look. Not sure I'll be able to test it, though.
Absolutely!
This save:
#1190169064383991858 message
This psudo code:
#1190169064383991858 message
This is the actual code: #1190169064383991858 message]
I suspect at this point someone with debug capability will need to step though and find the point at which it's failing. I would absolutely love to but I've recently abandoned Windows for Linux and although I don't know for certain I think this kind of debugging is a lot harder to setup to say the least.
I guess for now I'm looking for 'on windows': 'it should work but doesn't
OS shouldn't matter for the game, just dev really
So @tribal canopy , I'm dying to ask, what did you find?
I'm impatient 😁
Haha. Sorry, I was in the middle of something else I had to finish first. I'm pulling it up now.
so, I don't want to clap I just want to thumbsup, so yeah. IDK how get rid of the clap. 1st world problems
NVM, consider me the ultimate hero of everyone who reads this> The alpha of ahpha's the omega of omegas. The one true left clicker of left clickers. And what not
I just hope someone will relate to this discord convo and get a chuckle
haha
logically, it seems sound... but it does make assumptions about ordering and coherency/thread-safety?
This looks very similar to logic I abandoned because it tripped the circular execution detection:
condition:(ge (sig Signals.A1.Inventory.Water.Dirty) 1)
action:(act Signals.Set 'A1.Inventory.Water.Dirty' 0)
Yes, that used to not work but I think that last change changed that.
ah, okay
The way it was signals would trigger 1st then check expressions after... I think that was changed so they would only trigger if their expressions allowed.
honestly, I think we can't rely on any of the += logic and need to leverate the .Sum builtin suffix.
I kinda get what you're saying. Absolutely most of what that does is done by Sum. But there's really only 2 triggers. the Dirty Trigger and the Update trigger that is toggled as a result.
I only use that script now as a proof of concept for execution order etc
The simultaneous handling of the triggers is where I'd venture the problem is. It feels like you classic read-modify-write race condition.
as a proof of concept, did it work with a single water tank?
IDK I never tested with just 1
In my mind it should work with either but maybe that's worth testing
I think you may be onto something here: read-modify-write race condition.
I'm trying to write an example...
Just saying: what would be more useful than an example is something we could test
Say actor A and actor B attempt to do a read-modify-write 'buffer" at the same time, you could get this sequence:
- A reads
bufferas 0. - B reads
bufferas 0. - A writes 0 + 1 to
buffer - B writes 0 + 1 to
buffer
unless there's an explicit mechanism to make B read after A has done the write, you can never guarantee the above won't happen
by it's nature, the behavior isn't deterministic, so the only real test is to stress the system and see if it fails... I think you've done exactly that
That's pretty much what I concluded - that signas weren't truly gobal
it's not that they're not global, it's that modifications aren't atomic
*atomic
Not challenging, wanting to learn, what's the differnece
Global = instant update everywhere
B can only see what A writes to buffer... B cannot see that A is reading from the buffer about about to write to it...
it would be atomic if B is not allowed to read from buffer after A has read from it and is planning to write to it
an "atomic" read-modify-write means that nothing is allowed to happen between the read and the write
So, I understand namespaces. That's more generic perhaps. What you're describing is to do with a specific value. Which also makes snese
sense
"global" just means what's written to it is visible everywhere
after A has read from it and is computing the value to write, it has not yet modified the value... so visibility isn't playing a role yet
The whole signal system is event driven, do you think the atomic value mismatch fuckery-for-lack-of a better word is like you describe?
yeah
yeah, read-modify-writes are not generally compatible with event-driven systems
Ok so let me describe what I had in mind and please shoot it to shreads> There ware Singnal Objects that were defined on a global scale> they each had local static varibles, their value, that updated the instant they were set from anywhere. They were essentially global variables....
But, evidence suggests this is not the case
yeah, in such a case you generally tend to need mutexes guarding the global variable to prevent this exact issue
this mod doesn't have anything analogous to mutexes
Ok, so what I assumed as a purely single threaded mod is in fact not a purely single threaded mod. basically
the issue you're seeing suggests it isn't
the other explanation is caching
It's a real problem for any complicated script if we can't rely on one rule executing after another
surely though a read would not have an issue with this
i.e. when a global signal is changed, it's value is copied into an object passed to the callback
if the value is cached and the cached before any callback is called, then the callbacks are called sequentially
It all seemed single threaded when I lightly tested it and going through the verbose logs confirmed that. If there's some async kind of thing messing this up it happened in a way that make the log still seem synconised as if it was single threaded
It would have been great if there was some write or trigger out of place, but I didn't see any...
testing it with a single tank will pretty much confirm it's a read-modify-write race... regardless of the implementation detail that's causing it
Ok I'll try that
if it seems to function with a single tank, but not multiple
You tried it?
no, didn't try it... just clarifying expected outcome based on the hypothesis
Ok I will go and test with a single tank
Not 100% on what that will prove or disprove but will let you know
it should prove that the logic is sound
Logic is sound, I already know that 😉
this is what I get when a hauler delivers water to a storage tank
Everything starts at 0 if I read it correctly, as it should.
So I'm not sure what this means.
I deleted all other tanks, there's only 1
I'm actually not sure that's relevant - it's only the dirty signal and the actual water amount is not included
oh, you don't get a log for the buffer update?
no, apparently not
Unless it's hidden under one of the conditions listed there that lack actions
That would be the place where that would be expected
I sometimes have a building act as a monitor for signals I'm debugging:
condition: (eq (sig Signals.Test) (sig Signals.Test))
action: (act Debug.LogNum (sig Signals.Test))
unfortunately, the debug logs don't let you pass a string to label the number you're logging, so I track what's being logged by which building is logging it lol
Ok, yeah I don't think logging will for sure detemine this problem because if it's due to execution order debug log rules will be of limited help
There's a new concat fuction or statement that helps a lot now
if you're no longer suspecting a logical issue, there's no need to test with a single tank as I suggested
Igor should be able to just tell us if read-modify-writes are atomic
what do you mean a logical issue? I'm pretty sure the logic is sound But i can't be sure as I'm not sure about how things run
If you can't see any issue I'm sure we're at the point where debugging, breakpoints and all information is needed to diagonse this
by logically sound, I mean that if not for the race condition I suspect it would work
if the system doesn't behave as you expect, I don't consider that a logic issue
Yeah, I'm not certain. Thanks for you help with this, I really appreciate it
Well I stated my assumptions: #1190169064383991858 message
and as far as I can tell only 3 is failing
And actually testing those is the entire point of that script, it's pretty much redundant otherwise.
my impression is that your test has proven that operations are not atomic... the only further certainty we can get is reading and understanding the mod code, or the author telling us
BTW, does this link: #1190169064383991858 message work every time you click it?
It only works like 1/4 of the time for me.
Seems like 1/2 the time it goes to a different post.
Anyway, not atomic operations. Yeah, I still think they are. I'm not sure what's going on but I reckon it's all single threaded 100%. There will be some other explaination I expect.
But anyway, thanks for helping with this!
Yeah, the link h as work for me each time I've clicked it.
Are you using the mobile version of Discord?
It has never worked properly there.
No, it's cachy browser on cachyos. I've no idea why it doesn't always scroll to the right place
Wait no, it's the discrod snap I think.
No the discord flatpak. That's what I installed and doens't work 100%.
It's from Discover store - on CachyOS - that's what I'm using because it doens't spy on you and works with games, apparently>
I got to say switching from Windows was a big win.
Glad I did. Even if there are some minor issues and stuff I don't yet get.
If anyone is considering doing so, my 2c, just do it. Fuck windows, that's messed up what they and everyone else is doing. There are alternatives, if you give a damn, use them.
And for the record, when I say the discord flatpak doesn't work 100% it does except when you click links it might not scroll right too them - stop short or something. Other than that, no issues.
You do have a point, it does seem like this is the case. I just want to acknowlege that even though I still believe there is another explplaination and operations are atomic, for some reason. I just have a hard time believing Timberborn and Automation is multithreaded enough for that to be the issue here. Shit is dumb, usually, probalby here too. My take.
Got another crash from drought start, still a conflict with Moddable Weather. Just had a look with ilspy, seems that mod uses differently named classes for basegame weather, eg. GameDroughtWeather/GameBatideWeather/GameTemperateWeather, in addition to adding custom ones. This may need some more logic fixing, or perhaps a separate compatibility patch?
this will crash if the user uses any of the modded weather anyway. my mod still keep the original weather ID (not the type). So maybe just ignore if it encounter an unknown ID instead of throwing?
Wow! Good to know. In "The Crust", regolith is a key resource. One of the applications is "Smart Concrete". Not sure why it's "smart", but it's concrete.
Can be added, but what's the use case? At this point I'm trying to avoid adding things that are not really needed. Many options will blow up the constructor UI. And it will require a major refactoring of the UI concept. It will happen one day anyway, but I try to delay the moment 🙂 Option: add a signal/action, but not expose it to the constructor.
Working on it. Thanks for the very detailed description of the problem. It really helps.
As for the signal loading. Confirmed a bug. The "last" value is not restored. And not saved, lol. All signals per building are saved/restored properly, but "last" is a different thing - it depends on what happen in runtime. I had to store this value explicitly, and I didn't.
It just came to mind, but I can't see a decent use-case either.
@sand thunder This preview properly saves/restores the last value. Note, that the old saves will load with 0 values for all signals. Sorry, I don't want to keep the compatibility code.
That's no problem, thankyou.
@south wedge @floral thicket Any chance for weather mod compatibility, at least not to let the game crash on hazardous weather? If the weather signal-string doesn't need to be a constant/localizable, you could even just pull the weather's Id ... or just add a generic "unknown" hazardous weather/season constant for modded weathers/seasons
Sorry for the trouble
Its supposed to be fixed in 2.5.0. Do you still get troubles? What's the error?
It no longer crashes before the main menu, but ...
It still crashes ingame when any non-temperate season starts, that mod uses separate (that don't ihnerit from the originals) classes even for the basic drought/badtide weathers
See above: #1190169064383991858 message
Or did I just not get a proper update for this mod from steam ...
Seems there was also another such bug report on the steam workshop: https://steamcommunity.com/workshop/filedetails/discussion/3324234282/599654768975027756/
Ah, this is a new error.
Well, I see the palace where it fails. It's not actually a fail, it's a failsafe check to ensure the new seasons was properly recognized by Automation. The new seasons are not known to Automation. Thus - failure.
I can remove the check to not crash the game, but the season based eventing will not work.
Seems they still kept the same Weather ID for those basegame weathers, see their comment above.
Guess you could switch to checking the Id rather than the class/Type ... if that's not a bad idea
Yeah, seems teh IDs need to be checked instead of class names.
I will adress it soon. Byw, here is teh tarcking bug for this: https://github.com/ihsoft/TimberbornMods/issues/104
v2.5.2 (pre-release, June 6th, 2025):
- [Fix #103] Signals not restored on game load.
- [Fix #104] Game crashes with ModdableWeather mod.
@floral thicket @wicked furnace
I did smoke tests. Seems working to me.
Note that there are modded weathers so maybe if the ID is unknown, you should just silently ignore it instead of throwing 🙂
for example, Monsoon and Rain etc (and many unknown as mods can further add more)
Well, it's a debatable thing. If season changes, the scripts need to know it, right? And what do they know if the seasin ID is unkndow?
Technically, I can p[ass the ID "as is", but it will result in a very unpredicatble logic.
You said you keep ID intact. Isn't it the case for the Moonsoon?
well I don't know about the logic. but I am just stating what is happening.
no what I meant is, Badtide and Drought IDs are kept intact because the game has it
but the game does not have Monsoon
Ah. Unedrstood.
just curious, but why does the mod need to understand the string, rather than just allowing scripts do a string compare against an arbitrary string?
For the rules constructor.
There is no way to obtain "a full list of season ids".
found another issue: if a goodId contains some 'special' characters, then the signal name for its quantity turns out invalid ... for example, cond: (eq (sig Inventory.OutputGood.Grapes_MorePlants) 100) throws an error of "bad symbol name"
because if you throw when the ID is unknown, then the crash will just happen again, because there are more weathers than the base game
Hmm. Is this a real example? I mean, someone created good ID with underscore? 
So, the rules constructor can stick to seasons it knows, but scripts can use any arbitrary season? That sounds ideal to me.
I would predict that this will become a source of many questions going forward. But ok - let's do it this way for now.
yep, it's the grapes from @gritty patrol map mod (and the whitepaws faction too irc)
Could you please give me the full IDs list? I'll add it to the "allowlist". All the other will result in a warning in the log.
Here you go. No crash, only a warning in the logs.
BadtideWeather, DroughtWeather, Monsoon, ProgressiveTemperate, Rain, ShortTemperate, SurprisinglyRefreshing, TemperateWeather
but I think it's a bad idea to make a list.
because anyone can add more in
and I plan to make more weathers soon anyway
Only for the logging purposes. I don't want people coming to me and complaining about strange log records. On the other hand, I want them to come in case of some real issue happen.
They will be flagged 
Also, consider this. You are a newbie who decided to use Automation. You go and read Wiki to know what signals you have. And there, in the weather signal section, what should I put to describe the returned value? "You will get an arbitrary string that depends on the mods set you have in the game?" It would be unlikely a good documentation style.
The game crash (due to the check), was the way how we knew the problem exists 🙂 Otherwise, it would be people coming and asking why didn't their scripts work.
@floral thicket Feel free to ping me or send a PR when you add new IDs: https://github.com/ihsoft/TimberbornMods/blob/54aaca076a48f1197861c4d1d5a73b14b339cd8b/Automation/ScriptingEngine/ScriptableComponents/WeatherScriptableComponent.cs#L25
Do all weather types have a common base class?
I think the solution here is to have a mandatory field for the name that this mod (or any other that needs to access the weather system) can then detect and use to bind to them. Essentially a standard communication interface.
Then this mod should probably have moddable weather as an optional dependency (I think that exists, at least) so that the game will load them in the correct order by default.
yes, IModdedWeather, and IModdedHazardousWeather and IModdedTemperateWeather but I don't think he wants to check that because he has to refer to my DLL
or, guess he could check using Reflection and type name string
ModdableWeather.Specs.IModdedHazardousWeather if you want to use that route.
and I think it's not fair to ask one modder to support another mod's code
Dependencies to the other mods is a headache to support. Let's try to keep it as simple as possible. For now, just strings is OK.
I see you now do set the season signal to the "unknown" weather's id, but it can't be checked against
When does "unknown" show up?
Well, in fact I figured out that the non-standard IDs cannot be used (other than dumping them). The scripting system does type and value checking. I don't want to remove it, but it won't let you specifying the unknown season IDs in conditions. I have no good solution for it right now.
Maybe adding another signal with no value options, and hiding it in the constructor?
a .Raw suffix that bypasses the checks?
Or a global setting to bypass any checks ("advanced mode").
has anyone thought about how you might implement something like per-slot job priority with Automation?
https://timberborn.featureupvote.com/suggestions/297296/add-different-job-priorities-for-buildings-that-have-more-than-one-worker-availa
Add different job priorities for buildings that have more than one worker available. (per slot) - Timberborn – Bugs and Suggestions
@heady summit An example with input automation:
This monitors the total number of logs in the district (or at least the sum total of logs in every log pile with the broadcast rule applied), and shuts down the lumbermill if there is less than a certain quantity, or if there in no place to store the planks (detected based on internal inventory).
This ensures that the lumbermill can never use up all of your logs, so there will always be enough logs to use as fuel for things like making food.
;;;;EVERY LOG PILE IN THE DISTRICT
;;;;Auto-detects the type of resource set in the pile/warehouse/tank.
condition:(eq (sig Inventory.OutputGood.{% (getstr SingleGoodAllower.AllowedGood) %}) (sig Inventory.OutputGood.{% (getstr SingleGoodAllower.AllowedGood) %}))
action:(act Signals.Set 'District1.{% (getstr SingleGoodAllower.AllowedGood) %}s' (sig Inventory.OutputGood.{% (getstr SingleGoodAllower.AllowedGood) %}))
;;;;LUMBERMILL
;;;;Rule 1: Stop the mill if the log supply is critically low OR the internal plank storage is full
condition:(or (le (sig Signals.District1.Logs.Sum) 75000) (gt (sig Inventory.OutputGood.Plank) 1200))
action:(act Workplace.RemoveWorkers)
;;;;Rule 2: Restart the mill once the log supply is stable low AND the internal plank storage has space
condition:(and (ge (sig Signals.District1.Logs.Sum) 100000) (le (sig Inventory.OutputGood.Plank) 1200))
action:(act Workplace.SetWorkers 200)
Nice usage of the template mechanism 👏
You can create rules that would increase/decrease number of workers in the building. This looks like what you are suggesting.
Let's use the badwater rig as an example.
- Have every tank storing badwater broadcast
DistrictName.Badwateras the quantity they have avaiable (say, 12,000 units total) - The badwater rig listens to the tank output and changes the number employed to match:
- <10% calls 10 workers
-
50% calls 5 workers
-
90% calls 2 workers
- 100% releases all workers
Hmm... could the number of workers be used as an input in this?
That way the 10-worker surge could skip the 50% rule.
Alternatively, Perhaps a signal could be used as a flag to skip over it?
That said, the only workplaces I could see this sort of multi-stage job rule being useful on are:
- Badwater Rig (10 workers)
- Mine (10 workers)
- Hauling Post (10 workers, based on number of beavers in the district, according to
Haulers = beavers * 10% + 5)
Hmm, thinking about my original idea (#🤖mod-creators message) now, could there be a feature that always applies the same settings to a type of building by default across games?
I think that might be the best bang for the buck, so to say
Or a "set as building default" button?
Importing/exporting is already there, so I imagine there could be a persistent, special folder with files named after the buildings that always get applied when they're built
I was thinking about this idea, but so far didn't make a final vision of how to make it. The problem is not technical, it's more about usability. If people cannot find a feature, they assume it doesn't exist. So implementing something that only few gurus can find and use is a waste of efforts.
In addition to the export button, a "Set as Default" (for this save?) would totally work for me. Right now, the default is "do nothing" so I don't think we'd break any workflows. Except maybe another "Clear all automations" control would be helpful
And how will you know what is "default" after the fact you saved it? And how to change it afterwards? It all would need UI in some places.
Oh, right, I stumbled into something earlier.
Is it intended that applying a template/copying rules to a pile or warehouse in a stack also applies it to every warehouse above it?
This is how the selection system works in TB. I can switch if selection should go up or down from what you're pointing on, but that's it.
At least it was this way in U6 and early U7.
Hmm, that would probably need a menu to see what the defaults are, and possibly all rules in one place...
And this is where the "small tiny feature" stops being a such 🙂
Hmm, well, it would just load up new buildings with that automation. Afterwards, make changes and save it as default again. I wouldnt expect those changes to propagate elsewhere, since it would only apply to newly built buildings. 
Thus no need for any extra buttons except the ones I mentioned above, I suppose. If you wanna see the current default, just plop down a building.
So less "intended" and more unavoidable side-effect. okay.
And what would be "clear the default"? What you describe may look as an easy thing to implement, but it will create a lot of frustration down the path if there is no clear way to see what's applied to the new buildings.
Tbh, how many similar buildings at time you build? 5? 10? Not too much to be very bored by using the copy tool.
If people are really curious, they can check in the folder that's created with templates for all the buildings, maybe
Clearing all would be just removing all automations. Save that as default and you're back to "normal"
Are you serious? 🙂 Most people cannot attach logs due to they don't know how to find them. This is an absolutely not working approach.
FWIW, you can "go to the folder" right now and create your own templates. Did you try? 😉
If I were using such a product, I would be very mad at the author for such unclear UX.
I'd have to manage my own files, right?
What do you mean? All files on your machine are yours.
yeah of course. I mean as far as I saw all I can do at the moment is copy/paste templates, so I'll be managing my own automation collection (wherever)
I mean this: <mod folder>/Blueprints/Tools. These blueprints describe the autamation tools. You can create your own or modify existing.
Ah, that I didn't know. Let me check
Keep in mind that the mod's folder may get cleaned up by Workshop when updating the version. So you better keep the copies. Or try making a symlink with RO permissions.
How about a "copy to similar buildings" like Smart Power has?
In SmartPower, the similar buildings are searched by the network. What would be "similar" in case of automation? The buildings can be unfinished or non-connected to the district. Or they can be non-district buildings.
Was thinking about having it based on employment. Each building would have to advertise it's worker capacity, though.
Currently it's wanting to balance between haulers and researchers that has me thinking about it.
District would be reasonable in my mind.
It's not known until the building is actually connected with a road. When doing massive builds, it's rarely a case.
@sand thunder This should fix https://github.com/ihsoft/TimberbornMods/issues/107. I also changed how the circular execution is detected, I recall someone reported it.
I'm trying to control the floodgates using the stream gauge. If the contamination is greater than 5%, the flootgates should be closed. Floodgates at a discharge point should be opened. If contamination is under 5% it should be the other way round. Unfortunately, I don't understand what I need to set on the stream gauge and the floodgates. I hope someone can help me. It's probably quite simple for the experts here, but unfortunately, I don't understand this scripting language at all. With the constructor I can`t find any possible solution, and writing the script by myself is beyond my possibilities.
Give me a few minutes and I can create a demonstration script.
that would be so helpful, many thanks
So, for the steam gauge part, there is a template that gives you all the options:
All I do is change the name of the output signal:
Typical stream gauge setup for me:
This broadcasts the signal for the master floodgate to receive,
;;;; STREAM GAUGE
;;;; Broadcast contamination level on change
template:Gauge.Signals
precondition:(?sig StreamGauge.Contamination)
condition:(ge (sig StreamGauge.Contamination) 0)
action:(act Signals.Set 'Gauge1.Contamination' (sig StreamGauge.Contamination))
;;;; MASTER FLOODGATE (I USED A DOUBLE FLOODGATE)
;;;; If the season is "Temperate" AND the contamination level is below 0.03 (3%)
condition:(and (eq (sig Weather.Season) 'temperate') (lt (sig Signals.Gauge1.Contamination) 3))
;;;; Set height to 1.75
action:(act Floodgate.SetHeight 175)
;;;; Once triggered, it stays at this height until the season changes
;;;; At the beginning of a drought, raise the floodgate to the max height: 2.00
condition:(eq (sig Weather.Season) 'drought')
action:(act Floodgate.SetHeight 200)
;;;; During a badtide, drop the floodgate to 0.00 to minimize contamination risk
condition:(eq (sig Weather.Season) 'badtide')
action:(act Floodgate.SetHeight 0)
;;;; Broadcast master floodgate height
template:Floodgate.Sync
precondition:(?sig Floodgate.Height)
condition:(ge (sig Floodgate.Height) 0)
action:(act Signals.Set 'Floodgate1.Height' (sig Floodgate.Height))
;;;; ALL SLAVE FLOODGATES
;;;; any time the height of the master floodgate changes, update to match.
template:Floodgate.Sync
precondition:(?act Floodgate.SetHeight)
condition:(ge (sig Signals.Floodgate1.Height) 0)
action:(act Floodgate.SetHeight (sig Signals.Floodgate1.Height))
wow, that looks so confusing to me
many thanks for your help, I will give it a try
what do you mean by master flootgate and slave floodgate?
You can import that script directly.
maybe discharge point and other 
Technical terms for communications protocols.
There is 1 master floodgate; it listens to the stream gauge and determines the correct height to move to, then broadcasts that height.
Every other floodgate that should move with it is a "slave floodgate"; they simply repeat the height that they were sent without any other logic.
This means that if you want to change the settings, you only need to adjust the 1 master floodgate, and also limits the number of floodgates being constantly pinged by changes at the stream gauge to 1.
It`s all Greek to me. Looks harder than rocket science. Will try it, really appreciate your help!
It works great, you are a genius!
Yes, @reef widget is a true master of making scripts!
Hey, @floral thicket . Regarding the custom seasons. In general, are you willing to integrate with Automation. If yes, I can think about a kind of API (reflections based) so that the external mods could provide extra values for the fixed value arguments. This will let to show them in the constructor, but the side back is that localization will also be needed (loc key).
I am not sure how that works, what do you need?
right now all the weathers are registered as interfaces btw
and are all singletons
as well as specs
idk yet. This needs to be designed first. I'm just curious if it's worth it.
Specs you say... hmm 
so you can either grab a spec of type ModdedWeatherSpec
or you can grab from the game's IContainer all Multibound IModdedHazardousWeather and IModdedTemperateWeather
but I think the former will be easier for you
Anything with "modded" in name is a no go solution. I don't have this types in my mod. Neither I want to bring them.
though ISpecService doesn't provide non <T> overload I believe, but you can use reflection jsut fine
you will have to use Reflection anyway?
Well, I actually hoped it will be you 🤣
I don't know how I can help lol
I don't like the "pull" approach in this case. If a mod adds something, it should "push" it forward. It will make the code a spagetti.
yeah I agree, you cannot just add reference to all the mods out there.
well for the game, it's the Spec system
Right. The only problem is how to fetch all teh specs and bind IDs with the UI spec.
or EvenBus which my mod does push when a weather starts/ends, but EventBus also use concrete types.
IHazardousWeatherUISpecification is almost good, except it doesn;t have ID
I don't think this is how it work btw, I do push a lot of info out, but since you are right that you don't want to refer to my DLLs, I don't see how it's possible. either you have the concrete type, or you use Reflection
That's true. One of teh sides will have a concrete type, the other side would need using reflections. The question is wich side.
say I agree to give you a whole list of weather ID, how do I do that without a new type?
This needs to be designed. If you are in general agree to go this way, I will think how to make it simple and usable.
EventBus also uses concrete type unfortunately
also EB is risky because of timing. say I send out the registered list, remember you won't receive it until PostLoad
True, but managable. Due to my mod needs, I register to EB very early (in ktor). Exactly to be able to catch what happens during Load.
Technically, if you post to EB and "even" of type ComponentSpec, I will be able to catch it.
nope, EventBus code does that. It holds all events until PostLoad
you won't receive it until PostLoad, not because you register, but because EB's behavior
Didn't know, but it's even better.
I effectively means that anyone who registered prior to PostLoad will get all the events.
yes but don't you need that list to get your stuff ready?
I think the simplest way is use Reflection on your side on ISpecService lol 😛
All scripts are parsed after PostLoad and before the game is "unfreezed".
cast it to SpecService, scan the _cachedBlueprints for any of type with the name ModdedWeatherSpec
so you get the hold to the reference of the type ModdedWeatherSpec. then use it with SpecService.GetSpecs<T> using MakeGenericArgument with the reference to that type. and you can grab the Id.
Ideally. To start with, I need to know it's teh weather spec and not anything else.
here you go:
ImmutableArray<string> GetAllWeatherIds()
{
var spec = specService as SpecService ?? throw new Exception("ISpecService is no longer SpecService");
var specType = spec._cachedBlueprints.Keys.FirstOrDefault(q => q.Name == "ModdedWeatherSpec");
if (specType is null)
{
// No moddable weather
return [];
}
var specs = (IEnumerable)typeof(ISpecService).GetMethod(nameof(ISpecService.GetSpecs))
.MakeGenericMethod(specType)
.Invoke(specService, []);
var idProp = specType.GetProperty("Id");
return [.. specs.Cast<object>().Select(q => (string)idProp.GetValue(q))];
}
specService is an injected ISpecService
no need Harmony or DLL reference 😛
One thing I don't like here is a hardcoded name of the spec type. Any new mod that adds a new value (a new season, but not only seasons can be added), and again change the code. It will end up in a pile of hardly maintainable code with time. But as a start it looks good.
Let me think on it.
I don't see my mod change that name for any reason
if you want to you can refer to the DLL to use nameof, it's at compile time so your mod still won't actually need it, just a reference to the DLL when you compile.
I mean, you and me are not the only modders in the world, right? Tomorrow, another modder creates a new mod with extra vlues to either seasons or anything else.
well my policy has always been "not guaranteed to work with other mods" lol
So it's better to make a solution that can work going forward, and not only for your mod.
and because this mod adds something the game does not have.
It's the same here in general. But if I can to support something without breaking the main concept, why not.
but I don't understand why it breaks... if you choose not to support, and simply check the Hazardous Weather ID, my mod still has it?
it does have new string values, but why does it matter? string are meant to be "arbitrary" anyway? at least it does not crash if my mod is there and it's good enough right?
And the very next question to me will be "why is not working" 🙂 People are already ask for it. Players don't care about how it's done, they just want everything here and now. Including the custom seasons in the Automation UI constructor.
It breaks because the script engine does value checking on parsing. I'm working to add a setting to disable it, but it's a half-good solution. It will work for those who can write scripts, but it won't for those who use only the constructor (the most people).
v2.5.5 (pre-release, June 14th, 2025):
- [Feature] Allow disabling arguments and values checking in the scripts via settings.
- [Feature] Add
Debug.Tickersignal. You asked for it, you got it! Now you can useDebug.Tickersignal to get your rules executed every tick. - [Change] Improve circular execution detection.
- [Fix #103] Signals not restored on a game load.
- [Fix #104] Game crashes with ModdableWeather mod.
- [Fix #107] Signal values may not be truly global.
- [Fix #109] Add a debug option to re-evaluate scripts on a game load.
@sand thunder @reef widget @tribal canopy Folks, you are my best hope to verify if the scripting engine is in a good shape. I may agree with your opinions or don't, but I really value your input. Please, keep doing it 🙂
Just in time for me to get back to the game after a couple of weeks off.
Does Debug.Ticker return a number, or is it just always true?
I'm just curious how hard it would be to abuse it to make an automated void pump (floodgates constantly opening and closing to delete water), which would probably require running every n ticks instead of every tick.
The ticker returns a monotonically increasing int value. It's "float", though. Meaning, the very first non-zero value is 0.01.
So theoretically, I could still use modulus on it?
The value increases on every game tick
Yes, you can.
Keep in mind, the ticks are not happening when the game is paused.
And I deliberately placed it into the Debug component 😉
Hello all, is there a way to get a global storage figure for each item?
Well, I tested out the void pump idea, and found that even with an unoptimized script where every single floodgate (around 56 of them) is running separately off of Debug.Ticker (112 rules total being called every tick), there was minimal lag, even at 7x speed.
That said, outside of an oscillator like this or a function writing to logs, it shouldn't see too much use, so it should be fine.
In terms of capacity, it was capable of keeping up with a strength 40 water source.
Not directly.
What you can do is place a script on all of the storages for that item to broadcast their quantities, and have the target check the sum of all of them.
See I’m very much a noob to scripting, ChatGPT is helping lol, I have had a script for a warehouse to do the whole signal thing so if I was to have more than one storage then they all would need to generate a number to log then how would I get a script to sum up the total from the logs?
That's the easy part.
If you have 10 piles of logs, all broadcasting District_1.Logs, then the signal that the target should listen for is District_1.Logs.Sum.
Others: Min (quantity in the most empty storage), Max (quantity in the least empty storage), Count (number of storages sending this signal)
Would that work for the lumberjacks themselves if I want them to pause or resume based on global storage and their own?
In that case...
;;;;If total logs > 1000 and flag inventory is full, stop
condition:(and (gt (sig Signals.District1.Logs.Sum) 100000) (gt (sig Inventory.OutputGood.Log) 1900))
action:(act Pausable.Pause)
;;;;If total logs <= 500, resume.
;;;;This doesn't check the flag because we can assume it got emptied.
condition:(le (sig Signals.District1.Logs.Sum) 50000))
action:(act Pausable.Unpause)
Thanks I’ll try it another time as game just crashed, it was raining and I’m assuming it was a weather change that triggered it.
I had a few crashes with 2.5.3 and moddable weather. Is there anything new in 2.5.5?
There are a lot. Check the change log above.
A lot related to moddable weather? I meant if there is any change in regard to moddable weather between 2.5.3 and 2.5.5
Did you read the change log? Why do you think it mentions fix #104? 
I've read it. But 2.5.3 was supposed to also have that fix. So I want to make sure 🙂
v2.5.6 (June 16th, 2025):
- [Feature] Allow disabling arguments and values checking in the scripts via settings.
- [Feature] Add
Debug.Tickersignal. You asked for it, you got it! Now you can useDebug.Tickersignal to get your rules executed every tick. - [Feature] Load weather seasons from the game blueprints. This allows the modded seasons to work, given the mod that introduces them follows the specs naming convention.
- [Change] Improve circular execution detection.
- [Fix #103] Signals not restored on a game load.
- [Fix #104] Game crashes with ModdableWeather mod.
- [Fix #107] Signal values may not be truly global.
- [Fix #109] Add a debug option to re-evaluate scripts on a game load.
Now, released.
@floral thicket In order for the modded seasons to work, their specs should end with WeatherSpec, and have fields Id and NameLocKey. As far as I can tell, with the current version it works fine.
@south wedge Crash; seems to be this mod.
v0.7.10.0-5279ef7-xsw
Exception: ISpecService is no longer SpecService
IgorZ.Automation.ScriptingEngine.ScriptableComponents.WeatherScriptableComponent.LoadWeatherIds () (at <0f348ad9b7bc4b01b928a75bd49c1b20>:0)
IgorZ.Automation.ScriptingEngine.ScriptableComponents.WeatherScriptableComponent.PostLoad () (at <0f348ad9b7bc4b01b928a75bd49c1b20>:0)
Mods.MoreModLogs.SingletonSystemPatch.ErrorReporter (System.Action fn) (at /home/normanr/src/Timberborn-MoreModLogs/SingletonSystemPatch.cs:53)
(wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.Timberborn.SingletonSystem.SingletonLifecycleService.PostLoadSingletons_Patch0(Timberborn.SingletonSystem.SingletonLifecycleService)
(wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.Timberborn.SingletonSystem.SingletonLifecycleService.LoadAll_Patch1(Timberborn.SingletonSystem.SingletonLifecycleService)
Timberborn.SingletonSystem.SingletonLifecycleUnityAdapter.Start () (at <3bb50da0b9a949568631f734dea04cec>:0)
The exception occured while trying to load into a save from yesterday. Version 2.5.6
Reverting to Version 2.5.5 works fine.
Hmm. Could you please share the save file?
One minute.
Ah, wait. The error is about the service.
It seems, the last game update broke it.
I wonder if it fails in stable branch.
Crashes On load with Automation v2.5.6
Loads fine with Automation v2.5.5 (Prerelease)
Same crash on u7 stable
Also fyi, weather mods can also add new temperate seasons (Moddable Weather already does) - so just put out a disclaimer about those not being recognized in this mod as anything other than plain Temperate if you don't want to implement somehow detecting those.
wow, did they change the SpecService?
oops... I think one of my mod did change ISpecService to something else 
ModdableBindito I think
my new implementation should have just inherited the original SpecService.
if you use Moddable Bindito, please update that mod and it should work with this mod now
2.5.6 takes all specs that exist. Regardless to if they declare hazardous or temperate season.
But if i recall correctly the season signal only gets set to either 'temperate' or the harzdous weather's id... and it would take more hassle/work to check for separate Mod-Added temperate weathers (Moddable Weather's Rain weather for example). Oh well...
It's changed now. Weather signal returns season ID now.
temperate stays to be a synonym to the "standard temeprate", but nothing stops from mamking more "temperates".
Hi all, can anyone here help me with a new error I'm getting please?
Wow! I can't even imagine how you could get this error. Could you please share the save file?
Yeah sure can do.
Btw I just switched off all my automations and it's working fine (the mode is still enabled) I had just a few on:
- water dumps <-> water alerts
- warehouse <-> tapper's shack
- large tank <-> Coffee brewer
This should be it. I just checked again, without changing anything I let it play for a bit it should error on the next game day at some point.
@south wedge just fiy that update to "moddable bindito" theapologist316 just made yesterday ended up breaking timberapi instead... so that will take a lil while longer
but it should work for Automation now right?
I see people reporting this issue, but I cannot reproduce it. Was it fixed already in the newest version?
This is reproduced. Thanks. Working on a fix.
it should, though it breaks TimberApi now instead lol
I have 7.1.1, and Steam says it was updated last time on June 13th. The error should be happening to me long time ago, but I never seen it.
People reported the crash today, after 2.5.6 released. Something is not right here.
latest should be 7.1.2
on both Steam and Mod.io
Ah, its not the mod itself, but another one. Now it makes sense.
v2.5.7 (June 17th, 2025):
- [Change] Don't crash if the modded seasons can't be loaded. Ignore the specs and use the standard seasons instead.
- [Fix] Fix a crash during a game load under some circumstances.
Please, don't use don't crash, or eMka will push another update 🤣
This time, it was'n him 🙂
It's a good thing that I loaded into my save pointing directly at a building with a broken script...
I had to update all of the seasons to the new spec, and I use a lot of season-based automation.
Yeah Same here 🙂
Given the specs are not broken, the conversion from the old seasons names to the new seasons IDs should be seamless. What issues did you have?
E.g. temperate should get converted to TemperateWeather automatically, without errors.
It skipped that step. I had to manually change all of them.
Fortunately the error message told me what they needed to be.
Hmm. The values are changed on parsing, how could you skip it? 
Or did you have rules for the modded seasons, and the modded seasons didn't load?
No modded seasons.
As for parsing, it just threw parse errors.
Could you please share the error message?
The exact same thing happened to me, easy fix but was not automatic
It's not how it is supposed to work 
Could you pls share this save file? On my save files it works just fine 🙂
I will once this thunderstorm (real life weather, not in-game) ends.
Be aware that you need greedy embers to load it.
@south wedge Here you go.
I just mistook the "no-power" icon for the "broken script" icon.
@south wedge by the way how do i override/add templates (in a separate local mod of course)? are there any rules for writing one up?
The parser throws an uncaught exception if you try to save a rule that compares a string to a number.
Uncaught exception on dividing by zero with this rule:
(ge (div (sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Quantity.Sum) (add(sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Capacity.Sum) 1)) 95)
I got around it for now with
(add(sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Capacity.Sum) 1)
which ensures a minimum value of 1.
Also, Is there a way I could grab the name of the district? That would let me make the signal names completely procedurally.
There are no specific rules for making the templates. But keep in mind that they are applied via UI, and can be attempted to be applied to an incompatible building. For this, there is "precondtion" expression. Checkout how it's made for the standard templates. This expression should evaluate to "true" in order to allow the scripts be applied. Other than that, it's all about the tools specification semantics: unique tool IDs, the right classes and order indexes.
Thanks, I'll check. The recent changes to the signals handling could break the exception handling. It turned out to be a really tricky thing.
If a building has multiple recipes, is there any way to grab which output is "active"?
Take a gristmill, for example. It can make Wheat flour or Cattail flour, but only one at a time.
This one required some tricky logic. So far no support, but it's in the plan
I still didn;t decide on the output signals if they should or should not invalidate in case of the inventory output change. E.g. the stockpile good switch. Thoughts?
Maybe only consider the allower (or recipe selected) in constructor, but don't verify in parsing? 
Most of the use-cases would be in template-style scripts anyway; I would consider it fine if it was only allowed it in preprocessor.
So basically "it must be valid when the rule is saved, and it is up to you to make sure the rule is valid later."
The only additional time I would probably consider checking recipe output vs. good listed in rules would be when loading a save file.
Two outputs from one recipe is also rare enough to just say "not allowed" on; the only faction I know of with recipes like that by default is Whitepaws.
v2.5.8 (June 18th, 2025):
- [Fix] Properly convert the legacy seasons names into the season IDs.
- [Fix] Add a missing localization string for the settings dialog.
Snap, I forgot about the div by zero issue 
I never even thought of this! But yes, this info can be obtained. However, you cannot use district name "as-is" for the signal names (there are syntax constraints). How do you see the usage?
Maybe something like "this district ID", in which case it can be just a hash string.
(keep in mind this game is multilingual).
A good thing about hashes, it can be a constant. It won't change if you rename the district. A bad thing: it won't be human readable.
This was the best I could reproduce: https://github.com/ihsoft/TimberbornMods/issues/113
I'd prefer readable…
Maybe try parsing the name skipping spaces, and if it fails, then fall back to a hash?
Alternatively, when a district is built, store the hash in an array of all districts, and use Dist<array pos+1>. So Dist1, Dist2, etc. The list can be cleaned at the same time to prevent excessive growth from moving district centers.
Errors:
For floodgates, stream gauges, etc., that can't connect, "This structure cannot be connected to a district."
For any building that can connect but isn't, something allong the lines of "Please connect this to a district first"
Of course, a district center would never throw this.
Loving this mod. I'm trying to automate a phoenix protocol right now. Is there a way to get the progress of a breeding pod as a trigger? I want to setup an automation to pause a group of pods and some other buildings when the pod progress hits 99%.
What property would I use to get the maximum number of workers a building can have?
Ah... {%(getnum Workplace.MaxWorkers)%}
Huh... It finished but didn't explode.
Seems to have been a one-time thing; the next one worked just fine.
Dynamite won't explode if there are beavers or bots nearby. 3x3 area is checked. It includes the kittens too.
But wait till they leave, and the explosion should happen.
It's not supported as a signal, but you can use a mix of debug and advanced stuff:
(and (ge (sig Debug.Ticker) 0) (eq (getnum BreedingPod.CyclesUntilFullyGrown) 1))
But keep in mind, the condition will be executing every tick. It can affect performance. However, @reef widget did some tests and said the effect is not significant. Anyway, the ticker is a debug tool. So use it with care.
This is getting a bit ridiculous...
;;;;Monitor Input/Output by percent. Broadcast a stop signal when below 20% input or above 95% output.
condition:(or (ge (div (sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Quantity.Sum) (add(sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Capacity.Sum) 1)) 95) (le (div (sig Signals.District1.{%(getstr Inventory.InputGoods 0)%}.Quantity.Sum) (add(sig Signals.District1.{%(getstr Inventory.InputGoods 0)%}.Capacity.Sum) 1)) 20))
action:(act Signals.Set 'District1.{%(getstr Inventory.OutputGoods 0)%}.Make' 0)
;;;;Monitor Input/Output by percent. Broadcast a start signal when above 40% input or below 50% output.
condition:(and (le (div (sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Quantity.Sum) (add(sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Capacity.Sum) 1)) 50) (ge (div (sig Signals.District1.{%(getstr Inventory.InputGoods 0)%}.Quantity.Sum) (add(sig Signals.District1.{%(getstr Inventory.InputGoods 0)%}.Capacity.Sum) 1)) 40))
action:(act Signals.Set 'District1.{%(getstr Inventory.OutputGoods 0)%}.Make' 1)
;;;;Stop on stop signal.
condition:(eq (sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Make) 0)
action:(act Workplace.RemoveWorkers)
;;;;Start on start Signal
condition:(eq (sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Make) 1)
action:(act Workplace.SetWorkers {%(getnum Workplace.MaxWorkers)%})
You can make it a bit more readable by using multiple rules instead of "or" condition. But i's a huge setup anyway 🙂
The first 2 rules only go on the first factory of a type; the last two act as repeaters for the first two rules.
Basically:
IF OUTPUT quantity/capacity > 0.95 OR INPUT quantity/capacity < 0.20 THEN stop
IF OUTPUT quantity/capacity < 0.50 AND INPUT quantity/capacity > 0.40 THEN start
And half of the space is preprocessor stuff to make it fit nearly any building with 1 input and 1 output.
I was thinking about adding a "hysteresis" operator, but decided to skip it since it won't be used much. It seems I was wrong.
https://github.com/ihsoft/TimberbornMods/issues/114 - feel free to throw in your ideas.
Folks, this example (on the image) I was considering from the start. One day, there will be a building with too many rules. Any ideas to make the view shorter, yet informative?
I was considering two approaches (they are not mutual exclusive):
- Only show a list of signals, the building is reacting to.
- Create "a visual" view where text is replaced with icons. I like this approach a lot, but it's not scalable 😦
Any more ideas? Checkout the UI in the attached image. How we can make it shorter?
Is there a tutorial somewhere on how to use the mod more in depth?
Yes. We call it Wiki: https://github.com/ihsoft/TimberbornMods/wiki/Automation-(scripting)
And there is a button in the game, that brings you there 
Is there a way to disable scripts on a single building without deleting them?
Not directly, but you could make a small edit to include an impossible condition.
sounds about like what I have been doing then. Was hopping for an easier toggle to override my rules on some buildings when I want to on a temp basis. tnx for the quick answer.
The other thing you could do is press export, copy the rules you want to suspend to a file, and then delete them.
You could then restore them later with import.
yeah, was thinking just copy them to another building then copy it back when i am done with my need to override.
It sais you updated it 7 hours ago but you did not update "This document was last updated for version 2.2.0 on 5/20/2025." 🙂
That's a bummer it's not supported as a signal. Thanks for the script though! I'll try it out
Good point! Thanks.
How about a checkbox next to each script to select whether or not to show it in the building UI? I'd imagine there would be few you'd care to see in this view in the building UI, and to view the full list you'd open the edit window?
FYI: I've observed a crash on v2.5.8: https://github.com/ihsoft/TimberbornMods/issues/115
What is this actually doing,
I’m trying my hardest with scripts and at the moment just use warehouse and piles to generate storage signals which is working so far.
Check two messages down from that.
It is missing storage signal though…
Let's start here:
;;;;Broadcast capacity
condition: (eq (sig Constructable.OnUnfinished.State) 'finished')
action: (act Signals.Set 'District1.{%(getstr SingleGoodAllower.AllowedGood)%}.Capacity' {%(getnum Inventory.Capacity)%})
;;;;Broadcast quantity
condition:(eq (sig Inventory.OutputGood.{%(getstr SingleGoodAllower.AllowedGood)%}) (sig Inventory.OutputGood.{%(getstr SingleGoodAllower.AllowedGood)%}))
action:(act Signals.Set 'District1.{%(getstr SingleGoodAllower.AllowedGood)%}.Quantity' (sig Inventory.OutputGood.{%(getstr SingleGoodAllower.AllowedGood)%}))
The first rule causes a storage to send a signal stating how much it can hold, just once. (This will make more sense later).
The second rule has it broadcast its current stored quantity any time it changes.
;;;;The name of the good this storage accepts
{%(getstr SingleGoodAllower.AllowedGood)%}
;;;;The capacity of this warehouse
{%(getnum Inventory.Capacity)%}
These make it so that the script adapts based on the target warehouse; replace them and it becomes a lot more readable:
;;;;storing logs; capacity 180
condition: (eq (sig Constructable.OnUnfinished.State) 'finished')
action: (act Signals.Set 'District1.Log.Capacity' 180)
condition:(eq (sig Inventory.OutputGood.Log) (sig Inventory.OutputGood.Log))
action:(act Signals.Set 'District1.Log.Quantity' (sig Inventory.OutputGood.Log))
Next:
;;;;Monitor Input/Output by percent. Broadcast a stop signal when below 20% input or above 95% output.
condition:(or (ge (div (sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Quantity.Sum) (add(sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Capacity.Sum) 1)) 95) (le (div (sig Signals.District1.{%(getstr Inventory.InputGoods 0)%}.Quantity.Sum) (add(sig Signals.District1.{%(getstr Inventory.InputGoods 0)%}.Capacity.Sum) 1)) 20))
action:(act Signals.Set 'District1.{%(getstr Inventory.OutputGoods 0)%}.Make' 0)
For a factory is a single input and output item:
;;;; input item name
{%(getstr Inventory.InputGoods 0)%}
;;;; output item name
{%(getstr Inventory.OutputGoods 0)%}
If we use this on a lumber mill (input: Log, output: Plank):
;;;;Monitor Input/Output by percent. Broadcast a stop signal when below 20% input or above 95% output.
condition:(or (ge (div (sig Signals.District1.Plank.Quantity.Sum) (add(sig Signals.District1.Plank.Capacity.Sum) 1)) 95) (le (div (sig Signals.District1.Log.Quantity.Sum) (add(sig Signals.District1.Log.Capacity.Sum) 1)) 20))
action:(act Signals.Set 'District1.Plank.Make' 0)
Still complicated.
;;;; read in quantity and capacity from storage; is (Quantity / (Capacity + 0.01)) >= 95%?
;;;; .Sum combines the output of everything sending that signal, making it work with multiple storages
(ge (div (sig Signals.District1.Plank.Quantity.Sum) (add(sig Signals.District1.Plank.Capacity.Sum) 1)) 95)
The seemingly random +0.01 is actually to prevent the denominator ever being zero; dividing by zero would be bad.
The action is to broadcast a signal:
action:(act Signals.Set 'District1.Plank.Make' 0)
action:(act Signals.Set 'District1.Plank.Make' 1)
All this Percent Quantity stuff is heavy, so it only runs on one factory.
These last two signals go to all factories producing that good, essentially allowing multiple factories to listen to the two massive control rules.
;;;;Stop on stop signal.
condition:(eq (sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Make) 0)
action:(act Workplace.RemoveWorkers)
;;;;Start on start Signal
condition:(eq (sig Signals.District1.{%(getstr Inventory.OutputGoods 0)%}.Make) 1)
action:(act Workplace.SetWorkers {%(getnum Workplace.MaxWorkers)%})
One last automatic value:
{%(getnum Workplace.MaxWorkers)%}
Hopefully that one is obvious.
@south wedge is there any chance you'll add setting sluices back to Auto-mode as an automation action ... or make the scriptableComponent pass along contamination & downstream depth (and their set limits) as signals ?
The signals can be added. This will eliminate the need to set "auto" mode, right? Sluices implement open/close interface in the scripting engine. "Auto" doesn't fit the concept.
How would I set a precondition for an action NOT being available?
Specifically, I want a rule to be applied only for a building that can be paused, but does not have workers.
Hmm. let me think. To verify if teh buildign can be paused, check the action (?act Pausable.Pause). For the workers: do you need to verify if the building is not assumed to have workers or do you need to check the currently assigned number?
Specifically, I want to know if it has no worker slots at all.
I tried (eq (getnum Workplace.MaxWorkers) 0), but that fails for all buildings (presumably because Workplace doesn't exist if it is 0, and all the others are greater than 0)
Yeah, when the building doesn't have workers it doesn't have "Workplace" component.
You can check for (?act Workplace.ResetWorkers)
But how to negate it?
What I want: (and (?act Pausable.Pause) (not (?act Workplace.ResetWorkers)))
But I can't find anything equivalent to not, a boolean inversion.
you're missing a negation operator anyhow (keyword 'not') ... and comparisons have to have at least one signal within
"Not" is not implemented, but one day I will add it. Preconditions don't need signals in the condition.
Precondition; doesn't need a signal.
It's just saying "is this rule even allowed? Can this object actually use it?"
Yes, precondition is executed as a check logic when attempting to apply the script.
Technically, precondition can even fail with an error. It won;t be shown in UI, but will be logged.
v2.6.0 (June 22nd, 2025):
- [Change] Make input field in script editor multi-line.
- [Change] Better handling the script errors in both UI and the execution phases.
- [Change #106] Allow choosing if the values should be evaluated or "described" in the UI. Check the settings dialog.
- [Fix #115] InvalidOperationException: Condition already activated.
Would it be possible to have the constructor be able to incorporate and, or functions? I know it can kind of do it if you only have one function but if you have multiple nested scripts constructor can’t handle it.
What I do is use the constructor to make multiple rules, then save them and edit them as scripts.
That lets you copy them to a single rule where you can wrap and and or around them.
You know I actually did that shortly after asking that question lol but yeah good idea.
I was thinking though could a function dropdown box be added? Would have made scripting easier for me from beginning but I have learnt loads, similar to dropdown box for selecting the equals or less than you know
@south wedge any way to turn on a building at a specific time of day? i'm specifically looking to only run extra number crunchers when everything else turns off
Can not add a global trigger that count up if enabled and if less then x amount start the number cruncher and if more that x stop it
This one is in the list of the possible features, but for now is not on the road map. It sounds, like you try to optimize the energy usage. Did you try SmartPower?
I'll give that a try. Thanks for the interesting mod, I'm trying to see what I can achieve with it
Also take a look at https://steamcommunity.com/sharedfiles/filedetails/?id=3469209119.
The way I use it is by setting Lunch Start to 0h and Lunch End to when I want work to actually start. Then Shift Hours to when I want work to end. If you're trying to share Beavers between buildings, I'm not sure Configurable Workplace or Smart Power will serve your needs.
Folks, if you see too much spam in the games logs from Automation, please let me know. Sometimes, I forget to remove the debug logging which is not meant to get into the mod. Just now I found a debug log for the ticks (debug.ticker).
Oh, my, that could certainly flood the log pretty quickly, given that it runs every tick.
Luckily, it only runs if you use Debug.Tickable.
Quick vote before I post a pre-release of Debug.DistrictStockTracker.<good id>. Should it:
- Only return what's in the stockpiles (i.e. what can be brought in and taken out).
- Return #1 + what's in the output inventories of manufactures.
?
Option #2 is made. Usage:
(ge (sig Debug.DistrictStockTracker.AlgaeRation) 0)
(ge (sig Debug.DistrictStockTracker.AlgaeRation.Capacity) 0)
This is a ticker. The condition triggers once every tick regardless to if the value changed or not. The solution is non-optimal: the values are calculated each tick on all districts. I would assume it will impact performance on the big districts. Good for debugging, but not for the real game automation. So far, I haven't found a way to calculate it without iterating all goods in all inventories every tick.
Not sure this is the right place for this, but I noticed there was a command already included that detonates dynamite and automatically places another in the same spot, could this be used to place a different object in the same place?
I tried building tubeway tunnels and it was very tedious waiting for the tunnel to explode then manually placing the next tube tile by tile, could this potentially be automated by this mod where the next piece of tubeway is placed after the tunnel is exploded?
That command is exclusive to dynamite.
For you use case, look for the "More tunnels" mod.
-# Or... maybe just avoid trying to build the tunnel directly from a tubeway.
Is there any signal that tells the number of any item in the whole district?
lets say all the logs available in the district. Not just in one storage pile.
@south wedge
Not directly: it requires a little bit of work.
You need to add a custom rule to every single storage pile with that item to broadcast its quantity as a signal. THE SIGNALS MUST ALL HAVE THE SAME NAME. (I recommend using the copy tool)
Then, when you want to check the total quantity, you just call the signal name and add .Sum at the end.
Yeah using that only. Thanks. 🙂
@south wedge There is one bug If I use the copy tool and there are multiple storage stacked. It copies the rule to all storage above the selected storage.
There is no "good way" for now. One is creating custom signals on the stockpiles you're interested in. Another way, is in the pre-release (v2.6.1, see above). It's not performance effective, but you may give a try.
In general, not always you need to focus on the exact amount of something in the district. Create a stockpile in mode "obtain", and check the fill rate. If the rate is low, then obviosly you need to start more production. If the stockpile is close to 90%, you likely have enough and can stop production. This way you create one custom signal per good, and not all of them you need to automate anyway.
That's the game feature. I use standard selection tool. It can select buildings "up" or "down", but it cannot select exactly one building in the stack 
Oh, right, I made this.
Custom syntax highlighting for automation scripts in Notepad++.
If you use the file extension .tlsp it should auto-detect it.
Okay got it. Thanks for clarifying.
Impressive!
How exactly to install it into npp? Maybe I'm dumb, but just making a file and copying it into languages folder didn't do the trick.
Menu: Language -> User Defined Language -> Define your language...
In the window that pops up, select Import, then navigate to the file and open it.
If you want to change any colors, find the matching item in that same dialog and click the button labeled "styler" near it.
Near the bottom; they don't go in the letter tabs.
Hey guys. I'm diving into the Automating mod and I'm looking to get some information out of the storage buildings. Does anyone know how to get the value for max capacity out of the buildings? I believe I can use an Access operator to get it, but I'm struggling to find the ComponentName and the PropertyName for each building. Maybe there is an easy way to get the max value from any building with the same line of code?
You want how much can fit, not how much is currently stored?
{%(getnum Inventory.Capacity)%}
Full rule set (compatible with all piles, warehouses, and tanks)
;;;;Broadcast capacity
template:Piisfun.LogisticsBroadcast
precondition:(ne (getnum SingleGoodAllower.HasAllowedGood) 0)
condition:(eq (sig Constructable.OnUnfinished.State) 'finished')
action:(act Signals.Set 'District1.{%(getstr SingleGoodAllower.AllowedGood)%}.Capacity' {%(getnum Inventory.Capacity)%})
;;;;Broadcast quantity
template:Piisfun.LogisticsBroadcast
precondition:(ne (getnum SingleGoodAllower.HasAllowedGood) 0)
condition:(eq (sig Inventory.OutputGood.{%(getstr SingleGoodAllower.AllowedGood)%}) (sig Inventory.OutputGood.{%(getstr SingleGoodAllower.AllowedGood)%}))
action:(act Signals.Set 'District1.{%(getstr SingleGoodAllower.AllowedGood)%}.Quantity' (sig Inventory.OutputGood.{%(getstr SingleGoodAllower.AllowedGood)%}))
Well, so far...
- Storage: Priority Supply
- Storage: Priority Obtain
- Storage: Broadcast Quantity/Capacity*
- Factory: Workplace control based on Input quantity*
- Factory: Workplace control based on Output quantity*
- Factory: Workplace control based on both Input and Output quantity*
- Factory: Repeat to all other factories*
- Generator/Amenity: Priority restock*
- Generator/Amenity: Low stock shutdown*
- Floodgates: Various combinations
-# *Procedural signal naming
Any other obvious ones?
Hmm. You want them as signals or as the properties? It's a very big difference. In both coding efforts and performance impact sense. I fully understand that every user wants "everting here and now", but the reality is rude. You can't get it with no price.
Those aren't signals or properties.
Those are rule sets that I've made; I'm wondering if there's any other obvious ones that anyone can think of that should be added to my general set.
As it is, 90% of my automation scripts now are importing one of those rule sets.
to bad you can not set Recipe with automation 
+1
It's in the features. Hopefully, i will have time before the long vacation.
If you are using scripts, and not the constructor.
Automation uses fixed-point decimal values, where 1 is read as 0.01.
Therefore, if you want 5 logs, you would need 500 (5.00), but if you are trying to set a floodgate to 1.75, then 175.
As for the constructor, it just expects decimal points.
It's not always divided by 100, though
got an example where its not 100 and your not using constructor?
The one major thing is zero, because 0 equals 000.
I'll grab a screenshot in the morning, right now I'm meant to be sleeping
Rather than a screenshot, just export the rules and wrap them in triple backticks (`) when posting them to Discord.
Easier to analyze.
or both 😛
but I was literally copying the exact same subexpression and it would work in certain cases and not in others
I should figure out where the log files end up on linux
well if we have a specific case where it happen and a screenshot to show it should go along way to track down
Proton creates a subfolder that acts as a Windows file system; It'll be deep in that, in the folder that acts as Appdata/LocalLow/Mechanistry.
Somewhere like ~/.local/share/Steam/steamapps/compatdata/1062090/pfx/drive_c/Users/steamuser
Why is the top level hidden...
on a bot assembler:
condition:(gt (sig District.Bots) (sig Signals.BotTgt))
action:(act Pausable.Pause)
condition:(lt (sig District.Bots) (sub (sig Signals.BotTgt) 5))
action:(act Pausable.Unpause)
which renders, and seems to behave, as shown (5, not 0.05)
on an advanced breeding pod:
condition:(gt (sig District.Beavers) (sub (sig District.NumberOfBeds) 1))
action:(act Pausable.Pause)
condition:(lt (sig District.Beavers) (sub (sig District.NumberOfBeds) 10))
action:(act Pausable.Unpause)
I have to remove the smart power mod because it's impossible to click the edit button on certain buildings because it flows off the bottom of the screen, hopefully that doesn't break anything
on a gear workshop:
condition:(lt (sig Signals.Stockpile.Gear) (div (sig Signals.Stockpile.GearCap) 4))
action:(act Pausable.Unpause)
so it seems like maybe it's only in conditions, as it works as expected in all the actions I've tried
but even in conditions it only affects operands to math operators
maybe I should also ping @reef widget
unrelatedly, any chance that this template, or at least parts of it, could be integrated into the mod? the storage template in the game just assigns a "Stockpile.Yellow1" signal to things which is only useful as an example if at all
I think TImprove UI has an option to add scrollbars to help with this.
You can edit Stockpile.yellow1 to any proper name. For logs stockpile.log
And check that signal in any building.
It was intended as an example.
The attached file is just a text document with rules I frequently import.
They work on... most buildings. In particular, the automation rules for workplaces only automatically select the correct resource if the building has exactly 1 input and 1 output.
Yes, but it's possible to use a template to get an actually useful name fully automatically, with no editing required, and it's a lot of clicks to go in and edit these rules in multiple places each to change the signals
Umm. For now you can edit once save it in text file and import everytime you start a new game .
I follow that only. Once you play through a game you will find all the automation rule you need.
Export and import.
You can import templates? Or do you mean importing on the building?
oh I just installed the dedicated mod for it, I didn't consider it might be an off-by-default option in a mod I already had
Import on the buildings.
For storage you have signals. And for buildings you use those signals to automate.
Not quite fully automatically; there is still several things that are needed.
Some examples:
- Districts. If there is more than one, you often need different signal names.
- Anything related to water control. There simply isn't a reasonable value to use for automatic names here.
I don't understand what you mean then
Sure, but the flood gauge template already uses names with 1 on the end (although it could use more readable names instead of colors) and I was only talking about specifically the storage building template
@timber portal You can go through the file. It's pretty simple. I don't have any complicated stuff setup.
For that you can see @reef widget shared file.
You can't add templates to the bottom bar without some complicated JSON stuff. This unavoidable; TimberAPI manages this, not Automation.
What you can do is use the "import" and "export" options on the rule management panel to import custom template rules.
Then it is just copying and pasting to a text document.
Then what does "no import on the buildings" mean?
That's exactly what I asked if I was supposed to do and got told no
Forgot to use punctuations. 😂 Sorry for that.
If you start the first two lines with # or ;;;;, they will be treated as comments by the mod, making imports a bit easier.
Okay thanks for the hint will use that.
Do you need that many ;s?
Yes. That comment type is actually a LISP standard, which is what the automation scripting language is based on.
huh, I've never seen a language with a 4 character comment introducer
I mean unless you count rem in windows shell scripts but that's not technically even a comment, it's just a line with no actual effect
Ah yes, Command prompt and its executable comments.
Anyway, did you look into why some of my rules weren't dividing literals by 100?
I can't, that's something for @south wedge to look at when he has time.
Link: #1190169064383991858 message
alright, I wasn't sure who was a dev on the mod or just someone who knows it well
As for not dividing by 100. If this actually happens in execution, it's a bug. Based on the screenshot, the "describe" logic shows the script value (integer). This could be a bad choice after all. Try enabling "evaluate arguments value" setting in the mod. This way you will get the actual value used in the processing.