#TimberAPI
1 messages ยท Page 6 of 1
Congrats! A very good number ๐
I like binary round numbers, tho 
Does the building spec "RecipeIds" not support #append?
Nope. Hope will be soon un the base game.
darn, was trying to use it for my botkit mod that I'm trying to make, would've also switched my bentos mod to it
Should just work 
At least I don't know why it wouldn't
Well I tried it, couldn't see my recipes in the list unless I simply missed it
Was working at the first versions of TAPI ... ๐ญ
Does a full replace with only yours do work? otherwise either the specification is wrong, you don't have TimberApi not installed or I did something wrong
https://github.com/Timberborn-Modding-Central/TimberAPI/blob/main/Src/BuildingSpecificationSystem/BuildingSpecification.cs
I didn't have a docs for it in the old docs 
I just realised, I haven't check if my copy is up to date, lemmie check that
It has been in there for quite a few updates though
If you make a empty BuildingSpecification.Tester.json file in your specification folder it should crash
apparantly I need to update the mod manager too
tried updating, had tapi load after modmanager and had a crash. Found this: drive_c/users/steamuser/Temp/Mechanistry/Timberborn/. Was an unusual crash though as some progress dialog appeared before it quit
was manual update btw, removed the one mad manager had made
This seems a bit more verbose then usual so maybe it's of help?
was in the folder I just mentioned btw with a crash dump
the archive is the folder zipped
No idea where the error even is, do you have by any chance my quick start mod ?
well disabling the TBMPL stuff did get past the crash so you were probably right about it being his, just assumed it was tapi as that was all I touched. Maybe I need to update the TBMPL core too ๐
but updating tapi didn't resolve the inactive building spec situation ๐ฆ
How are you trying to do it ?
There are optional, do you have a base specification it can depend on ?
Uh, That's the name in of the vanilla buildings
, this doesn't match with the question I asked
m_Name: Refinery.Folktails
There -> these*
BuildingSpecification.Refinery.Folktails.optional.json
Finally, if the file name ends with .optional.json for example NeedSpecification.Beaver.Sport.optional.json, it modifies an existing Specification only if it is already present in the base game or a different mod but is otherwise ignored. This allows you to support compatibility with other mods as well as older versions of the game.
Isn't that supposed to be used when updating an existing object?
hmm, guess I'll try without the .option then
Wait do I generate them as well
I can't test this now but I use the name from
var buildings = prefabService.GetAll<Building>();
So if you log all building names from that it should have the one you want
If it doesn't it won't work
Maybe the name doesn't use . as seperation
nope, tapi or tb or both didn't like that
Ye because it isn't a full spec, you were right about using the .optional
But the logic behind it was just wrong ๐ so I was confused
It's not beacuse am existing object, but an existing specification. Unless you meant purely the specification with object and not building my bad.
did clue me in to what the issue might've been though, complained of missing "BuildingId"
You could just remove the Id in it's whole
Since it's optional it doesn't matter
But if the specification name doesn't mater that might be a problem, which I think where it goes wrong
That's a native crash, i.e. .Net did something really bad. I've only ever seen it before when trying to talk to the Steam API when it's not available.
Another way to say it is that it crashed in c++ code instead of c# code (which 95% of the game is written in)
@primal wind Looks like it's broke as far I can see now
Not sure when it bee fixed hopeefully this week
I don't even understand why it crashed, the top of the stack is roughly:
Timberborn.Modding.ModLoader:TryLoadManifest (Timberborn.Modding.ModDirectory,Timberborn.Modding.ModManifest&)
Timberborn.Modding.ModLoader:TryLoadMod (Timberborn.Modding.ModDirectory,Timberborn.Modding.Mod&)
Timberborn.Modding.ModRepository/<GetMods>d__16:MoveNext ()
which is managed code, so why a native crash?
unless the call to GetModDirectories was super lazy, and only runs when TryLoadManifest actually tries to reference Path the first time,
and the it could totally be a native crash, becuse that calls into the steam api which was not working,
but IsModDirectory should already have run on the path, so would have crashed earlier,
Iss that becuase of TimberAPi ?
Since I don't do much with the loading mods
There are so many mods loaded in that log that I have no idea what could have caused it,
or that it's more likely to have been caused by a bad interaction between two mods, and not an individual mod itself.
i.e. I doubt it's TimberAPI's fault,
and would like to see a smaller reproduction (i.e. same crash with fewer mods active)
Because log shows only "Managed Stacktrace:". First time TryLoadManifest was called before any mod was loaded/started and crashed trying to reload manifests after mods were enabled/started. I guess one of the mods tries to load another and messes up manifest path (or path is ok but the game doesn't have access to it).
well disabling the TBMPL stuff did get past the crash
I'd try to delete TBMPL folders and redownload through mod manager. If no success - try to reenable them one by one
Could be the new experimental update that changes some paths
Mod io Mod manager also broke
True but TB loads mods in order and TAPI was 3rd in the order, just after harmony and mod manager so I don't see a reason for other mods to have had a chance to do something besides when tapi is loading one. On a related note it would be very much appreciated if you could add an info/debug log message about which mod and/or mod file tapi is trying/addressing/whatever way you wanna put it before it actually tries them. If you could also add in info/debug logs about which parameters/functions are being attempted that would also help. Could build it as a separate mod called tapidbg due to how much extra time that would take and thus only be desirable for short term use instead of main tapi
I am making a logger which going to log like that. But this doesnt work for crashes as it never did, even with bepinex crashes would fall under a unity tag. It will only work when a codee mod uses it.
If I would have info about a mod while something goes wrong ill going to log it with its tag. But this info is with many thing lost.
hmm, well if you manage to do something about that issue then please ping me again about it. For now I'm going to assume it was partially tapi's fault but not entirely, meaning tapi made an assumption somewhere it shouldn't but it would never have been an issue if another mod didn't highlight that assumption with it's own poor code
It isnt tapi's fault... Just because you assume it is
I dont even do anything with Loading anymore
It always can be a fault but without knowing what mods toghether causees it out of 30 mods, who knows
and you can test if it's a steam issue by adding -feature-NoSteam to the game's launch options.
which should stop the Couldn't connect to the Steam client. Is it running and do you have the game in your library? appearing in the player log
Let me know if you ever see Successfully connected to the Steam client. under Linux, btw -- I just can't get it to work.
any easy way of getting a line of text from the user in game?
something like the district renaming dialog?
or name change dialog,
Judt like the UI ?
yea, Timberborn.CoreUI.InputBoxShower will probably do
need to figure out how to make a new hotkey too, KeyBindingSpecification probably,
No idea what that is 
Otherwise just pop a stackpanel and you can easily make that dialog layout with the boxbuilder + input presets
yea, that might be a follow up option too
Don't know 100% but something likee this would just be a box with a single input
uiBuilder.Create<BoxBuilder>()
.AddCloseButton("close-button")
.AddComponent<DefaultTextField>("my-text-field");
And you could almost copy the InputBoxShower code for making it pop up, it just pushes a visual element to the panelstack
yeah it will add the key/option to Key bindings menu and to input/keybiding manager so you can check it by name. And keybindingsUI or something like that will be your friend if you wanna do something different
yea, I figured out how to add a spec too
this box is my favorite
Does all the "ask for input, check for conflicts" etc. Is easy to use and doesn't mind being called outside of kb menu
What do you mean with easy to use? as a user or a modder e/
both. It is perfect
Most UI elements I touched were a bit tricky to reuse or adapt. This one is an exception
Have you tried TimberApi presets
?
I think I resud the name dialog for TimberPrint before, when I hadn't updated TimberApi
Also I've read TimberApi repo and was very confused by stylebuilder
As I tried to do similar thing but UnityUI stylebuilder is protected/internal or w/e not available. I couldn't figure out how tf did you get it 
By making it not internal :), the internals of the StyleBuilder is complex yea. But also isn't for the users ๐ unity's stylesheet builder is pretty weird it took me some time to figure everything out, and I still haven't for all selectors
This is how you would done that part in the unity stylesheet builder
This was mine, now you can just do .Width(100)
builder.AddClass(
"HelloWorld",
propertyBuilder => propertyBuilder
.Add(Property.Width, 100)
.Add(Property.Height, 100)
.Add(Property.PaddingLeft, 100)
.Add(Property.PaddingRight, 100),
PseudoClass.Hover, PseudoClass.Checked
);
Yeah in the end I decided to deal with the game's ui. Unity UI sounds great (and definitely much better than old one. ImGUI is life though
) but it tries to feed me uxmlemlements waaaay too much
Oh I tried using ImGUI before and the UIToolkit is wayyyy better imo
At least Dear Imgui is always there for us when Unity is not looking 
At least your builder makes uielements much easier to use. Not sure I agree with style builder as it's kinda same as inline styles but it is nicely done and does it's job well
What would your idea be to have a better something for styles?
To be fair just a USS file is I think best option, going to include this option later on. But if you are not using unity it can annoying to create a unity project just to make a USS.
Maybe a
propertyBuilder.AddStylePropert(new StyleProperty() {
width = 10,
height = 20,
})
propertyBuilder.AddStylePropert(new StyleProperty() {
width = 10,
height = 20,
}, PseudoClass.Hover)

It is a preference thingy
I think to most people current event based approach looks/feels more intuitive/easier/better. And some prefer immediate mode. I know for sure there are at least three of us!
UIToolkit can be done immediate 
You can just modify the text values directly
I don't think I understand it to well for what you saying ๐
yeah event or state ? Idk the right term. I might be mistaken/misremember afaik uitoolkit was kinda like uielements/web for end user interfaces (but worse) and immediate mode is meant for editor ui. If you ever saw if (button) { ... handle click ... } that was 100% imgui
I think styles are fine/good and builder approach fits ui really well. Using style builder for individual elements instead of building a theme kinda feels bad as it's similar to using inline styling instead of css and I was strongly adviced against doing so ๐ Afaik unity discourages it too as one style/theme is cheaper to draw. Idk if it is noticeable when laid over procedural water mesh and textures 
I think you are a bit off here, I know that changing styles of the buttons etc are indeed very slow. That's why the StyleSheetBuilder is recommended way in TimberApi.
The StyleSheetBuilder is creating the CSS files, but it does do it per preset basis, if you use the same preset it will reuse will only create he StyleSheet(css) once
I tested to creat a bunch:
100_000 stylesheets with 1 class and 1 modifier -> 1,2 seconds
100_000 classes in 1 stylsheet with 1 class and 1 modifier -> 0,7 seconds
100_000 stylesheets with 1 class and 3 modifier -> 1,77 seconds -> 47% increase
100_000 classes in 1 stylsheet with 1 class and 3 modifier -> 1,0 seconds -> 42.86% increase
And would not have huge impact, creating a VisualElement and mofiying it's styles directly was much slower
I likely am. Probably got wrong impression from code/examples as I was looking for specific things
Biggest performance issue is creating the elements, which I cannot optimize.
Timberborn initializes multiple visual elements with 1 UXML which takes pretty much the same time for 5 elements in 1 UXML as just initializing 1 element.
But ye, it's not a big big issue since most things are just generated once and than not touched. At most you need to wait a few seconds longer in the loading screen if someone goes really wild
Kinda funny this makes styles and classes look slow due to seconds but then I see hundreds of thousands aaaand it's alright now as anyone who decides to open 100000 styleshets in one second deserves to suffer 
Oh no. But you do follow class naming guidelines and try to optimize selectors, right? ... And then the game spends these seconds to reload your whole bundle just in case
@stone shoal btw do you have plans or desire for "normal"/non-api mods?
Wym?
like a mod for people not moders ๐ Idk what to call it. Simply curious
players ! Modders are also people ๐ฎ
disgusting
Im a beaver
orrr maybe perhaps by anychance your soul aches for another by modders by modders project? Accidentally I've come across an idea ~~id like to see implemented by someone who is unfortunately precisely not me ~~ like that and will be willing to give it up for your sake 
I hope someday to finish TimberPrint
Did you ever get around to looking into this?
No sorry, if you can make a issue on TimberApi for it Ill probably check it out as first when factorio time is over
No rush for me really, Just wondered, as I got a few more crash reports through steam.
But I'll make an issue nonetheless, you do it when it's good for you. I've been busy with other projects myself.
@stone shoal Remember I reported a spamming error when using MinMaxSlider (#1064983064020799498 message)? It seems to be Unity issue: https://discussions.unity.com/t/unity-6-uitoolkit-layout-update-is-struggling-to-process-current-layout-with-minmaxslider-in-editor/1538464
As for the misaligned dragger (#1064983064020799498 message), I fixed it like this:
.AddSelector(".api__min-max-slider--small > .unity-min-max-slider__input > .unity-min-max-slider__dragger > .unity-min-max-slider__min-thumb", builder => builder
.MinHeight(16)
.MinWidth(16)
.MarginTop(-6)
//.MarginLeft(-7)
)
.AddSelector(".api__min-max-slider--small > .unity-min-max-slider__input > .unity-min-max-slider__dragger > .unity-min-max-slider__max-thumb", builder => builder
.MinHeight(16)
.MinWidth(16)
.MarginTop(-6)
//.MarginLeft(-2)
)
I guess, the left margin was added to "center" the circles on the dragger, but it breaks the dragger layout. I think it also needs to be adjusted.
The bad thing about the spamming error is that it drops FPS to the floor: from 144 down to 22. So, until they fixed it, I'll be using two regular sliders ๐ฆ
Btw, nice stylesheet builder ๐ . I spent some times figuring out how it works, but then it was clear and easy to use.
Tru console spamming does that
At first yhis was needed otherwise you had them
Did you fix the errors?
I didn't find a way. Unity devs said they are investigating, but it can take years. I checked where the error comes from.
public override void Update()
{
int num = 0;
if (base.visualTree.layoutNode.IsDirty)
{
while (base.visualTree.layoutNode.IsDirty)
{
changeEventsList.Clear();
if (num > 0)
{
base.panel.ApplyStyles();
}
base.panel.duringLayoutPhase = true;
base.visualTree.layoutNode.CalculateLayout();
base.panel.duringLayoutPhase = false;
UpdateSubTree(base.visualTree, changeEventsList);
DispatchChangeEvents(changeEventsList, num);
if (num++ >= 10)
{
Debug.LogError("Layout update is struggling to process current layout (consider simplifying to avoid recursive layout): " + base.visualTree);
break;
}
}
}
base.visualTree.focusController.ReevaluateFocus();
}
For some reason they cannon settle layout fast enough. Thus, the error. But bobody nows why MinMaxSlider causes it.
That's nice, does it need to be on the update call though ?
Can't it be done in TickableComponent or maybe event triggered ?
It's from UnityEngine.UIElements.UIRLayoutUpdater ๐
Ah
I checked MinMaxSlider code. I think I have ideas why it happens. maybe I'll paly with own implementation.
You should be able to create it yourself I think. Never tried to make a core element though
Regarding the margins. At the top and bottom are regular sliders for the reference. The first minmax slider is from TAPI, the other one is my local copy with the left margins removed.
How is the trigerability of the buttons?
No issues found.
Like when does the hover effect trigger, is it around where the button is or very off center ?
Fixed what exactly?
Because at the very beginning it wasn't bugged iirc
Ah, that. Maybe.
You could not click on the handle (button) around the edges
It was a few pixels away of the image
Given MinMaxSlider throws errors now, they definitely changed it compared to the earlier versions.
It wiggled a bit at 0:16ish
That general unity UIToolkit ๐
Does happen in the game as well sometimes
Ahh okay
The common problem of this control is "floats". There are a lot of roundings there. Basically, it's the problem of that "cannot handle layout" problem.
For some reason, resolvedStyle.width can be non-round. I don't know if it's by design, but for the control it was a problem.
My fix was just forcing rounding each time it's used.
Ahh, that's what I was going to suggest.
Either round or use fixed point number (not sure if c# has something like that)
Python has a Decimal type
Here fixed point would not help. It wasn't the losing precision issue. It was literally a code logical problem. They were using non-round width to set positions, and then they used the positioned controls to calculate a new width ๐ Not a surprise the system couldn't stabilize at some edge case values.
And I was surprised how Unity does layout calculation. I thought they maybe have a hierarchy or something, but they just run a loop until all controls reports "not dirty" (no values changed during the last layout update call). If the layout cannot become clean in 10 loops, the error is written and updater terminates, leaving the whatever state. As a result, you could see one of the thumbs flickering in UI.
Either tapi still doesn't support modifying the recipe lists or I'm doing something wrong, someone mind taking a look and checking for me?
playing on greedybuilders btw
What's up with this btw? ```
/// <summary>
/// This class only deserializes specification jsons, so this is not used
/// </summary>
/// <param name="value"></param>
/// <param name="objectSaver"></param>
public void Serialize(BuildingSpecification value, IObjectSaver objectSaver)
{
throw new NotSupportedException();
}
It's up with what it's says it's up to
?
why's it not implemented?
Because it only deserializes...
then what's the point of a spec that's never deserialised?
It only does deserialize
isn't that needed to convert the json to binary though?
You either are talking about something else or you read it wrong
Serialize method is not implemented
Deserialize is
Deserialization is json -> object
hmm, fair enough I suppose. as for the recipe Ids, I don't see anything that actually deserialises them
lines 37 ?
that's only passing the list along, not deciding if something is an ID or not
either way I'm still not getting the recipes I declare showing up in game
Yes it was broken indeed trying to fix it now
don't forget the #append/#remove support, I want to switch my bentos mod to full json
?
That isn't what people implement, that's how merging of specification jsons. If you make a specification it will has that
sweet
Makes sednse that it does not work if the configurator isn't even recognized
what did you need to do to fix that, or are you still working on that?

Some are working but recipes not 
Changing the recipe ids doesn't do much anymore
I have a feeling that before it wasn't done in the inventoryInitializer or initialization was later
@lofty lark Are Manufactory components still placed on the prefabs ?
Answer is probably that it is replaced with the ManufactorySpec, Since that one seems to work ๐
@primal wind
sweet, it uploaded yet?
Not yet
lemmie know the version when you do so I can set the req on my bento and botkit mods
@vast otter whenever you're ready you mind doing those bot kit icons for me? Simple tool box with the relative FT/IT logos in the top right will be enough
No way ๐ฎ After more than 2 years (see this : #1064983064020799498 message), can add new recipe ? Guess, better later then never. TY ๐ ๐
lol XD
This was already at least 1 year possible, I don't think I created the sketch gear house directly after. It just broke with update 7 like everything else ๐
Added: 4 jan 2023
xD
Nope, when I send the message I pinpointed , was broke again. (middle 2023). From that moment I counted ...
But, important is to have that option again ๐
Well rip
Might be handy to make an issue next time instead, saying it on discord can be done as well but if I am not actively working on it I probably forget it within a week 
noted
sweeet ๐
yes, many scripts have been replace with "[script] spec"
The same old format ?
welp appears to have broken choo choo, I'll reload without that active to see what else breaks (if anything)
also is there an option to disable this type of output? ```GENERATING SPECS
LOADING SPECS
beaverbust.ironteeth
362
beaverstatue.folktails
362
bell.ironteeth
362
bench.folktails
...
nuts, height shower mod broke too ๐ฆ
Simple floodgate triggers knoked out, too ๐ญ
looks like those are the only 2 of my installed mods that broke ๐
UIBuilder isn't compatible anymore 
those are my last 2 crashes, 1st for choo choo and 2nd for height shower
I did not change it unless a clean solution does that 
I just figured you'd want to see where it broke, I'm not expecting this to be a tapi issue
It half of is can't do much about it though
Don't know enough about C# building process of dependency loading
But seems like my build for some reasons changed some internal data so the mods don't know it anymore or something like that
@primal wind or @austere tangle does this one work ?
got couple min left on a TLDR vid to watch then I'll try
just entered the ground news ad bit so quitting the vid there, let's about this build ๐
Just wait to load ...., and wait ....
right behind you ๐
Third here ๐
Yep crashign
Don't understand why though, Im prety sure I have updated TimberAPi before without making everything else crash 
maybe it was that configurator thing being different now?
yep, still got a crash, not sure if was height viewer though, gonna check the log now
yeah it was height shower again ๐
maybe it's the way they linked in the 1st place?
and, simple floodgate triggers ...
That was probably me not having TimberApi enabled 
Wait.....
I just wanted to fix a small issue
and go back to hobby stuff
yep, always the way
YA, a code that works from the start, do nothing ๐คซ
Well it didn't work remember ๐
In the first half of 2023, was working, remember ?
Oh ye but Timberborn also broke it ๐ not only me
I fixed mine part and still was broken
True
I suggest abandoning the try/catch part of it, or at least adding a log that says X does not have member Y in the catch statement
22-9-2024 is that less or more than 48 days ago 
that way you can actually see when the code is attempting to use something that don't exist
Anyway, maybe dev's will add in the U7 as game feature, so, could be a unnecessary headache ๐ค
I barely use any lmao
The problem now has nothing to do with the BuilderSpecification
Could you comment building spec and send the TAPI ? To check if something with the built is the culprit ..
The UIBuilder is breaking things, It's also breaking on another build without the cahnges
FINALLY! ๐ ๐
You, but me, without simple fllodgate trigger, my beavers are a dead meat ๐ญ
currently my botkit mod fully overrides the list as a left over from trying to get it to work with 7.7.0, now I just need to try with #append
Use a different version from mod.io ๐
Seems like I cannot fix this
you still need that? even though we have sluice gates?
Sure, to avoid small overflowing ...
uh, just install some normal dams at the top where you want the overflow to go
Is good for health on badtide ๐คฃ
always assume overflow
and I don't just mean when playing ๐
the mark of a good programmer/gamer is that they always assume the worst case scenario can and will happen eventually
True, like increase in water flows before drought or badtide ๐
yep, though I thought it was the reverse XD
About 2-3 days before ,,,
@median plinth Whenever possible could you recompile your mod with the latest version of TimberApi. Im pretty sure this solves everything without changes.
g2k
Either something in unity/Timberborn changed with UIToolkit which made UIBuilder do some changes and everything broke or I maybe changed something somewhere. Or it's just random C# stuff which I don't know enough about.
I can later in the evening today
My bentos are fully json made now ๐
At least something good from the update 
I'll just update the mod req and wait on 7.7.2 to be uploaded ๐
I think there's a memory leak somewhere as TB just crashed on me, no new mods, only removed mods
must be static linking occuring somewhere then
Same, might test with updating it some class in the DLL tomorrow and see if it crashes again
But I am pretty sure that would not matter
btw, was there a plan to support #append with a mod filter with a patch to JsonMerger? I'm trying to figure out if it would still be useful or not,
There was already a plan for that 2 years ago ๐
Not specificly that, and not sure if I am going to add it like that specificly but yes
From next week I am starting to plan in time for modding again
Altough this will be firstly documentation, then finishing the loggin feature + console
@stone shoal Btw, on https://timberapi.com/ most of the links point to nowhere. E.g. ui builder link directs to "https://vueuse.org/".
And there is no clear link that would give GitHub repository. I had to google for it.
If you mean for recipeId list then it seems to be supported already, I tried it
No I mean with a suffix like #append#Tobbert.Ladder so that it's only appended if the ladder mod is present.
oh, that's an interesting idea
so that faction mod authors can add "optional" buildings that only activate when the other mod is present,
hmm, prob with that is that it puts the problem of support many mods on those faction authors
yea, which is why I wasn't sure how useful it would actually be
in other words it converts a "many to one" to a "one to many" problem which I'm not a fan of
it's like going from multi-threaded to single-threaded, never a good idea when multi-threaded is already working well
There is a github icon 0n right top
Shit happens
I thought I was old at 35 going on 36, I haven't made the mistake of not look for icon yet, just hold old are you?
I make plenty of spelling mistakes though XD
I'm 48. When internet became a widely available thing, I was already drinking alcohol ๐คฃ
nice, though I don't get the fascination with alcohol. I occasionally drink it, maybe once a year at most, never really pulled me in
similar deal with fags. back when I was a I kid I nabbed my dad's fags, took 1 puff and decided then and there I would never smoke in my entire life
been the same decision every time I tried
Here I can only congrats you. There is nothing good in alcohol. I consume it only to save other people: the more I drink, the less remains for the others.
lol, nice excuse XD
I changed the class with a new method and it keeps working
. Probably has something to do with an updated unity version or because something weird happend in the project and I renamed an unrelated project manually.
Curious
@stone shoal 0.7.7.2 broke my custom GameTextMinMaxSliderBuilder2 which was a simple copy of GameTextMinMaxSlider<TBuilder>. I didn;t see anything in the changelog. Was there changes to the preset classes hierarchy?
Nm. It's Rider got a glitch after the mod update.
my first thought: ha! Grandpas 
Second one: wait a minute thats just 5 more years for me... 
I have made the tool system for the bottom bar for wel... tools. And everything must be done with tools (which is 99% the case) but for example the settings box isn't a tool. It can't and should not be switched to. But should be displayed in the bottombar
I don't think it's a supar great system but don't know either how to change it since UI en Tools are seperated systems. How would you allow UI only sections 
Should those elements even need to use the ToolSpecifications
Could you clarify a bit?
Right now bottom toolbar has nothing to do with tools, it is made entirely of UIElements and switching tools/groups done in event handlers. ToolButton knows about UI button but not the other way around. Do you need UI button to know about tool or what's the problem?
btw I think default cursor tool handles settings button in some special way - might want to look into that
Edit: don't hesitate to RTFM me I probably didn't pay enough attention reading tapi code. And questions are out of curiosity
Original bottombar are tools, but the "tool" is already implemented in the button so the tool is kinda lost. And you can only get the tool if you already know the tool.
I reworked it to make the whole bottombar to specification based and splitted UI and tools. These things allowed to
- Customize any button UI to any other UI or custom ones
- Easily changing order of buttons (and other stuff)
- Multiple rows (with many other patches)
At a later time I implemented the interface IUnselectableTool But this is just for scrolling IIRC.
What I want is also able to only have UIElements inside the bottombar (I think). But not sure how to do that nicely, also not sure if it's really that much of a problem. It would limit to adding things like a toggle button in the BottomBar, but does such thing even need to be in there
Cursor is just a casual tool, nothing special. The tool manager only defaults back to that one if nothing else is picked.
Maybe it's just a non issue
and only settingbox is special and not that much of a workaround required for it as in you need 1 extra class to enable the box instead of doing it somewhere else
It shouldn't be an issue right now (maybe with normanr tool search? probably fine though).
Do you need this button to be a part of bottom toolbar? Maybe remove it and place identical one near bug report button bottom right?
Yeah precicely, I was thinking of like the factorio quick actions teh right side. But why would this need to be part of a tool selection system. If you could also make a system next to it designed for that purpose
And at the beginning was like what if you want to add a Timbe in between
. But with the IUnselectableTool you could do this if you really really want to.
Sooo... just forget about all of this ๐
#1303754962387468328 message This on the other hand is the probably the correct fix for the current issue why I was rechecking this feature.
Okay made it possible to have generic tool specifications
Id = "Cursor",
Type = "GenericTool",
Layout = "GrouplessRed",
Order = 0,
NameLocKey = "Cursor",
DescriptionLocKey = "Cursor",
Icon = "Sprites/BottomBar/Cursor",
DevMode = false,
Hidden = false,
ToolInformation = new
{
BottomBarSection = 0,
ClassName = typeof(CursorTool).FullName,
}
ClassName can either be the full name with namespace or without. Should only be 1 match if there are multiple tools with same class name it throws an error
How would I know about the icon for a fall back one
@young tendon What mod is yours with the CutterTool and ForestTool
I think I found it... Forest Tool?
Alright that fully works ๐
Yeah, Forest Tool and Cutter Tool. On steam or mod.io.
Ok, so you've managed to load the mapeditor with the mod installed? 
Yes it's already live 
@quiet delta Was there any specific reason why you first extract all the #append and #remove actions and later apply them after each other instead of just changing it instantly?
public JObject Merge(IEnumerable<JObject> jsons)
{
JObject mergedJson = (JObject) null;
foreach (JObject json in jsons)
{
JsonMerger.ProcessCustomTokens((JToken) json, JsonMerger.AppendKeyword, (ICollection<JsonMerger.ArrayModification>) this._arrayAppenders);
JsonMerger.ProcessCustomTokens((JToken) json, JsonMerger.RemoveKeyword, (ICollection<JsonMerger.ArrayModification>) this._arrayRemovals);
mergedJson = JsonMerger.MergeJsons(mergedJson, json);
}
this.ProcessArrayAppenders((JContainer) mergedJson);
this.ProcessArrayRemovals((JToken) mergedJson);
return mergedJson;
}
I think it is due wanting to add everything from all mods first before removing anything 
Or maybe it's because of Wait that can't be it... json confuses me[Error : Unity Log] InvalidOperationException: The parent is missing. 
I don't remember tbh. Maybe this approach was cleaner for some reason ๐ค although adding all elements before removing anything makes sense too.
@vast otter very very WIP but the idea for this one at least works.
{ "TestList", new List<string> { "AAA" } },
{ "TestList#append@true", new List<string> { "CCC" } },
{ "TestList#remove@true", new List<string> { "CCC" } },
Results in: AAA, it got removed and added
{ "TestList", new List<string> { "AAA" } },
{ "TestList#append@true", new List<string> { "CCC" } },
{ "TestList#remove@false", new List<string> { "CCC" } },
Results in: "AAA, CCC", removal is disabled
{ "TestList", new List<string> { "AAA" } },
{ "TestList#append@false", new List<string> { "CCC" } },
Results in: "AAA", appending is disabled.
{ "TestList@false", new List<string> { "AAA" } },
Results: crash (if it's the only one because the property doesn't exist anymore now)
{ "TestList@true", new List<string> { "AAA" } },
Results: works as normal
{ "TestList", new List<string> { "AAA" } },
{ "TestList@true", new List<string> { "BBB" } },
Results: "AAA, BBB" it get's merged with the other "TestList" in same json, and will replace the whole list in a merge
I want it to make it support properties as well but for now I start with lists
Noice ๐

How about just making a separate spec file like PrefabGroupSpecification.Buildings.GreedyBuilders.mod.Tobbert.Ladder.json? where everything between mod. and .json is the ID of the mod to apply the configuration to. In the case of multiple overrides of mod configs could use something like PrefabGroupSpecification.ModOverridesOrder.GreedyBuilders.json to declare the order of override priority
How do I use a generic tool specification? Is there an example?
ahh, SettingBox is a simple example
And there are 2 or 3 more
CursorTool is also one of them
Pretty much any timberborn tool that does not use a factory or needs extra data beside the dependency injection. Which is also the use case for this update.
What do you think about the file name specs? My idea goes further than just required mods so that you could use mod settings for example. And I think that such files could get very ugly fast.
As side node, I am not sure yet if I want to do just the @ condition action or just make the full on .patch modifier which will work something like this
https://rimworldwiki.com/wiki/Modding_Tutorials/PatchOperations#PatchOperationReplace
And then in json format. With this you have more fine control about what is changed
For example:
At the moment you can't quite change a value like the points in this example
{
"ConsumptionEffects#append": [
{
"NeedId": "Thirst",
"Points": 0.3
}
],
"Weight": 2
}
With the patch operations you could look for the thirst need Id and change it's points.
append means that you add something. To change, use #remove and #append ....
Im fine with any way that i can tell the game:
only do this edit/append if mod x is enabled
What about changing things in additional to conditions
- If Choo choo exists
- Modify consumptioneffect thirst to 0.5
Or - If If Choo choo exists
- Remove thirst from Consumption effects (now this can conflict or not posible at all)
Are those things somewhat usefull? or you only want simple append/removal
Yes and that will lead to conflicts if 2 mods do that which is the problem ๐
And not sure if people care about being able to have more control in that aspect
idk if this would just be confusing or actual usefull 
{
"ConsumptionEffects@change('NeedId')": [
{
"NeedId": "Thirst",
"Points": 0.6
}
],
}
^ uses NeedId as a search modifier which is the only part that needs to match and changes the Points to 0.6
for me i only see a need for append/removal but if its not to hard to add it, go for it ๐
would that also work to set the GroupId for a ToolSpec when a mod is present (like More groups)?
like maybe:
{
"GroupID": "Storage",
"GroupID#KnatteAnka.MoreGroups": "Subgroup_MGTanks",
}
alternate syntax (sort of based on css):
{
"ConsumptionEffects[NeedId='Thirst']": {
"Points": 0.6
},
}
where the expression inside the square brackets is used to select the list element to merge the value into
and the first example in css like syntax might be GroupID:mod(KnatteAnka.MoreGroups)
I want this to be working yes
this was a new bug ๐ฎ
if the text is 2 lines some is hidden as the next icon is drawn on top
its soon released with decoration extention
(and not a critical problem)
I don't think names should be 2 lines. Probably also a problem without TimberApi ?
ok ya its the same in base game so will workaround it
I thought a bit about it and not even sure how I would fix it
Ya its fine will work around the limitation and have suggested yo change the ancor point from top to bottom left
you have ancor points in visual elements ?
It's probably due a fixed offset from the hovered element and height always goes from top to bottom in css (which unity pretty much uses just a old/minimal one)
So the offset should need to change at runtime which isn't really a simple or nice thing
Or maybe a wrapper around the element with a higher height and have it's child fix to the bottom
Not sure, but I think this part is still timberborn original. If you could make a issue on github I could maybe fix it someday. Kinda low on energy last few weeks
iirc tooltip box is on the same UIDocument but separate VisualElement/overlay from panels and is positioned by its own component or singleton. Sameish for dropdowns and storage choices. Might be different for bottom bar specifically then maybe hovered VE takes priority in sorting?
Edit: it is just Label with text, something like this code. Idk why it wraps though. Demolish is long too but it doesn't wrap.
<ve name="ToolGroup" class="tool-group" >
<ve name="ToolGroupButtonWrapper" class="bottom-bar-button" >
<ve name="" class="bottom-bar-button--main" >
<Button name="ToolGroupButton" class="unity-text-element unity-button bottom-bar-button__icon bottom-bar-button__button bottom-bar-button--clickable" >
<ve name="Frame" class="bottom-bar-button__inner-item bottom-bar-button__frame" />
</Button>
</ve>
</ve>
<ve name="" class="tool-group__tooltip-wrapper" >
<NineSliceVisualElement name="" class="bg-box--brown" >
<Label name="Tooltip" class="unity-text-element unity-label tool-group__tooltip game-text-normal" />
"Demolish buildings and resources"
</NineSliceVisualElement>
</ve>
</ve>
Why you asking this in TimberApi though 
Nvm you are about knattes problem i guess?
Depending on the text-wrapping type it normaly is done on word break.
which means single words never get wrapped. 2 words only get wrapped if it's too long (or always if the width is smoll)
@vast otter that gave me an idea - maybe using non-breaking space would help? html entity code ย iirc
Or less characters per line ๐ or just one line
anyone using the specification generator feature
? ISpecificationGenerator
for both or either?
down that path lies madness,
Does ModA;ModB mean A and B have to be enabled? (or A or B has to be enabled).
@mod(ModA)@mod(ModB) is probably the simplest?
another idea: Make it possible to enable/disable append/remove with mod settings,
maybe something like @modsetting(ModA.OptionA) which would need to be a boolean
from: #๐คmod-creators message
It would do the same. Im gonna make it that all modifierw should return true to enable the line
This is the plan yes. Bit will probably implemented another time
If not done by emka itself
yea, you could just use Unity's PlayerPrefs.GetInt
that'll work for Mod Settings that use the default ISettings binding,
I don't know how many mods are using FileStoredSettings
This is something for coded mods right?
yes
I have an issue, I wonder of someone in here could help me with it.
6 mods involved here.
Harmony, Ladders, Emberpelts and Ladders for Emberpelts are enabled for all tests.
Add TimberAPI, it works fine.
Add Bob Storage, it works fine.
Add both, and specifically only while loading a Folktails game, I get that error.
I'm pretty sure the error would happen with only those 2 mods.
A tool building or w/e has probably the same name
I'm looking at names now, but I don't see any duplicates.
Could you add to the error message what specification it tries to create?
Gonna disable all my new folktails buildings in PrefabGroupSpecification.Buildings.Folktails to see if it still errors when I load a folktails game.
okay, that actually loaded
I enabled the ExtraLargePile and it worked, and UndergroundTank and it worked, so I'm guessing it has an issue with me using UndergroundWarehouse.Folktails
it exists as a background compatible prefab name on the underground pile
UndergroundWarehouse.Folktails hasn't existed in Vanilla since U2. In U3 it was changed into the Underground pile, and you can't even load U2 games in U3 or newer, because of the huge change in the storage system.
so there's really no reason for the tag to be on there.
to test, I did this.
if this still crashes, I'm stuck, because if I don't add the backwards compatible tag here, I'm basically screwing everyone over who's already used the mod
okay, it actually worked.
I also think it's kinda dumb that it's only a problem with TimberAPI. if the game engine doesn't care if you're using a prefab name that something else has as a backwards compatibility name, TimberAPI shouldn't either.
At least I can fix the mod now.
I could have worded that better, but, consider that a TimberAPI bug report.
The Vanilla engine allows you to use a Prefab name that exists on another prefab's Backward Compatible Prefab Name, but if you do that and enable TimberAPI, it'll crash the game.
Ya it should not care for creating specification if it has backwards compatible names๐ค in older version of the game it was not allowed to have a building with one name and an other building with it as backwards conpatible name but that was fixed in u5 or u6๐ค
Interesting thread: #๐mod-users message. I wonder if TimberAPI should show which mod a Tool comes from
It would have to be based on the location of the ToolSpecification file,
Almost all ToolSpecifications don't have a fysical file.
The base game ones don't
None does
oh, you mean the prefab ones don't either
All buildings are generated by their prefab
For custom tools which almost no one uses yet would have one, or are done by code if they want to
Aside of not able to, I think this is more a debug tool than something I always want in TimberApi.
For prefabs it might be able to point it back to the prefab group specification files somehow
Not specific a TimberApi thing though, everyone could do that ๐
yea, the reason why I though of TimberAPI is because it already reimplements the Tool bar
so maayabe adding tracking of where tools are loaded from wouldn't be too impossible,
Yea, unfortunately since timberborn is pretty generic with most things getting info back where it came from can be tricky
but they're loaded from prefabs yea,
Yea I use the prefab collection from timberborn, so you would have to track it already down before it goes in there. And also know from which specification it would have been loaded
Getting locations from specifications would probably hardest part
Not sure what it is called nowadays, there is a specification where people define the buildings
Before in update 5 it was just in faction specification
The PrefabGroupSpec?
You are already way to late at that point
Might be
But I don't even have the energy to get through my work day, so something like this will likely not happen by me and would also be on a low prio compared to other things
yea, totally
I can however try to help you here and there if you are stuck and wanting to make it
Instead of relaxing and watching some YouTube videos, I spent the evening setting up my new PC so I could update my mods on the steam workshop so they'd have the Mod tag.
Mod tag on steam ?
Steam content is tagged with Mod or Map depending on how it's uploaded,
You upload mods manually instead of ingame ?
I couldn't get Timberborn working under Steam, so I used SteamCmd to upload initially, except it can't set tags ๐
I see
With new PC, I can now upload in game, so i't s a non-issue now
Neet
and I got a nice increase in graphics quality & fps
Thats always good 
@spring radish not 100% if you were the one who asked about properties but...
{
"TestString": "Hello,",
"TestString@mod(TimberApi.Debug)": "Hello, World.",
"TestList": [
"BBB"
],
"TestList@mod(TimberApi.Debug)": [
"ZZZ"
],
"TestList@mod(TimberApi.Debug)@mod(TimberApi.TesterMod)": [
"CCC"
],
"TestList@mod(test)": [
"DDD"
]
}
Properties are also working.
Results in:
{
"TestString": "Hello, World.",
"TestList": [
"BBB",
"ZZZ",
"CCC"
]
}
Yea, way back here
They typed that
that's really cool! then I can continue to make mods with UI without Unity then 
That was/is indeed the whole plan of it ๐
Although it has some limitations, but with this version way les than before
Like wildcards are not supported in selectors eg .myclass > * is not possible. But it's also not recommended to do by unity standards
Sadly no documentation though 
you have CSS in game development now? 
"CSS" yes, It's USS
It's like CSS but outdated
The one and only. Contribute to Timberborn-Modding-Central/TimberAPI development by creating an account on GitHub.
Here are almost all ingame components as presets you can use
And is also an exampe how you can make your own
thank you!
https://timberapi.com/timber-api/uibuilder/basic-usage.html
Actually there is a documentation
Timberborn modding documentation
Just WIP

@stone shoal
I am getting below error while starting the game.
v0.6.9.3-b880551-xsw
ArgumentOutOfRangeException: Length cannot be less than zero.
Parameter name: length
System.String.Substring (System.Int32 startIndex, System.Int32 length) (at <20a025bba6874f73adca28fec451f638>:0)
PumpExtender.ExtendablePumpSettings.ExtractPumpName (System.String prefabName) (at <1f0ecefd4dff4c698b8f813f7db26505>:0)
PumpExtender.ExtendablePumpSettings.OnAfterLoad () (at <1f0ecefd4dff4c698b8f813f7db26505>:0)
ModSettings.Core.ModSettingsOwner.Load () (at <9508e8c86d724f229ef86851c667d051>:0)
(wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.Timberborn.SingletonSystem.SingletonLifecycleService.LoadSingletons_Patch2(Timberborn.SingletonSystem.SingletonLifecycleService)
(wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.Timberborn.SingletonSystem.SingletonLifecycleService.LoadAll_Patch1(Timberborn.SingletonSystem.SingletonLifecycleService)
Timberborn.SingletonSystem.SingletonLifecycleAdapter.Start () (at <2cf8a69d91ab4139baf8d8d9e11adc45>:0)
So you have the value lower than 0?
I just subscribed and trying to start the game.
It didn't get to the menu also. before that only it's crashing. @stone shoal
have you tried with only Pump extender and its dependenty?
have you tried disable tbmpl mods so its not a collision of mods?
will try.
Same with all TBMPL mods disabled.
v0.6.9.3-b880551-xsw
ArgumentOutOfRangeException: Length cannot be less than zero.
Parameter name: length
System.String.Substring (System.Int32 startIndex, System.Int32 length) (at <20a025bba6874f73adca28fec451f638>:0)
PumpExtender.ExtendablePumpSettings.ExtractPumpName (System.String prefabName) (at <1f0ecefd4dff4c698b8f813f7db26505>:0)
PumpExtender.ExtendablePumpSettings.OnAfterLoad () (at <1f0ecefd4dff4c698b8f813f7db26505>:0)
ModSettings.Core.ModSettingsOwner.Load () (at <9508e8c86d724f229ef86851c667d051>:0)
(wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.Timberborn.SingletonSystem.SingletonLifecycleService.LoadSingletons_Patch2(Timberborn.SingletonSystem.SingletonLifecycleService)
(wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.Timberborn.SingletonSystem.SingletonLifecycleService.LoadAll_Patch1(Timberborn.SingletonSystem.SingletonLifecycleService)
Timberborn.SingletonSystem.SingletonLifecycleAdapter.Start () (at <2cf8a69d91ab4139baf8d8d9e11adc45>:0)
Then the step is to disable a few mods at a time until you find the culpit for why pump extender crashes
maybe with water beaver/white paws.
Might be. It searches for everything with a specific module inside a Building
If he does something weird with it thats not as a normal punp it can cause problems maybe
@stone shoal hi, any doc or sample mod I can look at for making a new tool? specificially, I will make a new area selection tool, similar to the tree cutting area marker
I guess I will look at the Forest Tool or the Cutter Tool on the Steam Workshop
Docs for timberapi.com. Contribute to Timberborn-Modding-Central/TimberAPI_Docs development by creating an account on GitHub.
How you should make the tool itself is up to you
If you have any questions, feel free to ping me.
thank you!
TAPI doesn't work in U7, right? It's not just me? ๐
Correct
Yep
Not sure when its fixed there are some things to checkout
If I have time and energy I'll try the weekend
Probably fixed around next weekend for sure
Do you have the latest version on GitHub? I can give it a try too. In case of there is a quick fix.
There is no quickfix but yes the latest untouched version from update 6 is live
Already fixed some issues, but the tool system needs some bigger chances due there are no deserializers anymore
Wow! Sounds like a big change. Unless the deserializer can be just ripped out of U6 ๐
And haven't looked at the bottom bar, yet but I saw at lease some errors
They made it dynamic so far I can understand
Like they check if it should be a string/int and they transform it into that etc..
Don't think it's going to be tooo bad. Just a small rework to convert my ToolSpecification to a ToolSpec with blueprints. And make the specification generator work with blueprints
It might be nice to split out the parts that don't have anything to do with the bottom bar into a separate dll (or even separate mod).
like the UI builders,
You mean how it has been since update 6 experimental 
hi I have a mod I would like to upgrade to U7 that uses TimberAPI, should I temporarily disable the feature that uses TimberApi or just wait?
I do not mean to rush you or anything, just ask for some estimation of when TimberApi U7 will be available, thanks.
What is the feature you use ?
Probably next week at maximum, maybe this weekend
I fixed the compiiling errors but it's crying about some public modifier crap
public void Load()
{
const string LabelName = "Coords";
panel = builder.Create<VisualElementBuilder>().SetName("HeightShowerContainer").AddClass("top-right-item")
.AddClass("square-large--green")
.SetFlexDirection(FlexDirection.Row)
.SetFlexWrap(Wrap.Wrap)
.SetJustifyContent(Justify.Center)
.AddComponent<LabelBuilder>(
LabelName,
(builder) => builder
.AddClass("text--centered")
.AddClass("text--yellow")
.AddClass("date-panel__text")
.AddClass("game-text--normal"))
.BuildAndInitialize();
lblCoords = panel.Q<Label>(LabelName);
layout.AddTopRight(panel, 7);
SetVisibility(false);
}
this is all ๐
I can't use the goddang new specs shit
It pretty much depends on this dumb error
Which I have no clue why it's happening
Publicizer accidentally publicize something that it should not maybe? because the access modifier got changed into public?
but is it an interface? then that's weird
because everything in an interface has to be public.
maybe for that one, refer to the original DLL without going through the publicizer?
HMM hard to test without publicizing xD
oh dear ๐
so, EqualityContract is generated by record class. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record#value-equality
so what I may try = add this:
protected override Type EqualityContract => throw new NotSupportedException(); // Implement later
protected virtual bool PrintMembers(StringBuilder builder) => throw new NotSupportedException(); // Implement later
and see if you can compile it with the publicizer?
Does not like that
Butttt maybe I can just remove the publicizer from the dll that includes that record
an easy way to find out way to try is to set ILSpy to C# 8 before record, to see what that class actually look like.
luckily they have so many
Why does it ned to be set to C# 8 ?
oh you mean this screenshot = you removed the publicizer from all assemblies? I meant only for that assembly ๐
Ye
Have to specificly do that than ๐
record is just a sugar syntax. behind the scene it add : IEquatable<ComponentSpec> and a generate a bunch of members
so if you want to see how the class actually look like in IL, you decompile it in C# 8
is this going to work 
maybe you need a <Reference Exclude="..." /> before?
I am not sure
one way to find out ๐
This way no difference, but the publicizer also adds things that say it has been publicized and in that class there exists non
Like this
<Reference Include="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Timberborn.BlueprintSystem.dll" Publicize="false">
<DestinationSubDirectory>libs/</DestinationSubDirectory>
</Reference>
<Reference Exclude="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Timberborn.BlueprintSystem.dll" Include="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Timberborn.*.dll" Publicize="true">
<DestinationSubDirectory>libs/</DestinationSubDirectory>
</Reference>
No luck
I guess I just create a new DLL and test specs with it
try it to be 3 entries, something like this:
<Ref Include="*">
<Ref Exclude="that-assembly">
<Ref Include="that-assembly">
<ItemGroup Condition="$(UseLocalTimberbornSource)">
<PackageReference Include="BepInEx.AssemblyPublicizer.MSBuild" Version="0.4.2"/>
<Reference Include="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Timberborn.*.dll" Publicize="true">
<DestinationSubDirectory>libs/</DestinationSubDirectory>
</Reference>
<Reference Exclude="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Timberborn.BlueprintSystem.dll">
<DestinationSubDirectory>libs/</DestinationSubDirectory>
</Reference>
<Reference Include="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Bindito.*.dll">
<DestinationSubDirectory>libs/</DestinationSubDirectory>
</Reference>
</ItemGroup>
If I just do this it still has the blueprint imported
hmm what if you try this:
<Reference Include="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Timberborn.*.dll" Publicize="true">
<DestinationSubDirectory>libs/</DestinationSubDirectory>
</Reference>
<Reference Update="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Timberborn.BlueprintSystem.dll" Publicize="false">
</Reference>
wtf is udpate
or:
<Reference Include="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Timberborn.*.dll" Publicize="true">
<DestinationSubDirectory>libs/</DestinationSubDirectory>
</Reference>
<Reference Update="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Timberborn.BlueprintSystem.dll">
<Publicize>false</Publicize>
</Reference>
well it... updates ๐
lets try things again. I am editing in the wrong csproj
Okay the exclude/include in one works
I got less errors 
But I extend, which still complains... because it's on toolsystems ofc...
@quiet delta, publicizing the ComponentSpec dll results in Error CS0507 : 'ToolGroupSpec.EqualityContract': cannot change access modifiers when overriding 'public' inherited member 'ToolGroupSpec.EqualityContract'.
@severe solar had this problem as well at the beginning. Altough he said it was fixed when updating unity. Not sure if this was just coincidence and maybe it's not yet publized
.
But might be a real problem if that makes it impossible to publicize.
Anything that comes in though with it will create this problem, extending existing spec. Or just directly ffrom ComponentSpec
does TimberAPI need Unity IDE? if not I can clone the code and see if I can try something
No it's unity free
okay could you commit the current code please, I will try it ๐
I have incentive to make this one go public as soon as possible lol
It's in update 7 branch
<ItemGroup Condition="$(UseLocalTimberbornSource)">
<PackageReference Include="BepInEx.AssemblyPublicizer.MSBuild" Version="0.4.2"/>
<Reference Include="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Timberborn.*.dll" Publicize="true">
<DestinationSubDirectory>libs/</DestinationSubDirectory>
</Reference>
<Reference Include="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Timberborn.BlueprintSystem.dll">
<DestinationSubDirectory>libs/</DestinationSubDirectory>
</Reference>
<Reference Include="$(SolutionDir)Timberborn\Timberborn_Data\Managed\Bindito.*.dll">
<DestinationSubDirectory>libs/</DestinationSubDirectory>
</Reference>
</ItemGroup>
In the end this was already enough, don't need to exclude it even
wouldn't that cause conflict though? you are refering to two assemblies with the same members?
, maybe it just checks which is more specific like css does ๐
our publicizer or the bepinex one?
BepInEx, tobberts problem might be unrelated. But was also about the Spec with modifier error
you can try generate your own equality members ๐ค
hmm, good point. I didn't try "disabling" individual .dlls to see if I could get SteamUpdateButtons to work in Update 7. It just crashed because of the Configurator changes.
and set proper access modifiers
is the problematic code on Git, @stone shoal ? I can compile it just now
what do I need to do?
Pretty much all dll's are broken, so not going to work I assume ๐
Did you go to the update_7 branch >
And UseLocalTimberbornSource should be true with a Timberborn symlink in the solution root folder
yes, I am on update 7, could you point me to the project/class please thanks
Otherwise you are using an quite outdated dlls
yeah I modified the projects a little bit to use files on my file system
it is using U7 asssemblies I extracted ๐
From the managed files or publizied files from a unity project ?
Maybe i just need to reclone itt and test if that works than 
How did you build it .-. because I get another error even without those
no just let me try to build to make sure it's right
which file are you having the issue right now?
TimberApi.Tools, ToolGroupSpec
Alright
you think using Reflection to fix these 5 easier?
it's just an issue with access modifier now, no more inheritance issue
Reflections won't let me extend the ToolGroupSpec, and are so slow and anoying to work with
huh how so? ToolGroupSpec is public isn't it?
Timberborn.ToolSystem.ToolGroupSpec is public, I checked the original assembly. It's not exactly slow you know once you made one static method for it ๐
Not using publicizer isn't going to do it. Reflections are so anoying to work with. Specially in a modding scenario, otherwise it's mostly fine. Even with static magic it's still slower except some cases, it's probably neglectable but with the extra time it takes to work with
.
And I have like over 30 erros without publicizer. Not sure if that's all because some won't be checked for some reason.
but its (record) hidden equality members may be protected/private
Stopppppid record...
How does your publicier work 
I have no idea if it works xd
I didnt check if it works with these new ComponentSpecs
if it won't I will probably add some if to not publicize these members. For bepinex one I guess you have to write some script that will revert this
Is the publicizer very unity specific ?
I don't mind a extra step in the setup time, since I don't use CI/CD anymore for publishing.
namespace TimberApi.Tools;
public static class AccessExtensions
{
static readonly BindingFlags PrivateInstances = BindingFlags.NonPublic | BindingFlags.Instance;
static readonly FieldInfo ToolButtonServiceToolGroupButtonsField = typeof(ToolButtonService).GetField("_toolGroupButtons", PrivateInstances);
static readonly FieldInfo ToolButtonServiceRootButtonsField = typeof(ToolButtonService).GetField("_rootButtons", PrivateInstances);
static readonly FieldInfo ToolGroupButtonToolGroupField = typeof(ToolGroupButton).GetField("_toolGroup", PrivateInstances);
static readonly PropertyInfo BuilderPriorityToolToolGroupProp = typeof(BuilderPriorityTool).GetProperty("ToolGroup", PrivateInstances | BindingFlags.Public);
static readonly PropertyInfo ToolToolGroupProp = typeof(Tool).GetProperty("ToolGroup", PrivateInstances | BindingFlags.Public);
public static List<ToolGroupButton> Get_toolGroupButtons(this ToolButtonService s)
{
return (List<ToolGroupButton>)ToolButtonServiceToolGroupButtonsField.GetValue(s);
}
public static List<IToolbarButton> Get_rootButtons(this ToolButtonService s)
{
return (List<IToolbarButton>)ToolButtonServiceRootButtonsField.GetValue(s);
}
public static ToolGroup Get_toolGroup(this ToolGroupButton b)
{
return (ToolGroup)ToolGroupButtonToolGroupField.GetValue(b);
}
public static void SetBuilderPriorityToolToolGroup(this BuilderPriorityTool tool, ToolGroup? toolGroup)
{
BuilderPriorityToolToolGroupProp.SetValue(tool, toolGroup);
}
public static void SetToolToolGroup(this Tool tool, ToolGroup? toolGroup)
{
ToolToolGroupProp.SetValue(tool, toolGroup);
}
}
I can compile your project now ๐
above is all I needed to write ๐
here's the compiled file, could you check to see if it works?
To be fair, it probably doesn't because the generation is not updated yet
Has nothing to do with that though
var json = JsonConvert.SerializeObject(new
{
Id = priority,
GroupId = "Priority",
Type = "PriorityTool",
Layout = "Default",
Order = (int)priority,
Icon = $"Sprites/Priority/Buttons/{priority}",
NameLocKey = "CAN NOT BE MODIFIED",
DescriptionLocKey = "CAN NOT BE MODIFIED",
Hidden = false,
DevMode = false,
ToolInformation = new
{
Priority = priority
}
});
yield return new GeneratedSpecification("Tools", $"ToolSpecification.{priority.ToString()}", json);
}
They aren't called that anymore, or setup like that. With the new blueprints
this is one solution if you are interested in (don't know why my local branch is update_7_luke but the Github fork is update_7):
https://github.com/datvm/TimberAPI/commit/40aec050480b440b40c51d825a601d2b1bef1357
the above change + this to the csproj = can compile:
<Reference Update="$(GameAssemblies)\Timberborn.BlueprintSystem.dll" Publicize="false" />
<Reference Update="$(GameAssemblies)\Timberborn.ToolSystem.dll" Publicize="false" />
As said previously, I don't want to use this solution. But with your help we at least fastly aknowledged the problem. If I cannot fix this problem within next week I'll use it for time being.
If it wasn't for me being sick the last 2 weeks, and now getting another fever with huge headache. It probably would already be fixed
.
The solution I want to go for, if it's working would be:
- Create a new console project in
TimberApi, to publicize dll's with the same script they use Github link
This way if there are some changes within their publicizer I can also use it, and might even be better than bepinex publicizer with less obfusication with attributes.
Is it just my dumbass project or pc. Or is nuget just refusing to work.
yeah you want a publicizer that doesn't publicize those generated methods. I can't believe there isn't already one that you can specify an exception. Like don't publicize members with this name
I use this extension https://marketplace.visualstudio.com/items?itemName=MadsKristensen.Tweaks2022 with the option to delete the bin and obj folders on Clean/Rebuild
Most games aren't that widely using C#.
Im using rider though
But to be fair, my cloud saves also always crashes with ANY game on ANY platform
@cinder fern What happens if you try to install Mono.Cecil on a any TimberApi project within the nuget package manager
sorry I already deleted the project ๐
np
try dotnet add package <package name> from the console?
It has something to do with the bepinex feed, not sure if it's on my side still or not but it's something already
okay this is very strange, I am checking BepInEx.AssemblyPublicizer source code to ignore generated record methods, but it should already ignore them:
if (!methodDefinition.IsPublic)
{
if (!ignoreCompilerGeneratedCheck && !options.PublicizeCompilerGenerated && methodDefinition.IsCompilerGenerated())
return;
if (attribute != null)
methodDefinition.CustomAttributes.Add(attribute.ToCustomAttribute(methodDefinition.Attributes & MethodAttributes.MemberAccessMask));
methodDefinition.Attributes &= ~MethodAttributes.MemberAccessMask;
methodDefinition.Attributes |= MethodAttributes.Public;
}
public static bool IsCompilerGenerated(this IHasCustomAttribute self)
{
return self.HasCustomAttribute("System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
}
I don't know why BepInEx publicize all of them, because these members definitely are CompilerGenerated
oh I see, PublicizeCompilerGenerated is not on by default
so the publicizer accidentally publicize this property only even though it should not have. In the contrary, it correctly leaves PrintMembers as protected:
[CompilerGenerated]
protected virtual bool PrintMembers(StringBuilder builder)
{
return false;
}
so it's actually a BepInEx bug, we can fix that
found it:
// Special case for accessors generated from auto properties, publicize them regardless of PublicizeCompilerGenerated
if (!options.PublicizeCompilerGenerated)
{
foreach (var propertyDefinition in typeDefinition.Properties)
{
if (propertyDefinition.GetMethod is { } getMethod) Publicize(getMethod, attribute, options, true);
if (propertyDefinition.SetMethod is { } setMethod) Publicize(setMethod, attribute, options, true);
}
}
so for some reason, they have this special logic
which they publicize record's EqualityContract as well
I removed that piece of code and now the publicized class is correctly kept as protected:
the correct code should be (I added IsVirtual check):
// Special case for accessors generated from auto properties, publicize them regardless of PublicizeCompilerGenerated
if (!options.PublicizeCompilerGenerated)
{
foreach (var propertyDefinition in typeDefinition.Properties)
{
if (propertyDefinition.GetMethod is { } getMethod && !getMethod.IsVirtual) Publicize(getMethod, attribute, options, true);
if (propertyDefinition.SetMethod is { } setMethod && !setMethod.IsVirtual) Publicize(setMethod, attribute, options, true);
}
}
since if they publicize a virtual method, further developer can do nothing with it
Make a PR on them
?
yeah I will. but will probably take them a long time to publish it. I can publish a temp Nuget package if you want to
Not too sure if it will take long htough, How do you use it locally ?
I can do that for time being
you can either refer to my project https://github.com/datvm/BepInEx.AssemblyPublicizer/tree/fix-record-EqualityContract, or compile a DLL with it
or I can push a Nuget package and you use that one for now
until they push a fix
You can refere a github
instead of a nuget and that works as well ?
no but you can clone it, and refer to it as a local project
Ah yea
you can use Git Submodule if you don't want it to be outside of your project
I think i'll just add it to my repo and have it locally until fixed with license
Thanks for the fix
you're welcome
Altough I need to do stuff, and am already tired. Will try to fix Tapi tomorrow with it
Or maybe in the evening who knows
huzzah
probably not a meaningful change for us but just want you to know I added a small change to the fix. See https://github.com/BepInEx/BepInEx.AssemblyPublicizer/issues/19
yea, even just UIBuilderSystem uses Bindito, so needs recompiling.
The publicizer change is on Nuget now: https://www.nuget.org/packages/BepInEx.AssemblyPublicizer/0.5.0-beta.1
Neet
Whats the difference between the new 0.4.3 and 0.5-beta-1
It looks like only "Update to AsmResolver 6.0.0-beta.1"
Alright, seems the fix is in 0.4.3 so ill just uise that one

Fix 1 issue, get 99 back
Stupid bepinex feed
Probably just problem with my pc but still 

oof,
I had code that compiled fine for Update 6 a month ago, throw errors during compile (about missing assemblies, etc).
Nothing should have changed in that month, it's compiling against the same Timberborn code.

I changed from bepinex feed unity editor dll's to localized downloaded unity editor dll's they provide.
But those are not publicized so I got other errors, because apperently some are internal for the UIBuilder 
Dimension apears to be internal, not sure how that has not yet been a problem with modding though
@spring radish you were indeed correct, not sure if this was changed in the 0.7.0.2 version or I just missed it.
Because it complains about BuildingSpec. So how can it complain about that when mods suppose to not be loaded
Specifications should not do anything if a mod is not loaded
If I disable the mod it doesn't throw the error 
So it's enabled even though it's not started 
enabled, but the dlls are not loaded,
yea
for the missing refs, I can only assume that the .Net dlls for 0.6.9.0 and 0.6.9.4 are slightly different,
I think it's just a double bug. While ingame the assetsbundle stuff just looks am I enabled. Yes? okay let's go. Even though the modding scene has not been initialized
It's a bug in the option,
it shouldn't skip loading the dlls
based on eMka's response
@quiet delta Can this be fixed
? The new feature skipModManager which is only for mod developers should not skip the list and not start mods. It should skip the list with the pre enabled list.
Current:
public void Awake()
{
if (this._fileService.HasDocumentsPermissions && !ModManagerScenePanel.ShouldSkipModManager())
{
ModRepository modRepository = this.CreateModRepository();
if (modRepository != null && modRepository.Mods.Any<Mod>())
{
if (this.AutoStartingInEditor)
{
this.LoadModsAndStartGame();
return;
}
this.InitializeModManagerPanel((IEnumerable<Mod>) modRepository.Mods);
return;
}
}
this.StartGame();
}
Should be (pretty sure):
public void Awake()
{
if (this._fileService.HasDocumentsPermissions)
{
ModRepository modRepository = this.CreateModRepository();
if (modRepository != null && modRepository.Mods.Any<Mod>())
{
if (this.AutoStartingInEditor || ModManagerScenePanel.ShouldSkipModManager())
{
this.LoadModsAndStartGame();
return;
}
this.InitializeModManagerPanel((IEnumerable<Mod>) modRepository.Mods);
return;
}
}
this.StartGame();
}
They know, see #๐mod-users message and #๐คmod-creators message
@quiet delta, I am trying to use the [Context("Bootstrapper")]. But it gives me isn't instantiable due to missing dependency:. The context is working as I can log it but a child context can't use it's singletons.
Beforehand everything what was in the bootstrapper could be injected into a child. But this has changed or removed
.
I was using this to keep a cached version of the prefab specifications and just generate whenever there would be a new version available. Which for prefabs is never after the first time.
Small test
[Error : Unity Log] BinditoException: ChildPlay isn't instantiable due to missing dependency: TestingBootStrapper. Dependency chain: ChildPlay => TestingBootStrapper.
nope, new thing
Yep works
hmm
Don't understand the usecase compared to other behaviour 
Just making sure something isn't used outside of it I suppose
yes, something like that
Wait can I export it from MainMenu as well to Game
It will just be trashed right
Testing. Yeah it's not there anymore than
So it's just for bootstrapper ๐
yes, it should work for child context only, in our case Bootstrapper => the rest
Yeah but I could see something like
- Do some logic in main, push it to the other scenes
- Goes to
Game - Comes back to main, wants to refresh with a load state and push the new one to rest
No idea when you would want to use it
. But I also don't think it would be the weirdest thing
well we have to pass faction id or map name from main menu to game when starting new game, so maybe there actually are some use cases for this behavior 
Would help all with loading issues if before game configurators are loaded the faction was already known tbh.
Edit: forgot I changed the loading order to access prefabs so specs can be generated on it before anything else. This can't solve that
WTF
[Error : Unity Log] Exception: Multiple blueprints found for Timberborn.SoundSystem.AudioMixerGroupRetrieverSpec

How did it become multiple
Ahh, I at least got in game. With like 3 out of 6 dll's
harmony.Patch(
harmony.GetMethodInfo<FactionSpecService>(nameof(SpecService.Load)),
harmony.GetHarmonyMethod<EarlyLoadPatcher>(nameof(Test))
);
Struggled 30 minutes or so with this...
Patched the wrong class FactionSpecService -> SpecService
Time to fix the next bug
Enabling Tools system
I think it crashes on generating them 
Make sure that there exists at least one spec that you are trying to get from SpecService, because there is a bug that it will throw NRE if it won't find any
although I knee that. It feels not the issue. Since my patch isnt being called that should prevent that method call.
But also have not yet tried to fix the generators so.. maybe
Timberborn.BottomBarSystem.BottomBarPanel.Load () (at <5554b898465f4cbcb2aad4741c1f9eb3>:0) This is so confusing
harmony.GetMethodInfo<BottomBarPanel>(nameof(BottomBarPanel.Load))
I am patching that method, but it's not logging
If I do the patch in a different location it works
But this one is special because it needs to unpatch when it's not ingame
Except it looks like it's not even patching anymore while registring the patch...
Okay, so the patch is somehow too slow. Even though the patch method is called before the crash 
Yashhh
I think I patched the wrong class previously when testing
But I changed the SceneManager to ContextManager which will trigger when a new context will be loaded.
Since Timberborn now also uses their [Context] attribute the scene manager patch is not as early as before which failed to patch a configurator
New error unlocked 
We're finally at the not completely converted Spec's. So almost fixed I think.
oh? So some steady (albeit annoying) progress
@quiet delta, I might have a small problem with the new blueprint system.
You are only allowed to have 1 typed name (only class name counts namespace is excluded).
Extending with that I cannot use a existing spec and extend onto it.
Do you know if it still might be possible to create an extension of a blueprint somehow?
public record TimberApiToolGroupSpec : Timberborn.ToolSystem.ToolGroupSpec
{
[Serialize]
public string Type { get; init; }
[Serialize]
public string? GroupId { get; init; }
[Serialize]
public string Layout { get; init; }
[Serialize]
public string Section { get; init; }
[Serialize]
public bool DevMode { get; init; }
[Serialize]
public bool Hidden { get; init; }
}
maybe I could just add a seperate spec with the additional data and fetch that from within ToolGroupSpec. This should not create problems right
And I can go from either way, from the additional data spec to the ToolGroupSpec
idk, if it isn't possible it will have to be in the future, because building's specs are using inheritance ๐ค
you can try using SpecAlias attribute
but I doubt naming is the problem here
Naming of the probs are not the problem. Just double names of the spec classes
I don't think inheritance in itself is a problem. But previsouly I used the ToolGroupSpecification files with a different deserializer. Since that's not automatic I can say I want to have all ToolGroupSpec's but convert it to my class instead of the Timberborns class.
Which I don't think you guys would need in the game since it would just be a completely new spec with additional data. Instead of the same spec with data added
If that makes sense ๐
Ok, but what's the problem here? Provided example doesn't work?
I don't know how I can use the TimberApiToolGroupSpec with the ToolGroupSpec files.
If I rename TimberApiToolGroupSpec back to ToolGroupSpec it just crashes.
, Expected making a ToolGroupExtensionSpec would be a bit smoother.
foreach (var toolGroupSpecification in toolGroupSpecificationService.ToolGroupExtensionSpecs.OrderBy(x => x.Layout).ThenBy(x => x.GetSpec<ToolGroupSpec>().Order))
Does not quite feel nice
And you want the game to perceive TimberApiToolGroupSpec as ToolGroupSpec? So when something calls ISpecService.GetSpecs<ToolGroupSpec>() it should return also your specs?
or is it something else
Yes
Preferably, the game can just run fine with their logic and me not needing to patch usecases where ToolGroupSpec normally would be used.
I just want to add extra params to an existing spec.
in that case I think the best approach would be to add new specs (components) to the blueprints with original ToolGroupSpec
Ye that's what I am trying to do now. But I need to do quite some .GetSpec<XXX>() within loops, which don't seem very nice to do. Not sure what the performance impact would be though.
I don't think they are mostly in loadable singletons so it doesn't have that much of an impact.

(โฏยฐโกยฐ)โฏ๏ธต โปโโป
GeneratedSpecs are now later than the SpecService... but it caches now instead of getching it on demand with the IAssetLoaders
How am I going to update the SpecService with generated specs
not sure if you like this approach but in one of my mod, writing a Bindito.Core.IContainerDefinition.Unbind helps a lot ๐
Not sure how that would help
I need the SpecService, to add to an existing spec. But how can I need it and generate it
think of it like Harmony patching but with official capacity (i.e. you are not stuck with a static method)
if SpecService doesn't let you expand on it officially, you can Unbind it and wrap it with your own implementation. similar to Decorator
That would not solve that I require it to be active before the generator can be active
Either I am writing it wrong, or you are reading it wrong 
The SpecService needs to be ran before the generator can be ran due other dependencies for the generator. So I cannot just unload it
but you can inject yourself to prepare for it? I am not sure what generator is but if it's inside the DI system still, then I don't see why not.
in that case, inject yourself before/wrap the generator?
It's a dependency loop
that's impossible. something has to be before something else ๐
Well with this update it now has to be at the same time. Or I need a way to add to it later on
anyway after I am done with this mod, I am happy to look at it if you still need some manpower ๐
Maybe something with modified blueprints, but i don't understand how to use that yet
I am working with the Specs thingy right now
but I have Harmony so it's a bit easier for me
Same but also won't solve this problem ๐
@cinder fern You know the usecase and how to use the ModifedSpecs option is for ?
Since it looks like if you still use GetSpecs it doesn't do anythin
for the Faction needs?
not sure why, that's the only code point I see is invoking it
I think I have seen something before... that uses something similar... I can't recall it
Are you providing generated specs using custom IAssetProvider? If so it should be loaded before SpecService
Yes it should, but I can't know to which groups they should be added automaticly without it
Unless maybe just using the asset loader and just checking the names 
@stone shoal Remember, long time ago, in TAPI, the sliders didn't have the horizontal line visible? At some point it got fixed. Did you do anything? Do you remember what?
Wasn't that a problem at unities side ?
I didn't change anything
idk, I just recall there was the problem, and then it gone. In the meantime, while you're fixing TAPI for U7, I thought I can quickly make styles for MixMax slider myself. It works fine in Unity, but not in the game.
With just unity USS ?
Btw, they have fixed the nasty behavior of MinMax slider: https://discussions.unity.com/t/unity-6-uitoolkit-layout-update-is-struggling-to-process-current-layout-with-minmaxslider-in-editor/1538464/7 I didn't even expect it.
That's neet
Yes. I create Minmax Slider in Unity, apply styles and the preview works fine. When I make the asset and load it in the game - no horizontal lines.
Maybe timberborn makes it invisible
It has a global thing to remove all styling of unity at first
Or maybe its disabled with an option idk
Hmm, if I read the code correctly, the asset is retuned as is from the load Unity method.
Hmm, obviously, the game does something to the controls. I just created MinMaxSlider and added my style that addresses the elements by their names (e.g . #unity-thumb-min). Clearly, the thumbs style worked (the sprites are there), but instead of the dragger controls, I got an empty button to the right. Hmm.
@quiet delta any idea what's happening here? Why cannot we just make a control and apply a style to it?
are you using uxml and uss files or is it generated by the code?
I tried both approach. First, I created uxml & style in Unity, then tried to load them via _assetLoader.Load<VisualTreeAsset>. It gave me the missing "lines" problem. Then, I tried to create the element directly and simply adding the style - same output.
var stylesheet = _assetLoader.Load<StyleSheet>("UI/Controls/TimberbornStyle");
var element = new MinMaxSlider();
element.styleSheets.Add(stylesheet);
The rectangle to the right of the control seems like a button 9-slice. And it definitely shouldn't be there. As far as I can tell, the #unity-dragger transforms into this thing when the height is large enough (10-20px), when it's too small (1-2px), it's just not visible.
I think, I got it. Unity doesn't see the images. And it's really strange since it does see the thumbs images!
oh, ofc, I forgot about it. It's one of my biggest problems with UI toolkit & modding - you can't define your own images in your uss files, as they can be only loaded from original Resources (or addressables iirc), so only the built in images can be set this way. You have to set backgrounds/sprites etc from the code
Also, for visual elements use VisualElementLoader instead of IAssetLoader. It will correctly call all initializers and create VisualElement to use for you
Using the existing images was what I has started from ๐ It didn't work, so I switched to my own images. I will try to use the stock images and VisualElementLoader now (which I think I did before, but just to be sure).
you can send me the uxml and uss you started with, I will take a look why the images loaded properly
Is the path UI/Backgrounds/bg-pixel-2 still actual?
I thought I had custom images working with USS
. If you use USS and UXML and the image in same project
Could be wrong
What does your uss look like ?
#unity-dragger {
background-image: resource('UI/Backgrounds/bg-pixel-4');
min-height: 4px;
height: 4px;
}
#unity-thumb-min {
background-image: resource('UI/Images/Buttons/circle-on');
min-width: 16px;
min-height: 16px;
}
#unity-thumb-max {
background-image: resource('UI/Images/Buttons/circle-on');
min-width: 16px;
min-height: 16px;
}
#unity-tracker {
min-height: 1px;
background-image: resource('UI/Backgrounds/bg-pixel-2');
}
It doesn't complain about the buttons. But it does about the backgrounds.
Maybe, I need to refresh the project ๐

Im not sure if it was a problem with USS as wel but I had a weird ass problem that it would not compile correctly if I had the UIBuilder open of unity
So, do you have your UXML UIBuilder open in unity while compiling ๐ ?
I do "build the mod " thing. I thought, handles all teh case. No?
I don't know what you mean with that
When you press that button, do you have the UIBuilder open of the UXML?
The editor of it, pretty sure it was called UIBuilder
Yes, and do you have this window open while clicking on it
This woodo is not of my level ๐คฃ
, I thought you were using UXML ?
I make resources in Unity, compile them, then load from the game.
Okay, save it. Close it and than press the build button
Did it many times before. I know about this unity thing to not saving stuff.

The error from the log, it says exactly what's wrong: the image is not found. Even though, it should be.
They are, but.... I just recalled that from the ripper I got all the stock game paths in the lower case. It's worth checking.
something must be wrong
Why does it say pixel-22
Can't remember there being that many
And i your USS you have bg-pixel-2
nvm, that was from your own
it should be 'UI/Images/Backgrounds/bg-pixel-2' (you are missing Images directory in the path)
trying...
It's a progress! The margins I can fix easily, but the "empty button" to the right makes me guessing. I didn't request it. Anyways, thank you @quiet delta !
So, we cannot use custom sprites/textures in the controls. Ack.
FYI the uss:
#unity-dragger {
background-image: resource('UI/images/backgrounds/bg-pixel-4');
min-height: 1px;
height: auto;
}
#unity-thumb-min {
background-image: resource('ui/images/buttons/circle-on');
min-width: 16px;
min-height: 16px;
margin-top: -6px;
}
#unity-thumb-max {
background-image: resource('ui/images/buttons/circle-on');
min-width: 16px;
min-height: 16px;
margin-top: -6px;
}
#unity-tracker {
min-height: 2px;
background-image: resource('UI/images/backgrounds/bg-pixel-2');
}
The path cases are different, but it seems it's not the problem.
there could be an additional IVisualElementInitializer, that would search for property like "--mod-background-image" and would load image from provided and set it, similarly to what UISoundInitializer is doing currently. Maybe it's something that TimberApi could offer, maybe it could be built in into the game ๐ค
My today's theme was: "TAPI is failing. Yeah, well. I'm gonna go build my own theme park. With blackjack and stuff". And... nope! 
I still need the "blackjack and stuff" from outside ๐คฃ
In fact, forget the park.
Never say "TAPI is falling", or, without More Group, bottom bar will be a disaster ๐คฃ
That would require 2 new image elements right
. One for with ninesliced and one without.
Can check it out if it's neccesary after I get TimberAPI back to be working
The SpecGenerator is just.... not wanting to go
For the spec generator I need the faction objects, which require the SpecService 
I have a similar problem, as I want to get rid of GetModifiedSpecs method, so the Blueprints would apply their modifiers themselves when calling GetSpecs.
so I may come with some solution
in a month or so xd
I still don't get why it exists and how it would be used ๐
Adding specs don't sound tooo hard (I think). But changing existing specs with the generated specs absolute no clue.
For example, adding my ToolGroupExtensionSpec into the existing ToolGroupSpec files.
oof, looks like a pain indeed, because all of this immutability.
Was it really slow so that it had to be cached ?
I didn't check it, it just felt right to cache deserialized blueprint instead of processing it over and over. On the other hand we didn't want to deserialize them all at once during the Load of each scene (mostly because invalid blueprints from the game would crash in main menu)
Yeah understandable
I myself like caching as well 
Maybe just additional functionality to addon to it or modify it. Altough that's probably more a modding requirement than a basegame one.
@quiet delta I know it's stupid but how comes that if I run SpecService.Load again after I cleared _cachedBlueprints it complains about a blueprint receiving it twice 
Is it cached at multiple places ?
Oh it does not even add a duplicate 
// Reloads the spec server, because everything is cached now. This is unoptimized but it is how it is for now.
// Might give problems with faction specs if they would have changed.
specService.GetType()
.GetField("_cachedBlueprints",BindingFlags.Instance|BindingFlags.NonPublic)!
.SetValue(specService,new Dictionary<Type, List<SpecService.CachedBlueprint>>());
EarlyLoadPatcher.BlockLoading = false;
specService.Load();
factionSpecificationService.Load();
EarlyLoadPatcher.BlockLoading = true;
Yes...
Well tomorrow I can fix the generators and see if it worked out
It's awefully ugly but, it's the only way I can see
If it works, sounds good
It seems to complain about "specs" being unproperly deserialized. Well obviously because they are still like the old specifications
But it at least tells that the generated stuff is actually loaded by the blueprints. Before the game can complain about specs
With the exception of FactionSpec. can't generate those ๐
That's the one that probably doesn't need to be generated at runtime anyway
Exactly
old:
var json = JsonConvert.SerializeObject(new
{
Id = prefab.PrefabName,
GroupId = placeableBlockObject.ToolGroupId,
Type = "PlaceableObjectTool",
Layout = !wonder ? "Default" : "WonderDefault",
Order = placeableBlockObject.ToolOrder,
Icon = labeledEntitySpec.ImagePath,
NameLocKey = labeledEntitySpec.DisplayNameLocKey,
labeledEntitySpec.DescriptionLocKey,
Hidden = false,
DevMode = placeableBlockObject.DevModeTool,
ToolInformation = new
{
prefab.PrefabName
}
});
new:
var json = JsonConvert.SerializeObject(new
{
ToolSpec = new
{
Id = prefab.PrefabName,
GroupId = placeableBlockObject.ToolGroupId,
Type = "PlaceableObjectTool",
Layout = !wonder ? "Default" : "WonderDefault",
Order = placeableBlockObject.ToolOrder,
Icon = labeledEntitySpec.ImagePath,
NameLocKey = labeledEntitySpec.DisplayNameLocKey,
labeledEntitySpec.DescriptionLocKey,
Hidden = false,
DevMode = placeableBlockObject.DevModeTool,
},
PlaceableObjectToolSpec = new {
PrefabName = prefab.PrefabName
}
});
I'm not 100% sure yet, but the thing I might dislike about the new blueprint system is the lack of default options.
Previsouly I could just fill any empty or missing properties. This way the whole spec becomes null so need to default it on multiple places.
Something like GetSingleSpecOrDefault returning a default class might be neet 
That way you can make the spec optional and act as if it would be on there anyway in places that would make sense
Use case example:
var json = JsonConvert.SerializeObject(new
{
ToolSpec = new
{
Id = "SettingBox",
Type = "GenericTool",
Layout = "GrouplessRed",
Order = 1000,
NameLocKey = "CAN NOT BE MODIFIED",
DescriptionLocKey = "CAN NOT BE MODIFIED",
Icon = "Sprites/BottomBar/Options",
DevMode = false,
Hidden = false,
},
GenericToolSpec = new {
ClassName = typeof(SettingBoxTool).FullName
},
BottomBarSpec = new
{
Section = 2,
},
});
The BottomBarSpec is in this case 2. But for almost all specs it's 0.
But that spec retrieved in multiple parts of the codebase, which all require a null check and defaulting to 0. Which is not handy when refactoring or if it is required in another place and need to check what the default value was again.
That said, you could argue why isn't it in the ToolSpec or just always add it.
Which in my scenario might just be unique, and the reason is that my ToolSpec isn't neccesary a bottombar. But it requires to be there as a default fallback
couldn't you assign a default value in the class?
oh, it's not a class, it's a record
the base game uses a class that inherits from BaseComponent
errr, for some specs
BasicDeserializer has a GetDefault function
ahh, you have to mark the field as optional,
eg: ```cs
[Serialize(isOptional: true)]
public int Section { get; init; }
Not the problem. I want the whole spec to be optional because it all has a default values.
But it needs to exist with the current system
ohhh, that would only work for
BottomBarSpec = new {},
Yeah
Which isnt much lf a problem for me generating. But I when creating a new tool makijg that required feels bit much
I was just thinking about it
Altough it can't be cached sadly, and needs to be on blueprint instead
That's how I "hide" my reflection
Why on blueprint instead of SpecService?
blegh, SpecService is internal
shouldn't be an issue if it's publicized,
SingleSpec in SpecService is wanting a single spec of all files.
I need to be on Blueprint for the GetSpec because I want to get another spec within a existing blueprint
why don't use use ?. accessors?
i.e. instead of blueprint.GetSpecOrDefault<BottomBarSpec>().Section I think it would be blueprint.GetSpec<BottomBarSpec>()?.Section
That would return a null
even if Section is an int?
what about blueprint.GetSpec<BottomBarSpec>()?.Section ?? 0 then?
Yes because section does not exist
This would indeed work. But as explained in use case, I require to do this everywhere I'll use any of this stuff
Requiring to check up a default value of an input whenever I need it.
And when refactoring it's worse
you mean when you want a default value that isn't the "zero" value?
Yeah
sounds like you want SerializeAttribute to have a default value?
no, then it defaults to the "zero" value,
I mean to set the default value to something else,
Can't you just fill in the default value and set it to optional. Then the default value won't be overriden ?
?
I mean something like:
[Serialize(default: 2)]
public int Section { get; init; }
public record BuilderPriorityToolSpec : ComponentSpec
{
[Serialize(true, null)]
public Priority Priority { get; init; } = Priority.High;
}
(isn't supported in the code at the moment)
I think this should work just fine right ?
I don't think records allow that
No, because it's not the class..
oh, because the spec is null,
GetSpec gives null.. so a default value in a non existing object will not
But with the extension method I can problably just add it
Check if it exists or create new
Altough who knows, maybe it is just better to let the users fill it in all the time 
Seems just a bit too much work ๐ , while it's 99% the same
so, you could do:
public record BuilderPriorityToolSpec : ComponentSpec
{
public Priority Priority { get; init; };
public static BuilderPriorityToolSpec Default = new BuilderPriorityToolSpec {
Priority = 2;
};
}
and with usage:
var p = (blueprint.GetSpec<BuilderPriorityToolSpec>() ?? BuilderPriorityToolSpec.Default).Priority;
kinda ugly though
I would prefer to make a GetSpecOrDefault method. Which would return a new instance of the spec when not existing
yea, you may even be able to define a way to register Spec defaults (maybe via a binding)
although it would be nice to define it near the spec,
like: Bind..UseThisFunctionToGetADefaultFor...ThisSpec
, idk if statics can be abstract. Otherwise I could maybe add a prop as a static for all my default componentSpec's