#TimberAPI
1 messages · Page 8 of 1
Yes
No, not anymore at least
Did the yml break?
imagen using github to host mods 
Github is usually THE place to get the LATEST update of anything.
its straight from the dev, no middle man, no steam, no bs
if the dev commits 
This is true. lol
I completely rewritten the codebase and the CI doesn't work on that anymore.
It requires game assets which is just anoying to update
I need to upload it to 2 other places already
It makes my local build more complex just to make CI also working
ah
No one looks at github releases anyway, had it automaicly upload to mod.io, but now there is a steam as well so at some point Ill just make a upload mod that can do both 🙂
Would you do me a solid and push this latest build to github so i can mess around with it and possibly contribute to the project if you want?
side note: downloading that steam updater thing now and testing that out.
It's pushed, but not going to help setting up your local env. Don't have the energy for that and it's alot of mess with this update
It's not super easy and straight forward setup
lol i'm good dude. I'm fairly competent with c#. 😛
Well it's a custom setup with some weird stuff 🙂
Well, this should be fun then. 😛
Because nuget of bepinex just decided to stop working so I needed something else
If i can't figure it out then screw it, but hey at least i tried right? lol
Bam it worked
thank you
also i didn't need that mod, simply closing it, unsubscribing, and resubscribing fixed it.
Which i did before i installed the mod. lol
hey whatever, it works now, idgaf how it works, it does and thats what matters lol
#1283367971280126087 should also allow you to force Steam to download updates for mods without having to unsubscribe, resubscribe
Yea, i'll test that next time. 😄
In that case it's pretty clear what the problem is and cannot be fixed at this moment
Maybe I will check if I feel enough for more complex problems. But so far there wasn't really a good other way
oh and I see it's not a Harmony patch, but actually Reflection:
specService.GetType().GetField("_cachedBlueprints", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(specService, new Dictionary<Type, List<Lazy<Timberborn.BlueprintSystem.Blueprint>>>());
EarlyLoadPatcher.BlockLoading = false;
specService.Load();
that's why you get a Null Ref there, the wrapped instance doesn't not have _cachedBlueprints
Ah yea doesn't get thru extension
hmm, am I doing something wrong here, I'm trying to add two NineSliceVisualElement with the UIBuilder,
I have their background images set differently, but the UI shows the same image for both.
it uses the sprite from the first element for both,
if I change the order in which I add them to the root, then the image changes,
eg
vs
and the only different is:
modItem.Root.Add(unavailableImage);
modItem.Root.Add(downloadPendingImage);
vs
modItem.Root.Add(downloadPendingImage);
modItem.Root.Add(unavailableImage);
it's weird because the NineSliceButtons next to them are fine,
isn't it the same visual element you trying to change ?
How did you create the elements ?
var unavailableImage = _uiBuilder.Build<UnavailableImage>("UnavailableImage");
modItem.Root.Add(unavailableImage);
var downloadPendingImage = _uiBuilder.Build<DownloadPendingImage>("DownloadPendingImage");
modItem.Root.Add(downloadPendingImage);
UnavailableImage uses unavailable-image as the class,
DownloadPendingImage uses download-pending-image as the class
Can you show the class in as hole
And did you add them as transient in bindito or singleton ?
as transient:
Bind<UnavailableImage>().AsTransient();
Bind<DownloadPendingImage>().AsTransient();
What do the classes look like from unavailableImage>
I think these are the applicable files you want
Yeah seems just fine
It's done how it should be
Need to sleep now, but can see if I can replicate it
modItem is just an empty visual element ?
It's the mod row in the mod list, so it has a checkbox, text element, and maybe Mod Settings button,
I can zip my working copy if that'll help debug, but I assume you'll want a smaller reproduction case anyways
you can also just apply those files on top of my git repo and comment out the parts that make the images optionally visible (because I didn't bother to include the files that detect the current state)
Didnt check your code much
But the ui oarts are build fine
Weird behavior. Can only rhink that kt has a reference to it or something
You dont have other mods enabled?
only:
- Harmony (v2.3.3)
- More Mod Logs (v0.1.0)
- Mod Manager (v3.0.4)
- Mod Settings (v0.7.2.0)
- TimberApi UIBuilder (v1.0.0.1)
- Steam Update Buttons (v0.1.2)
- Tool Finder (v0.0.5)
- Web UI (v0.1.4)
If I convert one of the images (both are NineSliceVisualElement), into a NineSliceButton, then the images show differently
of course it uses VisualElementBuilder instead of ButtonBuilder too then
The uxml looks correct:
<ui:Image name="ModIcon" class="unity-image mod-item__icon mod-item__icon--cloud" />
<ui:Label name="ModName" text="Web UI" class="unity-text-element unity-label mod-item__name" />
<ui:Label name="ModVersion" text="v0.1.3" class="unity-text-element unity-label text--yellow mod-item__version" />
<ui:VisualElement name="WarningIcon" class="warning-icon" />
<Style></Style>
<Style>.unavailable-image {
background-image: resource("sprites/statusicons/stranded");
}
.unavailable-image {
height: 28px;
width: 28px;
margin-left: 7px;
}
</Style>
<NineSliceVisualElement name="UnavailableImage" class="unavailable-image" />
<Style></Style>
<Style>.download-pending-image {
background-image: resource("ui/images/game/ico-child-grow");
}
.download-pending-image {
height: 28px;
width: 28px;
margin-left: 7px;
}
</Style>
<NineSliceVisualElement name="DownloadPendingImage" class="download-pending-image" />
<Style></Style>
<Style>.update-button {
background-image: resource("ui/images/buttons/migration/allow-emigration");
}
.update-button:hover {
background-image: resource("ui/images/buttons/migration/allow-emigration-hover");
}
.update-button {
--click-sound: "UI.Click";
height: 28px;
width: 28px;
margin-left: 7px;
}
</Style>
<NineSliceButton name="UpdateModButton" class="unity-text-element unity-button update-button" />
Yeah didnt feel like ot would be wrong
@spring radish did you already found the problem?
not really. I found that if I add unity-button class to one of the images (not both), then it behaves correctly.
so that's my workaround for now
@spring radish GetModListView does not exist
, is it an extension method of yours ?
Foudn iit in the github
Okay okay
I have it at least replicated
Altough I don't quite think it's much of a TimberApi problem, but more like how unity and USS work in combination 
It's not the cache stylesheet
It's not the creation order that matters either
yea, super weird
It's really just the position of the element
yea, I hide reflection in extension methods.
position?!?
in that first one wins, yea
Wym ?
in the image classes, add a line for AddClass unity-button
if you only add it to 1 image, then everything looks fine,
if you add it to both images, then there's an even weirder behavior
do you get the mouseover effect?
it's the 2nd image when mouseover, otherwise the 1st image?
I was just being dump, I didn't go to mod list in the main menu was just looking at startup mod list
Ah yeah, but if you only have 1 .AddClass("unity-button"). Then it works good
I wondered if it's the number of classes, but nope it has to be that specific class.
or at least adding unity-text-element instead doesn't seem to have any effect
I'm wondering if it miight be a Unity bug,
Yeah checking that out now
btw, I noticed that UIBuilder seems to add an empty Style element. Is that accurate, or does the UXml dumper I'm using missing something.
Saw that too, no idea why it would do that
I would only expect an empty one if you didn't add styling to it. But not when you do
yea
But maybe if you initialize an element with new it already has an inline stylesheet or something
hmm, I could move the styles into one class, then it would put them into a single style element right?
Yes but they should not work on other elements, at least that was my expectation always
But with the exporter it feel different, altough the exporter might not represent the whole truth 
Since the stylesheet is linked to the object and when exporting it isn't anymore
<Style>
.download-pending-image {
background-image: resource("ui/images/game/ico-child-grow");
}
.download-pending-image {
height: 28px;
width: 28px;
margin-left: 7px;
}
</Style>
Doesn't even feel like it works in unity 
ack, yea, moving it to other classes doesn't work
Okay the <style> brackets don't work in the unity editor at all
So I think that's just an export visually wrong
The style's I create should react as files anyway just the same as other StyleSheets
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:tb="Timberborn.CoreUI" xsi="http://www.w3.org/2001/XMLSchema-instance"
engine="UnityEngine.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd"
editor-extension-mode="False" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="Timberborn.CoreUI file:/G:/Development/Timberborn/TimberPrint.Unity/UIElementsSchema/Timberborn.CoreUI.xsd">
<ui:VisualElement>
<Style src="/Assets/Mods/TimberPrint/AssetBundles/Resources/UI/Views/Poggies.uss" />
<Timberborn.CoreUI.NineSliceVisualElement name="DownloadPendingImage" class="download-pending-image" />
<Style src="/Assets/Mods/TimberPrint/AssetBundles/Resources/UI/Views/Poggies_other.uss" />
<Timberborn.CoreUI.NineSliceVisualElement name="DownloadPendingImage" class="unavailable-image" />
</ui:VisualElement>
</ui:UXML>
This looks fine
yea
as you say the uxml export is probably wrong
It's something I added to the Unity code
because it didn't have it,
Ah okay
Altough if I export them to files and import it in the UXML as I think it would convert to ingame
It seems to work
Soo.... maybe I still do something wrong
But I don't have the mental energy to go deeper atm. For me it's already a wonder I came this far
If you want to test something, you could test like making a fragment in game. And than adding those 2 elements in there and see if it's the same behaviour
Otherwise it's maybe something with that box that conflicts
You can also as a workaround just set the image to the object itself as you would do with the older UIBuilder with the IAssetloader. Pretty sure this can't go wrong
Very weird bug though 
I'm not sure I understand the workaround,
so it's not just the background image, because I tried setting a different width
and it affected both
if I put the images outside of the ModItem row, it still reproduces,
It's so weird...
Like sure if it had the same classname I could maybe see that it become global or something
But it's not even the same class
yep
also reproduces if I add it at the bottom of the main menu list,
so it's not something from the mod panel
Hmm than there is something broke with it I guess.
Altough I had so many elements next to each other while testing and nothing was wrong
Most presets are buttons or something though
yeaaa
and I haven't tried testing on Update 6, just to get a different Unity version
I didn't have two images next to each other no
Ahh
I only added that today
back-porting the commit to update 6 wouldn't be impossible, just have to deal with a couple of merge conflicts,
public class UnavailableImage(IAssetLoader assetLoader) : BaseBuilder<NineSliceVisualElement>
{
protected override NineSliceVisualElement InitializeRoot()
{
return UIBuilder.Create<VisualElementBuilder>()
.SetStyle(style =>
{
style.backgroundImage = new StyleBackground(assetLoader.Load<Sprite>("sprites/statusicons/stranded"));
style.width = new Length(28, Length.Unit.Pixel);
style.height = new Length(28, Length.Unit.Pixel);
style.marginLeft = new Length(7, Length.Unit.Pixel);
})
.Build();
}
}
public class DownloadPendingImage(IAssetLoader assetLoader) : BaseBuilder<NineSliceVisualElement>
{
protected override NineSliceVisualElement InitializeRoot()
{
return UIBuilder.Create<VisualElementBuilder>()
.SetStyle(style =>
{
style.backgroundImage = new StyleBackground(assetLoader.Load<Sprite>("ui/images/game/ico-child-grow"));
style.width = new Length(28, Length.Unit.Pixel);
style.height = new Length(28, Length.Unit.Pixel);
style.marginLeft = new Length(7, Length.Unit.Pixel);
})
.Build();
}
}
You don';t have the code anymore from update 6? otherwise you only need to add a dummy image. nothing needs to work or something
You could use it as this as well. It's not my recommended way, this is how it technically was done in older versions. It's just reletively slower. Altough in your case that won't matter that much since it's so little
I have the code in a git repo, so I can just switch to the old branch and cherrypick the commit,
I suppose
. I thought of just copying the 1 extra element and adding it without additional functionality
mmm, it's about the same amount of work to do it either way
I want to fix it but don't even know where to start and can't really think clearly anyway
the conflict is in the Configurator more than anywhere else,
Of the bug or the work ?
to do the cherry-pick
okay, so in Update 6 it does not reproduce
with TimberApi (v0.7.8.0)
but I assume the UIBuilder didn't change between u6 and u7?
The only difference is that it's not included in TimberApi anymore
So it is a unity bug. Funny 😛
Altough it's hard to complaing about it to unity, if I can't replicate it in the unity builder
Maybe I need to export it to an asset bundle and try to load it ingame and see if that replicates the bug
Oh... I haven't updated my editor!
Installing it, will check out if the bug can be replicated in the editor than
Thanks for testing it in previous version, to be fair didn't expect it to work
. Thought it was just a me problem
Correct on 6000.0.16f1, Broken on 6000.0.41f1
I don't know that I care enough to try on whatever 0.7.1 was built with (6000.0.36f1),
IDK
Will test it in unity if it's broken I need to see if newer versions is still broken gotta make an post to unity
Otherwise asking pmduda to update unity version 
That's why I was thinking to try 6000.0.36f1
How you know its broken on 0.16f ?
0.6.9.4 uses 6000.0.16f1 and doesn't require the work around
0.7.2.1 uses 6000.0.41f1 and does the wrong thing without the work around
If I didn't delete the backup of 0.7.1 yet
You have the game backed up with updates 😛 ?
for experimental yes, in case it breaks in horrible ways
I can rollback
yea, I still have a backup of 0.7.1.2 which uses 6000.0.36f1
So which editor version were you testing on?
oh, I thought you said you hadn't updated it 👆
Yeah I am testing it now
which version did you test on earlier?
very
Im on windows
yea, let me copy the buggy version to my windows machine to test
same issue
so it's not wine then
hmm, how do I get Steam to launch the game without updating it,
offline mode?
No clue
6000.0.36f1 shows the same bug
Trying to test UXML ingame
They are invisible and I don't know why 
Ah okay found out why

It works
Dangit
So they changed something, somehow, somewhere
Otherwise it should not work in neither versions
@spring radish, for now I think best thing to do is just use the work around. If i'm feeling better (hope some day). I might recheck if I can extend it, and maybe test next week some more and post something on unity for it.
I tested a UXML example with 2 UXML files that only has a stylesheet + the visual element and it worked out
The only difference I can think of is that the stylesheet is not loaded inside the element in the unity's way. But I place the stylesheet in the element.
But... it kinda should be there 
The Visual element doesn't have the stylesheet in this scenario, but the container from the UXML has
Okay even if I add the stylehssets manually to the element when just using the element it seems to work fine...
Then my stylesheet is just different somehow currently
Thanks unity 🌈
hmm about the issue with Moddable Bindito, right now even if I provide _cachedBlueprints, there is no way for you to modify it anyway because you set it through Reflection
so my code cannot provide that field even, because I can't know when you set it and so set the actual instance with it too
unfortunately I can't really do it from my side, no way to patch it. maybe you can check if that one does not exists, you check for wrapped._cachedBlueprints instead?
Does it need to actually be replaced with a new dictionary? Could it just be Cleared instead?
because then you could add a _cachedBlueprints field to your override and set it to the same instance as the wrapped class.
yeah I could do that but I need support from TimberApi. right now it's just a plain set from Reflection so I can't do anything 😛
Well because its done woth reflections it should work. Instead the other way around
If I just casted the instance it doesnt know. But now it just checks for that field in the current instance
The class should just have a _cachedBlueprints which should be used for it's blueprints
Even if I remove the glunky code part needing to reload the blueprints. It still requires access directly to the cachedBlueprint to add my blueprints to it
.
If there would be an AddBlueprint it would maybe be possible. But that doesn't really make much sense for Timberborn to do.
can't you just clear it instead of replacing it entirely?
you can still access it right?
What is the difference between replacing and clearing... It's crashing because it doesn't exist

Yeah I think I can
when you replace it, (by using Reflection's SetValue), there is no way for my code to provide any way for you to "connect" it back to the original instance.
if instead you use GetValue for example, and Clear it, I can make a _cachedBlueprints field and refer to the original one
But I don't want to keep this code alive for always though. This was more a workaround to quickly fix for experimental. Later on I want to add new values.... which is totally duable the moment I am typing this
Can I do a cast like (SpecService) even if it's your wrapper class ?
no unfortunately not.
well... easiest would be, check if _cachedBlueprints exists, and if not, look for wrapped._cachedBlueprints instead. but then it's too specific just for my mod 
How can I check for wrapper
wait let me check your code again
I ain't going to add your mod as a dependency
to see where you actually apply it to
GeneratedSpecLoader
no, not if you are using reflection

I see
Would make it more confusing than just use reflection directly
Then it's like why do I do first a null check
specService.GetType().GetField("_cachedBlueprints", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(specService, new Dictionary<Type, List<Lazy<Timberborn.BlueprintSystem.Blueprint>>>());
so, you are looking for _cachedBlueprints in the specService. this I can provide. but the latter part, the SetValue call, I can't because there is no way for me to know it.
so, instead, you can call GetValue, and then call Clear()?
so it would be
var dict = specService.GetType().GetField("_cachedBlueprints", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(specService) as Dictionary<Type, List<Lazy<Timberborn.BlueprintSystem.Blueprint>>>;
dict.Clear();
Yeah have that in the zipped version
or you could use the way I use in #1357827899931234426, everyone is happy! 
and I suppose I have to keep it private right?
No? Why? Has nothing to do with my thing. And then I need to add your mod as a dependency ?
I believe so yes
no, I mean, if you want stuff to run before the ISpecService Load
then just inject yourself as a dependency, not that you add my mod.
What?
And I don't want to do stuff before ISpecService load
If I would just wanted that I just use my singletonloader that loads before ISingletonLoader
alright, that looks good, let's try it now
so users need to update both TimberApi and Moddable Bindito
If it works I can upload it
MissingMethodException: Method not found: bool Timberborn.WorldPersistence.ISingletonLoader.HasSingleton(Timberborn.WorldPersistence.SingletonKey)
wow...
that's a huge change
Timberborn change ?
yep new update
yep can confirm Moddable Bindito + TimberApi can run together now. no idea if any mod can actually use it but at least no more crash 😂
I will upload it now
This change is fine, doesn't change much on my end.
Only bit annoying is when I'm gonna fix this I probably can't just cast it which makes code uglier 
Gonna try it anyway, maybe it just checks for the field anyway and the cast is just comiler complaints
@stone shoal to bad this does not work would do it cleaner with one file for both base game and tapi to set toolgroup
Doesn't it ?
or i did something wrong but the error message tells me no
I guess that makes sense 
well will do 2 files for now but would have been neat
But why are we allowed to have files with unknown specs though 
it hard crashes
for Toolgroup 😉
when i splited it up to 2 files it loaded so not the content but what types is allowed for toolgroup 
wait this was without timberapi installed just the file so base game does not allow the added type
so it needs to be 2 files as otherwise basegame crashes
Yeah the base game doesn't allow it
But can't you just remove everything except the GroupId from the TimberApiToolGroupSpec ?
hmm ya true as thats the new info needed, but its still 2 files so not sure its worth the hassle
Forwarding here for more visibility. I’m pretty stuck at this point so any advice would be appreciated.
Reference files I’m trying to upgrade: https://github.com/Yurand2000/timberborn-timelapse-camera/tree/main/UI
Okay, so I figured a lot of this out so far, but now I'm stuck again.
The old code had this: panelBuilder.AddComponent(panelContent.Build()); where:
UIBoxBuilder panelBuilder = uiBuilder.CreateBoxBuilder() ...
and
var panelContent = uiBuilder.CreateComponentBuilder().CreateVisualElement();
but I cannot for the life of me figure out how to get the panelBuilder to add the panelContent to it
maybe this?
panelBuilder.AddComponent<FragmentBuilder>(_ => panelContent);
#🤖mod-creators message
If someone has a chance to help me here. I got this far but it isn't working. I feel like I'm missing something since the old code has SetFlexDirection and such but the only place I can see it in the current UI Builder code is in the BaseElementBuilder but no idea how that's supposed to work
What part dont you understand or are stick on?
I have actually mostly got it working 🙂
I just now cannot decipher how to make the text white (light?)
#🤖mod-creators message
SetColor I think 
I had completely missed that VisualElementBuilder exists so when I fixed that part (instead of FragmentBuilder in the Panel and BoxBuilder in the Interface) it got me to that
12:22:49 TimberApi.Tools.ToolSystem.ToolService.Load() failed after 00:00:37.8202104 😭
New update?
when does it happen for you?
i am able to load into a game with tapi 
my mod list:
Modded: true, official
- Harmony (v2.3.3)
- More Mod Logs (v0.1.6)
- TimberApi (v0.7.12.1)
- Bob Platforms Extended (v0.7.1.0)
- Bobingabout Script Pack (v0.7.5.0)
- Bob Storage (v0.7.1.0)
- Automation (v2.0.6)
- Mod Settings (v0.7.2.0)
- Configurable Tubeway & Zipline (v7.3.1)
- TimberApi UIBuilder (v1.0.0.1)
- Cutter Tool (v0.7.1.2)
- DamDecoration (v4.0.0)
- KnatteMaterials (v2.1.0)
- DamDecorations_DecorationExtention (v4.0.0)
- Emberpelts (v0.7.4.0)
- Employment Manager (v0.1.3)
- ExtendedFloodgates (v2.0.1)
- Forest Tool (v0.7.2.1)
- Frog Statue (v3.1.1)
- Goods Statistics (v0.7.3.1)
- Mod Manager (v3.0.4)
- MoreGroups (v3.0.3)
- Path Extention (v3.0.3)
- Planting Override (v0.7.3.1)
- SmartPower (v1.13.3)
- Staircase (v3.0.4)
- Steam Update Buttons (v0.1.5)
- TimberUi (v7.2.0)
- TImprove 4 Modders (v7.2.0)
- Tool Hotkey (v7.1.1)
- Water Extention (v3.0.2)
- Water Extention PowerEdition (v1.0.3)

should be one of these:
- Bench
- Birch
- Bobingabout Vertical T Power Shafts
- Bobingabout's Housing Optimize
- Construction Queue
- Convenient Large Water Wheel
- BuildingPath
- Dirt
- Ladder
- Ladders for Emberpelts
- Live at workplaces
- Lunch Break
- Mixed Beavers
- Configurable Growth
- Configurable Pumps
- Faster Underwater Movement
- Minimap
- Moddable and Unlockable Recipe
- No more Breeding Pods
- Pipette Tool
- Super Cursor
try pipette tools? (as that add to toolbar?) but automation works :S
Pipette tools could be, since even in previous 0.7 version failed to add icon in the toolbar
compered our mod lists and got a list of one you have but not me 😛
It's not Pippete tool ! Still working
Sooo... It's not broken?
It seems OK, you can breath again 🤣
Map Editor fails to load with TimberApi
Bug maybe in the box builder code?
TimberApi.UIPresets/Builders/BoxBuilder.cs
29: protected string BackgroundClass = "api__box--nontransparant";
168: .AddClass("api__box--nontransparant", builder => builder
172: .AddClass("api__box--transparant", builder => builder
Should this say transparent and nontransparent (not transparant)
I don't get it 
transparant is in the code
transparent is the correct spelling of that word ?
I guess not a bug, but a typo
@nurmr helped me here: #🤖mod-creators message
Yeah, but might be better if you didn't have to do that 😛
Ad could just do .Transparent or something
Yeah, like how the GameLabel has .Header()?
Yea
Just easier, unless you have to do it 100 times you can make a preset of it for yourself ofc 😛
Yeah, going to work on cleaning up my UI code tomorrow perhaps
Random question, is there a non-tapi way to do this?
var singletonLoader = DependencyContainer.GetInstance<ISingletonLoader>();
I used it because it was how the original code loaded items from the save file
Is it in a harmony patch ?
Than just retrieve it with depndency injection
Oh I see
like:
private readonly UIBuilder _uiBuilder;
private readonly ModManagerBox _modManagerBox;
private readonly ModRepository _modRepository;
private readonly ITooltipRegistrar _tooltipRegistrar;
private readonly VisualElementLoader _visualElementLoader;
private readonly IAssetLoader _assetLoader;
public TestClass(UIBuilder uiBuilder,
ModManagerBox modManagerBox,
ModRepository modRepository,
VisualElementLoader visualElementLoader,
ITooltipRegistrar tooltipRegistrar, IAssetLoader assetLoader)
{
_uiBuilder = uiBuilder;
_modManagerBox = modManagerBox;
_modRepository = modRepository;
_visualElementLoader = visualElementLoader;
_tooltipRegistrar = tooltipRegistrar;
_assetLoader = assetLoader;
}
yeah, I learned how to do that between writing that line and asking now 😐 (I just didn't realize it was part of DI)
@brisk ether Not sure why I made a non transparent the default. Are boxes default more transparent thatn non 
The ModSettings boxes are transparent. The boxes for the buildings on the right are not
The Well-Being Overview is transparent
The Settlement Management panel is mixed
It is

I guess i make it transparent by default
Even thoug the method NonTransparent really gives me itches
maybe call it Solid or Opaque?

I like solid but would it make sense ?
w/e it's not that NonTransparent will be used much I suppose 😛
Could you make test it with the method and without
Fixed the typo so your override should break with it 😄
Yeah one moment
But yeah, now my mod only has dependencies on ModSettings and TimberApi.UiBuilder 🙂
(Nothing against Tapi, just didn't need it if I can use DI for things)
Everyone trying to remove Tapi 
😛
But yeah the UIBuilder probably will barely ever break
Ok i've set everything to upload
testing now
It would help if I put the updated mod in my mod folder instead of just the dlls in the project 😰
nice
So, using NonTransparent makes it transparent
Nice
Might forgotten to change the strings
Im gonna go to the market, will upload afterwards
Updated
TimberAPI seems to (sometimes? always? unsure?) sort Solid Power Shaft before the regular Power Shaft
they both have _toolOrder: 29
looks like a game issue, we will fix it in one of upcoming updates
eh, if it sorted in alphabetical order then it would be fine.
but adjusting it in the game will fix it too
Wasnt this already a long time 
Pretty sure ive said something about same order before
Bug in TimberApi UIBuilder or did I do something wrong here?
var panelContent = _uiBuilder.Create<DefaultListView>()
.SetName("CameraList")
.SetMakeItem((Func<VisualElement>)(() => {
var ve = _uiBuilder.Create<DefaultListViewItemWrapper>();
ve.ModifyRoot(builder => builder
.AddComponent<VisualElementBuilder>(veb => veb
.AddComponent<GameTextLabel>(lbl => lbl
.SetName("TextTestLabel")
)
)
);
return ve.Build();
}))
.SetItemSource(_screenshotService.CameraData)
.SetBindItem(
(Action<VisualElement, int>)((ve, i) =>
ve.Q<Label>("TextTestLabel").text = _screenshotService.CameraData[i].CameraName)
);
Ignore the mess, I'm still working out how this actually works
Bug in my thinking 👆
I had to make a class that inherited DefaultListViewItemWrapper and now it works 😄
Not sure, but might be true
Could I get some guidance on this?
#🤖mod-creators message
You mentioned that the 2 classes are not required. but when I try to not have the two classes, I get various errors I can't make sense of.
Or I get a recursive stack overflow with 200k lines and a 30 MB log file
It's possible I just don't know enough about C# yet and it's a simple thing I'm missing but I just don't get this
The log in question here:
I think the "base type" should be NineSliceButton (or some other base class), not the subclass
i.e. MyClass : Button<BaseClass>
not MyClass : Button<MyClass>
and calling UIBuilder.Create<BaseClassBuilder>()
So maybe try class TimberLapseButton : LocalizationButtonBuilder<LocalizationButton>?
Thanks 🙂
I tried that and Rider doesn't like it either.
And then this doesn't work right either:
panelBuilder.AddComponent<TimberLapseButton>(
builder => builder
.SetLocKey(TimberLapseSetCamerasButtonLoc)
.SetName("SetCamerasButton")
);
If I remove the <LocalizableButton> part, the button class no longer throws errors but then the other errors persist
This seems to work so far, about to go test it in the game
Yeah, that worked. Thanks @spring radish 
I'm excited to have a single button class for my code that can be adjusted instead of making 3 different classes or endless gross looking repeated tweaks to the presets
So the trick was BaseBuilder<LocalizationButton>?
Yeah, it seems so
I played around with ~10 different things until Rider "approved this message"
Lol
What
Bad joke I guess
i.e. until Rider stopped complaining and compiled the code without error.
Is it intentional that the only UI preset sliders in the UI builder code that has a SetValue method are
GameMinMaxSlider and GameTextMinMaxSlider?
I can and probably will write my own eventually, but it feels weird that the other preset sliders don't include this by default
panelContent.AddComponent<GameTextSliderInt>(
builder => builder
.SetLowValue(TimberLapseFrequencyHelpers.FrequencyMin)
.SetHighValue(TimberLapseFrequencyHelpers.FrequencyMax)
.ModifyRoot(
sBuilder => sBuilder
.SetStyle(style => {
style.marginBottom = new Length(10, LengthUnit.Pixel);
})
.SetValue(TimberLapseFrequencyHelpers.ToInt(_timberLapseManager.Frequency))
)
.SetName("FrequencySlider")
);
No clue
Maybe it was a mistake
Not a big deal either way.
Minmax slider was also just a bit of a quick thing kf why not
And then it was instantly used
Lol
Can you share the full crash log?
KeyNotFoundException: The given ToolGroupId (subgroup_thoseplatforms) cannot be found.
Maybe an issue with that mod Those Platforms?
Thanks. I'll try to talk to that modder
You’re welcome.
Oh, someone already mentioned to that mod.
0
Add BottomBarSpec to your blueprint
with Section 0
You know how blueprints work ?
Yes and no
bc i know how single layers work
but that spec in spec shit
no clue xD
bc its not clear from the code
Just add the second one in the same file
as there is no bottombarspec field in ToolSpec
also doesnt work for me?
I might have added incorrectly
Have you added with timberapitoolspec?
Sorry, forgot to mention it works now 🙂 added the thingy TheBloodEyes mentioned
Thanks @vast otter 
Thank you @stone shoal Im foverer in your favor, my favorite modder much loves
@stone shoal are the tool specification files required to have unique names even if they are located in separate folders? I had several files named ToolGroup.json in the blueprints hierarchy, and got errors during the load.
250509T005954.929 [EXCEPTION] [TimberApi.Tools.ToolGroupSystem.ToolGroupService.GetToolGroup] KeyNotFoundException: The given ToolGroupId (automationsignalstoolgroupid) cannot be found.
at TimberApi.Tools.ToolGroupSystem.ToolGroupService.GetToolGroup (System.String id) (at <5b41fe7e63b344c19c0564b729944abe>:0)
at TimberApi.Tools.ToolSystem.ToolService.Load () (at <5b41fe7e63b344c19c0564b729944abe>:0)
at (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.Timberborn.SingletonSystem.SingletonLifecycleService.LoadSingletons_Patch2(Timberborn.SingletonSystem.SingletonLifecycleService)
at (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.Timberborn.SingletonSystem.SingletonLifecycleService.LoadAll_Patch1(Timberborn.SingletonSystem.SingletonLifecycleService)
at Timberborn.SingletonSystem.SingletonLifecycleUnityAdapter.Start () (at <ba126410857740d8933279b72b4b61c8>:0)
There are no other errors that would tell that there is a file name collision. The issue got resolved when I gave unique names to the toolgroups files.
I believe so, thats just how specifications worked. I don't think that changed when it changed to blueprints
Every same name file is getting merged
But I am bot 100% sure. Mayke Enka made it so that path is included if it should be merged
Well, if the file name is used to merge the blueprints, then making it unique is a must.
@stone shoal Does TimberAPI still have PickObjectTool?
Yes, i do believe so. But not 100% sure if iI quoted it out
Hmm, can't seem to find it
my VSCode didn't find the reference and neither did I find it when using ILSpy. Found it in the github tho, so I'll probably copy it from there and try to add it to my mod
There were probably too much stuff broke at that point and me not being able to program really for last 6 months
I can always just readd it if it works
I hope to be able to fix the temp disabled features by next month if the recovery keeps going
all the best to you my friend
True
So I have a question:
I have a few UI Classes I made BatchControlLabel and BatchControlNineSlice to be able to use the style sheet builder code (among a few other reasons)
But I'm a little confused what the correct way to write AddComponent methods on the Nine Slice class is. I have the following (incomplete) code where I want to build the UI out:
var rootBuilder = _uiBuilder.Create<VisualElementBuilder>()
.SetFlexDirection(FlexDirection.Column);
rootBuilder.AddComponent<BatchControlLabel>(
builder => builder
.SetLocKey(HeaderLocKey)
.Header()
);
var headerBuilder = _uiBuilder.Create<BatchControlNineSlice>()
.SetFlexDirection(FlexDirection.Row);
headerBuilder.AddComponent<BatchControlLabel>();
rootBuilder.AddComponent<BatchControlNineSlice>(_ => headerBuilder);
var root = rootBuilder.BuildAndInitialize();
return new(_eventBus, root);
But if I want to add components to the headerBuilder like I did for the rootBuilder, the attached image was what I found in the BaseBuilder class but it throws an error.
Am I missing something obvious with C#/TApi UI Builder code here?
The rest of the class from the photo above :
Why not use the AddComponent from the base builder and just pass the data thru ?
Because I'm a newb and not sure how to do that 😰
I added another AddComponent though so you can add builders into it. Now you have to add a .Build to it
Instead of Root.Add There should be a AddComponent IIRC
This?
public BatchControlNineSlice AddComponent<TComponentBuilder>(Func<TComponentBuilder, TComponentBuilder> builder)
where TComponentBuilder : BaseBuilder {
_bcNineSliceBuilder.AddComponent(builder);
return BuilderInstance;
}
public BatchControlNineSlice AddComponent<TComponentBuilder>() where TComponentBuilder : BaseBuilder {
_bcNineSliceBuilder.AddComponent<TComponentBuilder>();
return BuilderInstance;
}
Yea
💯 thanks yeah, idk why I didn't see that as an option.
Altough the first one works ?
Pretty sure you cannot do that yet
. Or I am just reading it wrong
if I have Root.AddComponent, it says cannot resolve symbol AddComponent
Yea with the root it's normal, but I expected you needing to do builder.Build(). idk what my problem was than 
Root is just an unity element so you don't have any easy options than anymore. at least for modifying it
Yeah, idk. I guess I could also just learn proper UXML 😛 But this feels nicer than that so I'm trying to make it work
My head was swimming trying to make sense of the UXML stuff
UXML isn't that hard either 😛
The only thing I dislike the most is I cannot just make a singular item and reuse it. instead you need to write the whole component everytime
So, I guess my question here is: When would UXML be worse but I think you just answered that?
PRetty much 😛
I think mine is a bit more complex in the earlier states, but after having some setups it gets faster and easier to reuse
It feels like I could easily with TAPI UI Builder write a utility mod that is all the UI elements I reuse in multiple mods ?
relatively easily*
Yeah sure that would be just like the presets dll
Makes sense
Yea, thats is a big plus for TAPI UI as i can then also use them and dont need to make them
TheBloodEyes so smurt!
Hi for https://steamcommunity.com/sharedfiles/filedetails/?id=3487241285 (Hospital), my buildings disappear if TimberAPi is present, wonder what happened 
The building path is added using this: https://github.com/datvm/TimberbornMods/blob/master/Hospital/PrefabAdder/HospitalSpecAdder.cs
probably not relevant to the issue but these files are used to load a placeholder prefab and then replace it with a copy of Medical Bed: https://github.com/datvm/TimberbornMods/tree/master/Hospital/PrefabAdder
idk, does your mod even have a prefab?
If you manually add it to somewhere timberborn has wanted it it might not work for TimberApi
no clue how your code works
If your building doesn't have a PlaceableBlockObjectSpec it won't be converted
could it be a timing issue Timberborn check and adds to bottom bar before you have edited the prefab? 
it definitely does because it's a modified copy of MedicalBed.
Is it a actual copy or a runtime copy
so what I do =
- Add the path (something like "Buildings/Hospital") to the
Buildings.FolktailsPaths. - Add a AssetProvider that when loading the prefab, simply give it an empty placeholder.
- In PrefabGroupService, after they are all loaded, replace the placeholder with the copy of Medical Bed.
made/copied at runtime
which spec? it should have everything the original Medical Bed has.
did you load the list for your custom bottom bar way before that?
hmm I don't understand, how does that work for other Prefab though? it's loaded through the PrefabGroupSpec like "Buildings.Folktails" right?
No
Its bot loafed by a path
Its converted by the placeable spec
Then it will use the prefab name to build the correct tool
Im pretty sure you have a unique prefab name for your tools
If you make a toolspec it might just work fine
yeah I rename it to something else after copying. not sure how do I make a ToolSpec. could you give me the schema? thanks.
like I just need to place a JSON file there "just in case" there is TimberApi right?
oh nvm found it PlaceableObjectToolSpec. Simply a JSON file with PlaceableObjectToolSpec with PrefabName right?
No
You need a toolspec. In the first link you can see what needs to be in it
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
}
well I asked @austere tangle to just give me a prefab instead lol
Has the new version deprecated the UIBuilder system?
New version ?
update 7 doesn't include UIBuilder
u7 has it as a standalone mod instead right?
No it's a stand alone mod
Yes
Aaaah right ok, yeah I see it, thank you!
@stone shoal well with the new #1382243128253087895 , if they have TimberApi, the new buildings are not showing again...
and this time I didn't use Moddable Bindto or even Harmony...
I use a proper IAssetProvider to provide the specs as if it's a real JSON file 😦
https://github.com/datvm/TimberbornMods/blob/master/ConfigurableFaction/Services/ConfigurableFactionBlueprintProvider.cs
I do wrap the FactionSpecService with a wrapper (but it's still the same type), did you happen to patch its Load method?
https://github.com/datvm/TimberbornMods/blob/master/ConfigurableFaction/Services/ConfigurableFactionSpecService.cs
if I tried to add Faction.Folktails as well to add PrefabGroups directly there, then now somehow your script still load it before it's loaded
because I can't add Materials and Needs and Goods any earlier because there is no info at that time
100% sure this has already been said before with another mod of yours
Not sure what specs you mean but I generate buildings based on prefabs
Yes so this probably will never work
Because harmony doesnt do both patches
I need fractions to generate specs and you reload the specs again and add new ones
Why would you reload it in first place?
Aside from that if you just generate the jsons for TimberApi bottombar of the added buildings it might work
But some mods might going to be incompatible when using generated specs. Or other aspects of TimberApi
Meanwhile TimberApi is currently broken I believe since experimental is now live. And i am on holiday
It was working for me in experimental at least last I checked earlier today
(Unless I don't have mods that use the broken things)
Than it might not be broken. Thought it crashed in exp. Maybe user error
If i could have a better way to use the prefabservice and dont require factions to be loaded it would be easier
pretty sure this time I use a different approach, not patching/replacing the thing anymore...
Doesnt matter your timing ks way later. So you have to generate the specs yourself like i said in later message
because those info aren't available to me at that time yet. I can't list all factions within the Provider because it's used by the provider itself
oh well, I just rolled back the original version, and then just release this one without TimberApi compatibility then... I can't generate the specs because the user choose them dynamically.
You know what they picked so you can generate them?
How do you know what buildings there are if you dont have the info?
yeah based on the file name only, not from the game. so I have the faction ID only
after the Spec loaded.
For the configuration?
so right now:
FactionSpecService -> SpecService -> AssetLoader -> IAssetProvider
IAssetProvider is where I am putting in a custom prefab group in. the content is cached in a file.
at FactionSpecService, I put in the other info (needs, materials etc)
for Materials I need to know what material other factions have
so I can't know that before FactionSpecService finished loading
btw, I see that you still call FactionSpecService.Load in TimberApi loading code, how come that info is not in? I already added that info at FactionSpecService.Load
public new void Load()
{
base.Load();
OriginalFactions = Factions;
factionOptionsProvider.AddMissingFactions(Factions.Select(q => q.Id));
AppendData();
}
The faction is probably already loaded. But your code isnt
You are bot loading the faction before i do
Its weird you reload the faction anyway instead of just depend on it and add to it after the load
what do you mean? I can't modify them because their setters are init
Csn you share it? I csnt look it up on phone
it's simply a loading specs code:
public void Load()
{
Factions = _specService.GetSpecs<FactionSpec>().ToImmutableArray();
}
Okay
Oh well if you cannot generate them before https://github.com/Timberborn-Modding-Central/TimberAPI/blob/main/Src/TimberApi.Tools/ToolSystem/ToolSpecificationService.cs is loaded i cannot help you
You arent going to add a dependency anyway so not going to bother any further.
Without that info(ToolSpec) there is not much to do
how do I make it run before btw?
easy to add a dependency to run after, but before is harder
I can make a branch version with TimberApi depenendecy
or maybe just use reflection type.
No clue. Bindito doesnt provide much for that. But if you have TimberApi as a dependency you can easily use earlyLoadableSingleton and make sure your asset provider has the data at that point ready
usually I make my own class that inherit another class, replace it with mine and put anything I need in the constructor
so I could replace your ToolSpecificationService with mine with an extra constructor
or... actually it's easy lol. I remove your service, add it using a Provider
I totally forgot about that
No clue, but sure. If it breaks make sure they know its on your end
so basically:
this.RemoveBinding<ToolSpecificationService>();
this.Bind<ToolSpecificationService>().ToProvider(MyClass).AsSingleton()
There is a remove binding?
TimberUI provides that
simply scans the registry and remove it
I even provide RemoveMultiBinding (all or a specific type) lol
Migjt have been easier than transpiler
yep
hi do you remember how we solved the issue back then? 😂 back then I replaced the SpecService and now I do not replace it anymore but how come it crashes 😅
NullReferenceException: Object reference not set to an instance of an object
at TimberApi.SpecificationSystem.GeneratedSpecLoader.PostLoad () [0x00057] in <514fe957c82a4375b887fa4e42e2be35>:0
at TimberApi.SingletonSystem.SingletonLifecycleServicePatcher+<>c.<LoadAllPrefix>b__0_1 (TimberApi.SingletonSystem.ITimberApiPostLoadableSingleton singleton) [0x00000] in <0673fedbcca9497a90c561275f1aa775>:0
at TimberApi.SingletonSystem.SingletonLifecycleServicePatcher.LoadSingleton[T] (System.Collections.Generic.IEnumerable`1[T] singletons, System.Action`1[T] action) [0x00012] in <0673fedbcca9497a90c561275f1aa775>:0
at TimberApi.SingletonSystem.SingletonLifecycleServicePatcher.LoadAllPrefix (Timberborn.SingletonSystem.ISingletonRepository ____singletonRepository) [0x00032] in <0673fedbcca9497a90c561275f1aa775>:0
at (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.Timberborn.SingletonSystem.SingletonLifecycleService.LoadAll_Patch1(Timberborn.SingletonSystem.SingletonLifecycleService)
at Timberborn.SingletonSystem.SingletonLifecycleUnityAdapter.Start () [0x00000] in <9117b1294fcf4df390fc07f3eef2285e>:0
so back then I added a "fake" _cachedBlueprints for it I think, but now I don't need to do that anymore because it's there now, in the original SpecService
hmm I don't understand how your code can crash. it should work perfectly fine though 
public void PostLoad()
{
foreach (ISpecGenerator item in specificationGenerators)
{
generatedSpecAssetRepository.AddSpecRange(item.Generate());
}
((Dictionary<Type, List<Lazy<Timberborn.BlueprintSystem.Blueprint>>>)specService.GetType().GetField("_cachedBlueprints", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(specService)).Clear(); // This line crashes
EarlyLoadPatcher.BlockLoading = false;
specService.Load();
factionSpecificationService.Load();
EarlyLoadPatcher.BlockLoading = true;
}
specService does have _cachedBlueprints
oohhhh I know why, it's due to publicizer! since my new class ModdableSpecService inherits SpecService but through the publicizer, it thought _cachedBlueprints was a public member. So your BindingFlags.NonPublic would not get it I think. so a fix would be BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public. Or since you have Harmony anyway, you can just use AccessTools.all or use .Field("_cachedBlueprints") instead (Harmony extension method).
I'm getting this in experimental. The game seems working, though.
Any patches or something you do or is this just since update
Started to show up after the latest game update. I didn't try it on an empty game setup, though. Just noticed the stack trace is pointing to TAPI, so assumed it can be related.
No idea to be honest, the only thing i do eith the early stuff is calling base game stuff earlier
So might also be there if tapi was disabled. If the mod causing it doesnt deoend on tapi
This is the error that I get as of today:
Do you have ModdableBindito? #1064983064020799498 message
It just had a bad update, causing timberapi to crash
yes, i just removed it and now its working fine again. Thank you all for your help
ModdableBindito errors are due to TimberAPI or ModdableBindito?
reason - v7.1.2: Technical update: ModdableSpecService is now a SpecService (for ISpecService)
Thanks
yep, unfortunately depends on which mod you need. 7.1.1 = works with TimberApi and 7.1.2 = works with Automation
Using the 7.1.1 version fixed it for me, as I don't use automation
Does TimberApi require a working internet connection? context: https://www.reddit.com/r/Timberborn/s/BILzbYezRe
No?
Well not to my awereness
I never tried it haha
I don't have anything that requires internet connection though, maybe the mod manager
Yea, that's pretty much what I replied, and the commenter is 100% sure that I'm wrong.
They do that sometimes
That's why they are a redditor 🙂
I found the reasoning very neet,
Because it's an API
Well, you ain't 100% incorrect if you thinking about webbased stuff.
API just means Application Programming Interface. Has nothing to do with internet connection 
Yep
If my game would just update I can test it
Just wanted to post here in case you (@TheBloodEyes) don't read #🚀mod-users , but I'm in agreeance with you in that I don't think the two are really compatible at this point (but I would love to be proven wrong). You can see just a snippet of the attempts I've made trying to get the 2 to work in that channel, but if it saves you time/stress, then at least there's a positive that came from me testing this out 👀
Didn't want you possibly spending the same amount of unhealthy fun time I did on this (was fun at times) :p
Well if i just need to do as he says its nkt much work
But if its alot of work, he should probably fix it.
Just didnt have time to check it out yet
I tried that
This was the stack trace with it
#🚀mod-users message
Again I’d love to be proved wrong, but also didn’t want someone else to go though it all in the event they inevitably come to the same conclusion
This patch work for me (no crash in the game), in C# you cannot get a private member from a base member.
static FieldInfo FindCacheField(Type type)
{
var field = type.GetField("_cachedBlueprints", AccessTools.all);
return field is null
? type.BaseType == typeof(object) ? throw new FieldAccessException("Field not found") : FindCacheField(type.BaseType)
: field;
}
public static void ClearCache(object __instance)
{
var fields = __instance.GetType().GetFields(AccessTools.all);
var specServiceField = fields.First(q => q.Name.Contains("specService"));
var specService = (ISpecService) specServiceField.GetValue(__instance);
var cacheField = FindCacheField(specService.GetType());
var cache = cacheField.GetValue(specService);
var clear = cache.GetType().GetMethod("Clear", AccessTools.all);
clear.Invoke(cache, null);
}
public static IEnumerable<CodeInstruction> Patch(IEnumerable<CodeInstruction> instructions)
{
var list = instructions.ToList();
var index = list.FindIndex(q => q.opcode == OpCodes.Callvirt && q.operand is MethodInfo method && method.Name == "Clear");
// Go back two `ldarg.0` instructions
var startIndex = list.FindLastIndex(index - 1, q => q.opcode == OpCodes.Ldarg_0);
startIndex = list.FindLastIndex(startIndex - 1, q => q.opcode == OpCodes.Ldarg_0);
// Clear that part
// Don't remove the first ldarg.0 as it's a label for a branch
list.RemoveRange(startIndex + 1, index - startIndex);
// Insert our ClearCache method
list.Insert(startIndex + 1, new(OpCodes.Call, typeof(ModStarter).Method(nameof(ClearCache))));
return list;
}
this is the patch btw, because I don't want to copy the DLL:
void IModStarter.StartMod(IModEnvironment modEnvironment)
{
var harmony = new Harmony(nameof(TestMod));
harmony.PatchAll();
var t = AccessTools.TypeByName("TimberApi.SpecificationSystem.GeneratedSpecLoader");
var method = t.Method("PostLoad");
harmony.Patch(method,
transpiler: typeof(ModStarter).Method("Patch"));
}
but much easier if the code author add it in, no transpiler needed, only need to find the member in the parent class as well
wonder if it's easier if I put in a shadowed member with the same name there lol
Aha, so AccessTools.all instead eh
Could be safe and cover both, but that’s really up to you two
In what way did you try it
, did you build TimberApi yourself ?
Nah, I didn’t find anything recent on the repo so I just went by what I could find without building either of your mods
I was trying to make a compatibility/patch mod that just patched the problematic part that was suggested previously
Going the AccessTools.all or shadow route is completely different though and makes sense
I wasn’t going to rebuild both entire environments with what I might assume you both had, so I was going off of the information I read here. I had my own goal(s) way before this though as I had in mind a compatibility mod patch that other games have, so I was approaching this from that angle as the 3rd party
Well that should be a lot easier for you as they said
Optimistically speaking I did say I’d love to be proved wrong, but this got the solution correctly from the sound of it, so I count that as a win
Before I had a legend called hytone which helped me with these small fixes
But since update 6 it's broken down so much, just trying to keep it up for now
Maybe some day
Gets overwhelming trying to keep up with it all depending on the environment
Especially when not paid to do so
Speaking of, you don’t keep TimberAPI on the repo, do you? Or at least not on the public repo
I’ll have to look when I’m back at my desk. I still wouldn’t bother rebuilding it all depending on your setup as I don’t like doing that for multiple reasons
It's not a easy setup 
Mostly due bepinex nuget is broken on my pc so I had to do it differently
For some reason my network connection doesnt establish some stuff anymore. Just like all my cloud saves are broken on any platform and I cannot start a download/update on steam before restarting the client
I’d imagine, but it’s more I just don’t like doing that if it’s another modders thing unless asked or unless it looks like something I can help with as a 3rd party
Safest approach sounds like both sides adding said small fix though, but glad I’m the one that ran with the BindingFlag.public knowledge as that was a major chicken and egg scenario
nah AccessTools.all is just covering the convenient stuff (Public + NonPublic + Instance + ... etc)
but even with it (and even with FlattenHierachy, which is not included in that), you cannot grab the private variable from base. you have to traverse to the base type
so with the new move to #1422778917366005770 using Harmony, I receive this error instead:
ArgumentException: An item with the same key has already been added. Key: Package_Algae
System.Collections.Generic.Dictionary`2[TKey,TValue].TryInsert (TKey key, TValue value, System.Collections.Generic.InsertionBehavior behavior) (at <4780199c95764436ade50bbd58f63488>:0)
System.Collections.Generic.Dictionary`2[TKey,TValue].Add (TKey key, TValue value) (at <4780199c95764436ade50bbd58f63488>:0)
System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement] (System.Collections.Generic.IEnumerable`1[T] source, System.Func`2[T,TResult] keySelector, System.Func`2[T,TResult] elementSelector, System.Collections.Generic.IEqualityComparer`1[T] comparer) (at <56bcb176486e400396fc9557eca2a147>:0)
System.Collections.Frozen.FrozenDictionary.ToFrozenDictionary[TSource,TKey,TElement] (System.Collections.Generic.IEnumerable`1[T] source, System.Func`2[T,TResult] keySelector, System.Func`2[T,TResult] elementSelector, System.Collections.Generic.IEqualityComparer`1[T] comparer) (at <6bb08d37de124a778ca2954872cc5e3e>:0)
Timberborn.Workshops.RecipeSpecService.Load () (at <6064568cf4f24a9abe05482a8954f025>:0)
Mods.MoreModLogs.SingletonSystemPatch.ErrorReporter (System.Action fn) (at C:/Users/Norman/Documents/src/Timberborn-MoreModLogs/SingletonSystemPatch.cs:61)
(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.SingletonLifecycleUnityAdapter.Start () (at <37714495c7b34fbf87491c89893567c4>:0)
any idea why? I was adding new Goods and Recipes into the Specs.
You sure it's a TimberApi problem? I don't remember doing something with goods
Unless package_algae is an building and it's added twice to the buildings
it does not crash if I don't enable TimberApi
the stack trace crash is from RecipeSpecService
so I added it by adding stuff to the _cachedBlueprints right after SpecService.Load.
since all other methods are generic and cannot be patched
only thin I can think out of my head is if you do a prefix and block the rest
im changing the load order so if that patch is removed it crashes
nope, only thing I do is to run a postfix and add a few items to the list
nothing for prefix
btw, I do read all the Lazy<T> in there to get the info, then after that append a few (values are already calculated but wrapped inside Lazy because the type need it)
does reading the Lazy<Blueprint> trigger anything?
well fixed for Packager because I am making a separate version to generate JSON files for now
I really csnnot remember much of it
I dont do much with specs except blocking the load function and than executing it myself
Sadly enough my recovery only lasted for about 2 months so yeah...
so there is this strange bug, I finally found out because apparently TimberApi was trying to call PrefabGroupService.Load somewhere earlier than it should?
#🚀mod-users message
for example, a proper run without TimberApi, I add my own service as a dummy IPrefabGroupProvider, so its Load should be called before PrefabGroupService.Load:
However, with TimberAPI, for some reason PrefabGroupService.Load is called before it even though PrefabGroupService depends on it and cause data to be unintialized:
yes
I also load all the other required services
well, the above log shows the MSettings.Load isn't called until after it
specificially the dependency chain is something like this: PrefabGroupService -> IEnumerable<IPrefabGroupProvider> -> one of my MyPrefabGroupProvider -> MSettings
Okay?
I just move the load order of few parts, to the most earliest state and disable the load calls if they happen before that

Maybe that's the problem
@cinder fern is your patch add something to a list when the load method is called as a dictionary it will do it twice
Probably
Altough with this harmony is I prefix block it and yours is a postfix it shouldn't trigger I believe
only after. anything before that is not patched, it's just Bindito's standard Load order due to dependency
no Dictionary is involved btw
this is for PrefabGroupService, not SpecService
so from the source:
public void Load()
{
EarlyLoadPatcher.BlockLoading = false;
((GameSceneSerializedWorldSupplier)worldEntitiesLoader).Load();
specService.Load();
factionSpecificationService.Load();
factionService.Load();
prefabGroupService.Load();
EarlyLoadPatcher.BlockLoading = true;
}
you manually call the Load methods of those services. but everything in between is not called, as well as the Load of all their dependencies (for example, IPrefabGroupProviders)
What you mean, it litarly has specservice load
And sll other loads ate indeed done in normal order
no, the DI guarantees that all dependencies's Load are called before that.
so look at PrefabGroupService constructor:
public PrefabGroupService(ISpecService specService, IAssetLoader assetLoader, IEnumerable<IPrefabGroupProvider> prefabGroupProviders)
that means, before PrefabGroupService.Load is called: ISpecService.Load is called, IAssetLoader.Load is called and all IPrefabGroupProvider.Loads if any of them are ILoadableSingleton
in your code above, you didn't call any IPrefabGroupProvider.Load
so PrefabGroupService.Load is called before any IPrefabGroupProvider.Load is called when it should be after.
Except the fact that it doesn't do that at all. At least not specificly.
It would be that way IF it would use ILoadableSingleton which it does not. It uses ITimberApiLoadableSingleton which is always loaded before any ILoadableSingleton
it does though...
The DI only determens the order of instaniation of classes. And that makes them registered in the same order for the singletons
You can believe that if you want. But it's not true
#🤖mod-creators message
And how does that disprove what I said, did you read it all?
well anyway in that case it's not my mod's fault that TimberApi changed the expected behavior then
I don't use ILoadableSingleton
That's true, never said it was
wait was you talking about ILoadableSingleton.Load here or something different? I think we are talking about two different things here.
public void LoadAll()
{
this._loadableSingletons = ImmutableArray.ToImmutableArray<ILoadableSingleton>(this._singletonRepository.GetSingletons<ILoadableSingleton>());
this._nonSingletonLoaders = ImmutableArray.ToImmutableArray<INonSingletonLoader>(this._singletonRepository.GetSingletons<INonSingletonLoader>());
this._postLoadableSingletons = ImmutableArray.ToImmutableArray<IPostLoadableSingleton>(this._singletonRepository.GetSingletons<IPostLoadableSingleton>());
this._nonSingletonPostLoaders = ImmutableArray.ToImmutableArray<INonSingletonPostLoader>(this._singletonRepository.GetSingletons<INonSingletonPostLoader>());
this._unloadableSingletons = ImmutableArray.ToImmutableArray<IUnloadableSingleton>(this._singletonRepository.GetSingletons<IUnloadableSingleton>());
this._updatableSingletons = ImmutableArray.ToImmutableArray<IUpdatableSingleton>(this._singletonRepository.GetSingletons<IUpdatableSingleton>());
this._lateUpdatableSingletons = ImmutableArray.ToImmutableArray<ILateUpdatableSingleton>(this._singletonRepository.GetSingletons<ILateUpdatableSingleton>());
this.LoadSingletons();
this.LoadNonSingletons();
this.PostLoadSingletons();
this.PostLoadNonSingletons();
this._initializedSuccessfully = true;
}
This determens the load order, anything that uses PostLoadSingletons are always loaded after the load method
so anyway, my point was, the ILoadableSingleton.Load of dependencies were supposed to be called before the main class/using class's ILoadableSingleton.Load
They do it only loads even earlier
public void Load()
{
EarlyLoadPatcher.BlockLoading = false;
((GameSceneSerializedWorldSupplier)worldEntitiesLoader).Load();
specService.Load();
factionSpecificationService.Load();
factionService.Load();
prefabGroupService.Load();
EarlyLoadPatcher.BlockLoading = true;
}
This is loaded before anything else
yeah which causes unexpected behavior because when prefabGroupService.Load() is called, it's normally expected that all dependencies' Load if any, were called?
Yes, so unless you change the expected behaviour as well and overwrite the whole clas replacing it with your own it might crash
If it requires more
why do you need to call it early btw, why don't just intercept/patch the Load methods?
I don't see how I can intervene with this behavior from my side
I intercept them by disabling them at original point and call them at the earliest point in the scene load cycles
Thus early
I don't know how you can cause problems really 
Only thing would be a patch I assume
Something is done twice in a dictionary
This was beforehand mostly the case of the spec service being loaded twice
due _cachedBlueprints
before PrefabGroupService.Load is called, my service needs the setting.
no this issue is not related to the ISpecService at all
so normally, this is this:
PrefabGroupService -> my service (through IPrefabGroupProvider) -> MSettings
so, the load order called should be MSettings.Load, MyService.Load, then PrefabGroupService.Load.
but you called PrefabGroupService.Load out of the DI cycle, so MyService.Load was not called and MSettings.Load was not called, so there is no data
Im not really calling it out of the DI cycle, I'm moving it out of the ISpecificationLoad cycle
But aside of that yes, that's correct
Since providers wouldn't have loaders in Timberborn
well they are interfaces, so say tomorrow the dev wants to add make an IPrefabGroupProvider to be ILoadableSingleton, it's totally acceptable.
and that's what I am trying to do to have my services run before it.
Yes
I can try one thing and after that I'll be brain dead again
If I make it at all 
Not sure why I haven't thought of this before, so I kinda doubt it's gonna work
It's probably gonna break other mods of you now though
((Dictionary<Type, List<Lazy<Blueprint>>>)specService.GetType()
.GetField("_cachedBlueprints", BindingFlags.Instance | BindingFlags.NonPublic)!
.GetValue(specService))
.Clear();
With this I need the reference to the _cachedBlueprints and replace it with new values
other mods do modify the _cachedBlueprints after the Load. not sure where you execute that one though
How do they modify it if it's readonly ?
it's not? it's a Dictionary
public readonly Dictionary<Type, List<Lazy<Blueprint>>> _cachedBlueprints = new Dictionary<Type, List<Lazy<Blueprint>>>();
right
I never replace the whole thing
well it only apply to the variable itself. the content of the object no one can guarantee. if you want readonly, you use FrozenDictionary or ImmutableDictionary
Wtf is a LoadedAsset
not sure what it does but it's basically a wrapper of an Asset (GameObject etc)
I don't remember why it's wrapped

It doesn't crash

It still regenerates the whole specService but it did that before so hopefully not a problem
then the question does more groups still work 😛
Yes,
@cinder fern does this solve it ?
meaning both move of things and added groups works 🙂
stairs should be moved to its subgroup
But more groups just use the normal spec stuff not really the generated things. So should not really give problems if i get in the game in general
oh yeah Configurable Faction crashes with a few TimberApi mods too when they exist only in a subgroup
because it tries to group stuff into a group that does not actually "exist"
like Flywheels, I guess because it only exists in a subgroup
is it not that you expect it to exist in one place and then its moved with a specification and then its not found?
but is this after the new tapi version beta?
no, it has been happening for a while
but they can disable TimberApi while using CF to export so I guess it's fine and don't need to be fixed
as mods that give buildings with TimberApi usually give them to all factions anyway
ImmutableArray<BuildingToolGroup> GroupBuildings(IEnumerable<NormalizedPrefabSpec> buildings) => [.. buildings
.Select(q =>
{
var objSpec = q.PrefabSpec.GetComponentFast<PlaceableBlockObjectSpec>();
var toolGroup = ToolGroups[objSpec.ToolGroupId];
return (q, objSpec, toolGroup);
})
.GroupBy(q => q.toolGroup, (k, list) => new BuildingToolGroup(
k,
[.. list
.OrderBy(q => q.objSpec.ToolOrder)
.Select(q => q.q)]
)).OrderBy(q => q.ToolGroupSpec.Order)
];
the code that crashes btw
I realized by doing this LINQ it's not very helpful because the stack trace does not show what exact line causes it lol
yep with this the order is called properly now:
MSettings.AfterLoad called
[ModdableTimberborn] PrefabGroupService Load was called.
[ModdableTimberborn] Modified prefab 'BeaverStatue.Folktails' using 'ConfigurableFun.Services.PrefabModifier'
loading my mods and checking them 2
(even if i expect them to not break 😛 )
checked these mods and no crash in FT or IT
- Harmony (v2.4.0)
- KnatteMaterials (v7.0.0)
- Mod Settings (v0.7.10.0)
- More TopBars (v7.0.0)
- TimberUi (v7.8.2)
- TImprove (v7.6.0)
- TImprove 4 Modders (v7.6.0)
- TImprove 4 Mods (v7.2.2)
- TImprove 4 UI (v7.10.1)
- 1x1x2Storage (v2.4.5)
- Automation (v2.7.1)
- Water Extention (v7.0.2)
- Water Extention PowerEdition (v7.0.2)
- Bob Platforms Extended (v0.7.9.0)
- Bobingabout Script Pack (v0.7.9.8)
- Bob Storage (v0.7.9.0)
- Configurable Tubeway & Zipline (v7.4.2)
- TimberApi UIBuilder (v1.0.2.0)
- Cutter Tool (v0.7.1.2)
- DamDecoration (v7.0.1)
- TimberApi (v0.7.8.0)
- DamDecorations_DecorationExtention (v7.0.0)
- ExtendedFloodgates (v7.0.0)
- Extra Terrain Tools (v0.9.3)
- Flywheels (v3.1.0.61)
- Forest Tool (v0.7.2.2)
- Frog Statue (v7.0.0)
- Goods Statistics (v0.7.3.1)
- Ladder (v3.0.4)
- MaterialPlzNoCrashes (v7.0.1)
- More Tunnels (v0.7)
- Path Extention (v7.0.1)
- MoreGroups (v7.0.2)
- Tiny Tubeway Station (v0.7.9.1)
- Tubeway Bridges (v0.7.9.0)
- Tubeway Levee (v0.7.9.0)
- Tubeway Top Connection (v0.7.7.0)
- Staircase (v7.0.1)
- Steam Update Buttons (v0.1.6)
- TimberCommons (v1.13.0)
- zxuiji - Append Vanilla Resources (v0.7.0.01)
- Underground Path (v7.10.8.0)
- Torii Gates and Lanterns (v2.2.0)
- Unstuckify (v2.0.2)
- Water Extention Irrigation Towers (v7.0.2)
- Zipline Levee (v0.7.9.0)`
The only problem now would be if you require a generated prefab before the Prefab Load method wich cannot be controlled that flow
Unless adding the prefabservice to your class even though you don't need it
Will try to upload it tomorrow
well that flow was unusual to begin with isn't it?
I mean normally you can't do that in the game to begin with?
Previsouly the flow would work normally again except that it's loaded earlier 🙂
For the generated parts could be used as any normal spec
Just like many other things you can't
?
well yeah I mean, if you do something unusual, you should expect something unusual happening right lol?
Had another idea way back how to fix it in another way
Never able to test-make it htough
well, for ModdableTimberborn, I just add ISpecModifier, ISpecTailRunner and ISpecFrontRunner, same for PrefabGroupService
so basically if you need something run earlier/later than those services, you can
and all of them use Bindito I believe, except the TailRunner which needs Harmony, so you get all the proper DI flow
btw I was thinking about a fun project similar to More Groups but do not replace the game's Tool bar 😛 why did you make a whole new toolbar back then btw?
can't you patch/overwrite certain stuff instead for more groups?
More groups doesn't have anything to do with the new toolbar
The bottombar rework is to allow multiple layers of bars
and ability to modify it all with specs
Before hand mods also crashed without it if a group had the same order so you had to make sure everyone had an unique order
can't you patch them instead?
patch what ?
And how would it be specs if you need code to patch it 
ofc you can path it from the spec but not able to make multible layers
The problem of duplicated order would also still exist
I will try later
Hi I was told you come here as this mod seemed to bug my save game
They didnt go for fun activities (I did have the fun mod too)
I deactivated this and it worked
you could try this alpha build and see if it then works:
#1064983064020799498 message
I wouldnt know what to do with that file 😮
I am useless 😄
steps to test it:
- Download the zip
- open folder
%userprofile%/Documents/Timberborn/Mods - unpack zip inside above folder
- run the game and disable timberapi with a ☁️ icon (to return to steam download enable the one with a ☁️ and disable one with a 📁 icon)
- test if it crashes or not when loading a save
- report back the findings 😉
Updated for steam
Thanks
noticed flywheels / white paws / etc is looking for a newer version of the timberapi - is that a known issue?
@stone shoal , you have uploaded TAPI with the wrong version (0.7.8.0) in the manifest file. It should be at least 0.7.12.3 Most mods that use TAPI are nuked out 🤣
Ohh dang i thought it was just the same version
Should be updated now @blissful kindle
hmm i got some weird error log, can i share in here?
i can't tell what mod it's from (not a programmer so harder for me :|)
Ether here or in mod users
ok i got this error with trying to load whitepaws after the timberapi updates, so i'll share this here. and i got a separate error for the coil, i'll share that in mod users
Can you also post the player log gives more info about exact mods and setup
I run Timberborn with the thread limiter, and the call to ModManagerUI.SteamChecker.IsRestartCompatible when exiting the Mod Manager after installing/updating a mod fails (because the parent process is gone).
ugh, I put it in the wrong channel 😔
I wasn't commenting here for too long. Which is technically good (no complains => no comments). But just to leave some kudos for TAPI 
@stone shoal , thanks for your great job! (which doesn't make me complaining, lol)
Bit tapijt isnt updated yet 
Thanks anyway

My mods are not updated either. It was "a kudos from the past". When everything was working as intended, lol 🤣
issue with the timberapi
if on experimental do not use Timberapi its not updated!
TimberAPI has been replaced with Moddable Tool Groups
Good info. So anything that had a timber api dependency should run with Moddable tool groups?
after its updated to support the new mod
gives equal functionality but some differances
On steam it should not crash anymore though
Maybe upload the same change to mod.io to make it easier if people just upgrade the mod?
and maybe also change the name to something like TimberApi (obsolete in 1.0)?
I never did this, there are tags for imo. I added all tags for what game version it is. Can add it in description
Mostly for the name in manifest.json so that appears in the mod loading screen.
Oooh, truueee, i add those things in the title because we didnt bwfore, now i can remove again. Smurt