Skip to the content.

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.

Publicizer

Feel free to use my Publicizer. 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.

Beside the game’s assemblies, I also publicize some other mods’ assemblies in there. See below on how to refer them.

Project Structure

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 has this .csproj file:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputModFolderName>ScientificProjects</OutputModFolderName>
        <GameSolutionFolder>..\..\</GameSolutionFolder>
    </PropertyGroup>
    <Import Project="../../Common.target" />
    <Import Project="../../CommonTimberUI.target" />
    <Import Project="../../CommonBuffDebuff.target" />
</Project>

Feel free to check the .targert files in my TimberbornMods repository. For example, the Common.target with added explanations:

<!-- I even modularize the Common.target file further -->
<Import Project=".\CommonProperties.target" />
<Import Project=".\CommonGlobalUsings.target" />

<!-- Define where the mod will be output in each csproj file -->
<Target Name="Validate">
    <Error Condition="'$(OutputModFolderName)'==''" Text="OutputModFolderName was not specified" />
</Target>

<!-- General properties -->
<PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
    <LangVersion>preview</LangVersion>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <DebugSymbols>true</DebugSymbols>
    <DebugType>embedded</DebugType>
</PropertyGroup>

<!-- Copy the built files to the Timberborn mod folder -->
<Target Name="CopyFiles" AfterTargets="PrepareFilesForCopy">
    <Message Text="Deleting..." />
    <RemoveDir Directories="$(ModFolder)" />

    <Message Text="Copying..." />
    <Copy SourceFiles="@(ModManifestFile)" DestinationFolder="$(ModFolder)" />
    <!-- ... -->
</Target>

<!-- Use the publicized and other assemblies -->
<ItemGroup>
    <!-- IgnoresAccessChecks.cs is needed to use the publicized assemblies -->
    <Compile Include="$(GameSolutionFolder)GameAssemblyPublicizer\IgnoresAccessChecks.cs" Link="IgnoresAccessChecks.cs" />

    <!-- Refer to all the Publicized assemblies -->
    <Reference Include="$(GameSolutionFolder)GameAssemblyPublicizer\out\common\**\*.dll">
        <Private>false</Private>
    </Reference>

    <!-- These are not publicized but sometimes we need them -->
    <Reference Include="$(AssemblyPath)\System.Collections.Immutable.dll">
        <Private>false</Private>
    </Reference>
    <Reference Include="$(AssemblyPath)\Newtonsoft.Json.dll">
        <Private>false</Private>
    </Reference>
</ItemGroup>

Other .target are for projects that only use a certain feature like CommonTimberUI or CommonHarmony.

Find components without Unity

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 to map the UUIDs to the actual component names.

You simply need to replace the FileInput constant and run it. It will search for all the UUID and print out the relevant files.