Skip to content

Commit 0778a32

Browse files
committed
Added more docs.
1 parent 00cc8a0 commit 0778a32

File tree

7 files changed

+522
-10
lines changed

7 files changed

+522
-10
lines changed

ModdableWeather/index.MD

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
title: "Moddable Weather"
3+
description: Add more weathers to Timberborn
4+
date: 2025-06-05
5+
tags: mods timberborn guide modding weather moddable
6+
---
7+
8+
The [Moddable Weather](https://steamcommunity.com/workshop/filedetails/?id=3493039008) can be used to add new weathers to Timberborn.
9+
10+
[Placeholder content]

ModdingGuide/advanced-modding.MD

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,91 @@
11
---
22
title: "Part 5: Advanced Modding Techniques"
3-
description: A comprehensive guide to making mods for Timberborn
3+
description: Some techniques I use in my mods to make modding easier and less repetitive.
44
date: 2025-03-13
55
tags: mods timberborn guide modding
66
---
77

8-
Placeholder content
8+
Since I have made many mods, I need to keep my `.csproj` files short, and also reuse the publicized assemblies so I don't have to publicize them for each mod.
9+
10+
# Publicizer
11+
12+
Feel free to use my [Publicizer](https://github.com/datvm/TimberbornMods/tree/master/GameAssemblyPublicizer). It's a Console app that uses `BepInEx.AssemblyPublicizer` package, find all Timberborn assemblies in the `Timberborn\Timberborn_Data\Managed` folder, and publicizes them to the `out` folder. I only need to run this app once after each Timberborn update, and then I can use the publicized assemblies in my mods.
13+
14+
Beside the game's assemblies, I also publicize some other mods' assemblies in there. See below on how to refer them.
15+
16+
# Project Structure
17+
18+
Since I have made many mods, I need to keep my `.csproj` files shorter by reusing the targets. For example, a "complicated" mod like [Scientific Projects](https://steamcommunity.com/workshop/filedetails/?id=3442389397) has this `.csproj` file:
19+
20+
```xml
21+
<Project Sdk="Microsoft.NET.Sdk">
22+
<PropertyGroup>
23+
<OutputModFolderName>ScientificProjects</OutputModFolderName>
24+
<GameSolutionFolder>..\..\</GameSolutionFolder>
25+
</PropertyGroup>
26+
<Import Project="../../Common.target" />
27+
<Import Project="../../CommonTimberUI.target" />
28+
<Import Project="../../CommonBuffDebuff.target" />
29+
</Project>
30+
```
31+
32+
Feel free to check the `.targert` files in my [TimberbornMods repository](https://github.com/datvm/TimberbornMods/tree/master). For example, the `Common.target` with added explanations:
33+
34+
```xml
35+
<!-- I even modularize the Common.target file further -->
36+
<Import Project=".\CommonProperties.target" />
37+
<Import Project=".\CommonGlobalUsings.target" />
38+
39+
<!-- Define where the mod will be output in each csproj file -->
40+
<Target Name="Validate">
41+
<Error Condition="'$(OutputModFolderName)'==''" Text="OutputModFolderName was not specified" />
42+
</Target>
43+
44+
<!-- General properties -->
45+
<PropertyGroup>
46+
<TargetFramework>netstandard2.1</TargetFramework>
47+
<LangVersion>preview</LangVersion>
48+
<ImplicitUsings>enable</ImplicitUsings>
49+
<Nullable>enable</Nullable>
50+
51+
<DebugSymbols>true</DebugSymbols>
52+
<DebugType>embedded</DebugType>
53+
</PropertyGroup>
54+
55+
<!-- Copy the built files to the Timberborn mod folder -->
56+
<Target Name="CopyFiles" AfterTargets="PrepareFilesForCopy">
57+
<Message Text="Deleting..." />
58+
<RemoveDir Directories="$(ModFolder)" />
59+
60+
<Message Text="Copying..." />
61+
<Copy SourceFiles="@(ModManifestFile)" DestinationFolder="$(ModFolder)" />
62+
<!-- ... -->
63+
</Target>
64+
65+
<!-- Use the publicized and other assemblies -->
66+
<ItemGroup>
67+
<!-- IgnoresAccessChecks.cs is needed to use the publicized assemblies -->
68+
<Compile Include="$(GameSolutionFolder)GameAssemblyPublicizer\IgnoresAccessChecks.cs" Link="IgnoresAccessChecks.cs" />
69+
70+
<!-- Refer to all the Publicized assemblies -->
71+
<Reference Include="$(GameSolutionFolder)GameAssemblyPublicizer\out\common\**\*.dll">
72+
<Private>false</Private>
73+
</Reference>
74+
75+
<!-- These are not publicized but sometimes we need them -->
76+
<Reference Include="$(AssemblyPath)\System.Collections.Immutable.dll">
77+
<Private>false</Private>
78+
</Reference>
79+
<Reference Include="$(AssemblyPath)\Newtonsoft.Json.dll">
80+
<Private>false</Private>
81+
</Reference>
82+
</ItemGroup>
83+
```
84+
85+
Other `.target` are for projects that only use a certain feature like `CommonTimberUI` or `CommonHarmony`.
86+
87+
# Find components without Unity
88+
89+
Sometimes you may want to know which components are attached to a game object. When using AssetRipper, you can find the `.prefab` files but they use UUID references which may not be very useful in finding out what it is. You can use my [FileFinder](https://github.com/datvm/TimberbornMods/tree/master/FileFinder) to map the UUIDs to the actual component names.
90+
91+
You simply need to replace the `FileInput` constant and run it. It will search for all the UUID and print out the relevant files.

ModdingGuide/base-component.MD

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
title: Base Component
3+
description: Timberborn's prefab component system
4+
date: 2025-06-05
5+
tags: mods timberborn guide modding architecture prefab component
6+
---
7+

ModdingGuide/di.MD

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
---
2+
title: "Bindito"
3+
description: Timberborn's dependency injection framework
4+
date: 2025-06-05
5+
tags: mods timberborn guide modding architecture bindito di dependency injection
6+
---
7+
8+
Timberborn uses Bindito as its in-house dependency injection framework.
9+
10+
# Declaration & Injection
11+
12+
Since U7, you usually use `Configurator` classes to declare your services:
13+
14+
```cs
15+
[Context("MainMenu")]
16+
public class ModMenuConfig : Configurator
17+
{
18+
public override void Configure()
19+
{
20+
Bind<MSettings>().AsSingleton(); // Bind a class as a singleton service
21+
MultiBind<ISomeInterface>().ToExisting<MSettings>(); // Bind an interface to an existing singleton
22+
}
23+
}
24+
25+
[Context("Game")]
26+
public class ModGameConfig : Configurator
27+
{
28+
public override void Configure()
29+
{
30+
Bind<ISomeInterface>().As<SomeImplementation>(); // Bind an interface to its implementation
31+
MultiBind<TemplateModule>().ToProvider(() => GetTemplateModule()); // Bind a multibinding to a provider function
32+
33+
// Bind a class as a transient service,
34+
// meaning a new instance will be created every time it is requested
35+
Bind<MyClass>().AsTransient();
36+
}
37+
}
38+
```
39+
40+
You can use multiple `ContextAttribute` on the same class but in my experience, usually it is better to separate them into different classes because sometimes not all services are available in all contexts. For example, `CameraService` is not available in the main menu context.
41+
42+
You can then inject them to your services:
43+
44+
```cs
45+
public class MyService(
46+
MSettings settings, // Inject a singleton service
47+
ISomeInterface someInterface, // Inject an interface
48+
IEnumerable<TemplateModule> templateModules // Inject a multibinding
49+
) { }
50+
```
51+
52+
> **ℹ️ Note:**
53+
> In multibindings, you can inject them even if no implementation is bound. You will just get an empty collection. However, if you inject a single service that is not bound, it will throw an exception. Be aware of cyclic dependencies as well, Bindito will throw an exception if it detects a cycle.
54+
55+
In some cases, you cannot use constructor injection, for example `BaseComponent` or `MonoBehaviour` that must have a parameterless constructor. In that case, you can use `[Inject]` to inject the dependencies manually:
56+
57+
```cs
58+
public class MyComponent : BaseComponent
59+
{
60+
MSettings settings = null!;
61+
ISomeInterface someInterface = null!;
62+
63+
[Inject]
64+
public void InjectDependencies(MSettings settings, ISomeInterface someInterface)
65+
{
66+
this.settings = settings;
67+
this.someInterface = someInterface;
68+
}
69+
}
70+
```
71+
72+
- The method must be public. The name does not matter. You can have multiple methods with `[Inject]` attribute in the same class. It even works for inherited classes.
73+
74+
# Manually get a service
75+
76+
If you need to get a service manually, get a reference to `IContainer` service. I sometimes use this for UI elements:
77+
78+
```cs
79+
public class MyDialogController(IContainer container)
80+
{
81+
82+
public void Show()
83+
{
84+
// MyDialog is usually a transient service but it can be anything
85+
var diag = container.GetInstance<MyDialog>();
86+
}
87+
88+
}
89+
```
90+
91+
There is also the `IContainer.Inject` method that can inject dependencies into an existing object.
92+
93+
# Popular Multibindings
94+
95+
These are some popular multibindings I think you will use often:
96+
- `TemplateModule`: Used to [add a component to a prefab with another component](./timberborn-architecture#base-component).
97+
- `EntityPanelModule`: Add an info panel (the panel to the right of the screen when you select an entity). You can use [TimberUI](../TimberUI/) to make it easier.
98+
- `IDevModule`: Add debug commands to the game.
99+
- `IWaterStrengthModifier`: Used to modify the water strength of a `WaterSource`.
100+
101+
## TemplateModule
102+
103+
The game usually uses `TemplateModule` to add a component to a prefab. For example:
104+
105+
```cs
106+
protected override void Configure()
107+
{
108+
Bind<WaterStrengthService>().AsSingleton();
109+
MultiBind<TemplateModule>().ToProvider(ProvideTemplateModule).AsSingleton();
110+
}
111+
112+
private static TemplateModule ProvideTemplateModule()
113+
{
114+
TemplateModule.Builder builder = new TemplateModule.Builder();
115+
builder.AddDecorator<WaterSourceSpec, WaterSource>();
116+
builder.AddDecorator<WaterSource, DroughtWaterStrengthModifier>();
117+
118+
// ...
119+
120+
return builder.Build();
121+
}
122+
```
123+
124+
Which means, in the prefab, they only need to add `WaterSourceSpec` with all the required properties. Then, all prefabs with `WaterSourceSpec` will automatically have the `WaterSource` component and the `DroughtWaterStrengthModifier` component added to them.
125+
126+
So for example, in my [Moddable Weather](https://steamcommunity.com/workshop/filedetails/?id=3493039008) mod, I add the Monsoon and SurprisinglyRefreshing like this (using TimberUI's extension method to help with the syntax):
127+
128+
```cs
129+
configurator.BindTemplateModule(h => h
130+
.AddDecorator<WaterSource, MonsoonWaterStrengthModifier>()
131+
.AddDecorator<WaterSourceContamination, SurprisinglyRefreshingController>()
132+
// ...
133+
);
134+
```

ModdingGuide/index.MD

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ Useful external links:
2727
1. [Getting Started](./getting-started): Setting up your modding environment and making a simple code-less mod.
2828
2. [Modding Basics](./modding-basics): Make a simple C# mod for Timberborn.
2929
3. [Modding with Harmony and Mod Settings](./mod-settings-and-harmony): How to use Harmony to patch Timberborn's code and use Mod Settings to configure your mods.
30-
4. _(Optional)_ [Useful knowledge of Timberborn architecture](./timberborn-architecture): My experience and knowledge about Timberborn's codebase that may come in handy when making mods.
30+
4. _(Optional)_ [Useful knowledge of Timberborn architecture](./timberborn-architecture): My experience and knowledge about Timberborn's codebase that may come in handy when making mods:
31+
- [Dependency Injection](./di): How Timberborn uses Bindito as its in-house dependency injection framework.
32+
- [Base Component](./base-component): How Timberborn uses `BaseComponent` as the base class for all components.
3133
5. _(Optional)_ [Advanced Modding Techniques](./advanced-modding): Some techniques I use in my mods to make modding easier and less repetitive.
3234

3335
Extra useful stuff:
@@ -39,4 +41,5 @@ The following sections are more specific to certain types of mods that I made:
3941
1. [UI modding with TimberUi](./timber-ui): How to make UI mods for Timberborn using [TimberUi](../TimberUI).
4042
2. [Make a mod with Buff & Debuff mod](../BuffDebuff): Adding customizable buffs and debuffs to various in-game entities.
4143
3. [Make a mod with Scientific Projects mod](../ScientificProjects): Adding new research projects to the game.
42-
4. [Make a code-less mod (using JSON) with Moddable prefab](../ModdablePrefab): Adding components to a prefab or changing their values using JSON (Blueprints) files.
44+
4. [Make a code-less mod (using JSON) with Moddable prefab](../ModdablePrefab): Adding components to a prefab or changing their values using JSON (Blueprints) files.
45+
5. [Moddable Weather](../ModdableWeather/): Adding new weather to the game.

0 commit comments

Comments
 (0)