Modding Oxygen Not Included (ONI) is an adventure in itself, but recently I undertook a project to fix a persistent strings issue in a dirt tile mod. I can see why nobody has fixed it. It was not straightforward. The problem? The mod allowed you to build dirt tiles, but the game kept showing MISSING.STRINGS.MISC.TAGS.DIRT instead of the proper name. After countless hours of troubleshooting, dependency wrangling, and code editing, I finally got it working. Here’s the full journey.
For the original repository please see https://github.com/ecool/ONI-Mods

Step 1: Understanding the Problem
The original mod was written for pre-U52 versions of ONI. With U52:
- The string system changed significantly, so old mods often report missing strings for materials like Dirt.
 - Assigning raw elements directly (like 
SimHashes.Dirt) to a building’s construction caused string corruption. - API changes meant 
PlanScreen.PlanInfo.datawas now obsolete. While this didn’t break the mod, it threw warnings. 
Our mission became clear: modernize the mod so that it works with the new string system and uses proper material categories.
Step 2: Preparing the Development Environment
Before touching code, I needed a working project environment. This was non-trivial, because ONI mods rely on multiple dependencies:
- Game DLLs from ONI itself: copy them all if in doubt
- Assembly-CSharp.dll
 - Assembly-CSharp-firstpass.dll
 - UnityEngine.dll
 - UnityEngine.CoreModule.dll
 - 0Harmony.dll
 
 - Mod helper DLLs:
- CaiLib.dll
 - CoolLib.dll
 
 
These DLLs needed to be collected, referenced in the project, and in the right folder structure. The ONI game DLLs sat in vendor\ONI-DLC, and mod helper DLLs sat in vendor\.
We also needed NuGet packages, most importantly Newtonsoft.Json 12.0.2, which the project used:
dotnet add package Newtonsoft.Json --version 12.0.2
This resolved namespace errors like:
CS0246: The type or namespace name 'Newtonsoft' could not be found
Step 3: Cleaning the Environment
Before building, I had to make sure no leftover artifacts interfered with the build. This included:
rd /s /q bin
rd /s /q obj
dotnet nuget locals all --clear
Then restoring NuGet packages freshly:
dotnet restore
This prevented duplicate reference warnings and ensured a clean build environment.
Step 4: Fixing Project References
Even with all DLLs in the right folders, the project file initially failed to compile. The issues included:
- CoolLib and CaiLib not being recognized.
 - Newtonsoft.Json not found.
 - Old MSBuild paths pointing incorrectly to ONI DLLs.
 
We fixed this by editing the .csproj:
<Reference Include="CaiLib">
  <HintPath>vendor\CaiLib.dll</HintPath>
</Reference>
<Reference Include="CoolLib">
  <HintPath>vendor\CoolLib.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
  <HintPath>vendor\Newtonsoft.Json.dll</HintPath>
</Reference>
– Vendor DLLs were now accessible to the compiler.
– Removed old duplicates of Newtonsoft.Json references to eliminate NU1504 warnings.
Step 5: Updating the Dirt Tile Configuration
The core of the problem was the missing strings. The original mod tried to register them directly:
Strings.Add("STRINGS.ELEMENTS.DIRT.NAME", "Dirt");
Strings.Add("STRINGS.ELEMENTS.DIRT.DESC", Description);
Strings.Add("STRINGS.ELEMENTS.DIRT.EFFECT", Effect);
But in U52+, this no longer worked because:
- Direct element assignment in building materials causes string corruption.
 - The game now requires material categories instead of specific elements to display strings correctly.
 
So we updated the building definition:
string[] construction_materials = MATERIALS.ALL_BUILDABLE;
float[] construction_mass = BUILDINGS.CONSTRUCTION_MASS_TIER1;
And kept string registration in DoPostConfigureComplete so Dirt displayed correctly in-game.
Step 6: Compiling and Merging DLLs
Once the references and code were fixed:
dotnet build -c Release
Merged DLLs using ilmerge:
&lt;PostBuildEvent&gt;
  ilmerge /wildcards /out:BuildableDirtTile-merged.dll BuildableDirtTile.dll vendor\*.dll /targetplatform:v2,C:/Windows/Microsoft.NET/Framework64/v4.0.30319
&lt;/PostBuildEvent&gt;
Copied the merged DLL to the mods/dev folder of ONI.
Getting ilmerge to work with all dependencies was a mammoth task. It required exact paths, wildcards, and knowledge of which assemblies were required at runtime.
Step 7: Testing in Game
After enabling the mod:
- The mod loaded separately from the Steam version.
 - Strings no longer showed as missing. ✅
 - Tiles displayed correctly, and construction worked.
 
A warning about PlanScreen.PlanInfo.data being obsolete appeared, but it didn’t break functionality:
PlanScreen.PlanInfo.data' is obsolete: 'Modders: Use ModUtil.AddBuildingToPlanScreen'
Step 8: Lessons Learned
- DLL management is critical: Every dependency must be referenced and present at runtime.
 - Material categories matter: Direct element references in building costs cause string corruption in U52+.
 - API changes matter: Obsolete warnings hint at future-proofing needs.
 - Persistence pays off: Cleaning 
bin/objand NuGet caches often resolves mysterious build errors. - Patience is key: The journey from build errors to a working merged DLL took multiple iterations.
 
Conclusion
After a month of troubleshooting, code changes, and dependency wrangling, the Dirt Tile mod finally works with U52+ ONI:
- Strings display correctly.
 - Tiles can be built without breaking the UI.
 - The mod is fully separated from Steam Workshop dependencies.
 
This experience reinforced that modding isn’t just coding—it’s dependency management, environment setup, and problem-solving all rolled into one.