Skip to content

feat: real WorldGen + SimDLL physics for dedicated server#385

Open
zed-assistant[bot] wants to merge 26 commits intomain-aifrom
feature/game-loader
Open

feat: real WorldGen + SimDLL physics for dedicated server#385
zed-assistant[bot] wants to merge 26 commits intomain-aifrom
feature/game-loader

Conversation

@zed-assistant
Copy link

@zed-assistant zed-assistant bot commented Mar 20, 2026

Summary

Phase 2 of dedicated server (#383): real game world generation + SimDLL physics.

Screenshot

ONI Dedicated Server — real WorldGen + SimDLL

Real SandstoneDefault world (256x384) generated by the game's WorldGen pipeline, with SimDLL physics running at 5 ticks/sec. Web visualizer shows element overlay with 191 game elements.

What changed

  • Load all 191 elements from game YAML via ElementLoader.Load()
  • Run game's WorldGen pipeline (SandstoneDefault, 256x384, real biomes)
  • Initialize SimDLL for physics simulation (5 ticks/sec)
  • Frontend: dynamic element loading from /api/elements endpoint
  • All paths via environment variables (no hardcoded OS-specific paths)
  • ServerLauncher for standalone Mono execution

Environment variables

  • ONI_STREAMING_ASSETSrequired, path to game's StreamingAssets directory

How to run

# Build
dotnet build src/DedicatedServer/DedicatedServer.csproj -c Debug

# Set required env
export ONI_STREAMING_ASSETS="path/to/OxygenNotIncluded_Data/StreamingAssets"

# Run via ServerLauncher
mono src/DedicatedServer/bin/Debug/net48/ServerLauncher.exe

# Open http://localhost:8080

Next steps

Phase 3: multiplayer — connect clients via LAN transport.

zed-assistant bot added 16 commits March 19, 2026 13:30
Port the mod to compile against the latest ONI game DLLs (build 21518087).
API changes addressed:
- KObject.GetEventSystem() now returns bool with out parameter
- AccessControl.DefaultPermission → SetDefaultPermission
- SkillListable removed, replaced with IListableOption
- Chore.GetSMI() moved to protected StandardChoreBase, use reflection
- SafeCellMonitor type hierarchy changed (Def instead of object)
- ScheduleGroup constructor gained Color parameter
- PauseScreen.OnQuitConfirm() requires bool saveFirst
- Chore.addToDailyReport/reportType → GetReportType()
- DevTool/DevPanel/DevToolManager not available, excluded via csproj
Adapt test code to ONI API changes:
- PathProber is now static, remove AddComponent<PathProber>()
- Worker renamed to StandardWorker
- MinionConfig.MINION_NAV_GRID_NAME moved to TUNING.DUPLICANTSTATS
…t.Sdk)

Enable dotnet test execution by adding required NuGet packages and
IsTestProject property. Tests now run: 70 pass, 335 fail due to
HarmonyLib mprotect EACCES on macOS ARM64 (W^X security restriction).
Bump OniMinimumSupportedBuild from 577063 to 21518087 to match
the game version this PR was compiled against.
- SensorsPatch: prevent Sensors.Add() from calling sensor.Update() immediately,
  which crashed MingleCellSensor, ClosestEdibleSensor etc. during minion setup
- ScheduleManager: add to test setup so MingleCellSensor.IsAllowed() doesn't NPE
- ChoreConsumerStatePatch: null-safe Schedule resolution in constructor (game
  code bug: GetSchedule() can return null but ctor doesn't check)
- MinionIdentityPatch: suppress Debug.LogError during OnSpawn when Personality
  DB is empty (test environment has no personality data)
- AbstractChoreTest DI: inject ChoreExtensions dependency (was missing,
  causing NPE in chore.Register())
- PlayableGameTest TearDown: comprehensive singleton cleanup (~30 singletons)
  to prevent cross-test contamination
- Unity mock patches: SystemInfo.processorCount, MonoBehaviour stubs,
  Object companion registration
- ChoresPatcher: fix Chore constructor access (became protected),
  handle abstract Cleanup method
…ssion

- Add TestPersonalitiesCsv constant with valid personality entry ("TestDupe")
- Set MinionIdentity.personalityResourceId to match test personality
- Remove MinionIdentityPatch (SuppressErrors hack no longer needed)
- Revert DebugLogHandlerPatch to original behavior (always throw on LogError)
- Revert unnecessary whitespace change in BehaviourPatch
- .NET 4.8 console app with HttpListener web server
- Mock world state: 64x64 grid with ONI elements, temperature, mass
- React + TypeScript + Vite frontend with Canvas 2D renderer
- Three overlay modes: elements, temperature, mass
- Zoom, pan, cell tooltips, entity markers
- API endpoints: /api/world, /api/entities, /api/state
- Vite proxies /api to backend in dev, builds to wwwroot for production
- Skip AssemblyExposure for DedicatedServer project
- Add /decompiled/ to .gitignore (game IP protection)
…world boundary outline

- Add LibNoiseDotNet, ImGui, Ionic.Zip references (fixes assembly load failure)
- Fix RealWorldState to safely read Grid data (Grid.Mass crashes process)
- Add world boundary outline to visualizer (vacuum was invisible against background)
- Rebuild web client with boundary fix
- Register 11 elements (Vacuum, Oxygen, CO2, Water, Granite, etc.)
  matching frontend's hardcoded indices in constants.ts
- Populate Grid cells with procedural world: rock floor, resource zone,
  habitable area with oxygen, water pool, cold zone, vacuum top
- Fix Grid memory: use GCHandle.Alloc(Pinned) instead of fixed() blocks
  that lose pinning after scope (caused garbage data in long-running server)
- Add /api/elements endpoint returning element registry (id, name, state)
- RealWorldState now returns element mass from defaults
- GameLoader now loads all 191 elements from game's YAML files
  (bypass SubstanceTable, create stub Substances)
- Patches Application.streamingAssetsPath to real game path
- Initializes SimDLL: SIM_Initialize → CreateSimElementsTable →
  SimDataInitializeFromCells → Start (Grid points to DLL memory)
- Simulation tick loop runs at 200ms intervals
- WorldGen attempted but falls back to procedural world
  (noise generation needs CustomGameSettings fix - TODO)
- Frontend: dynamic element loading from /api/elements
  (supports 191+ elements with auto-generated colors)
- RealWorldState reads Grid.mass from SimDLL-owned memory
- Fix WorldGen: call SetWorldSize() before GenerateOffline()
  (matches Cluster.BeginGeneration flow)
- Fix DebugLogHandlerPatch: test patch throws on LogError,
  but WorldGen uses Debug.Assert for non-fatal warnings.
  Added SoftDebugLogHandler with Priority.First to log instead
- Fix ElementLoader: populate elementTagTable (needed by
  EnsureEnoughElementsInStartingBiome)
- Remove procedural fallback — WorldGen is the only path now
- SandstoneDefault 256x384 generates real biomes + SimDLL physics
- Initialize GenericGameSettings._instance via reflection
  (prevents NPE in WorldGen error reporting)
- Patch ReportWorldGenError to skip KCrashReporter calls
- Remove CustomGameSettings.Awake() from InstallPatches
  (KMonoBehaviour needs full game init first)
- Remove compiled wwwroot/assets/ from git (add to .gitignore)
- Update web-client README with actual build/run instructions
- Assets are embedded as resources in DedicatedServer.csproj
/// <summary>
/// Generate a real ONI world using the game's WorldGen pipeline.
/// </summary>
private WorldGenResult? GenerateWorld() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems to be a lot of code. Can we somehow just call game library to generate it? Without repeating their logic?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — now calls ElementLoader.Load() directly with stub SubstanceTables. All the manual YAML parsing and element creation code has been removed.

- Remove MockWorldState — no longer needed with real WorldGen
- Use game's ElementLoader.Load() directly instead of reimplementing
  YAML parsing and element creation logic
- Make StreamingAssets path configurable: auto-detect from common
  Steam paths (macOS/Linux/Windows) or ONI_STREAMING_ASSETS env var
- Simplify ServerBootTest to thin wrapper
- WebServer returns 503 when world not loaded instead of mock data
zed-assistant bot added 9 commits March 20, 2026 10:52
- All paths via env variables only (ONI_STREAMING_ASSETS required)
- Remove hardcoded macOS/Linux/Windows Steam paths from GameLoader
- Remove hardcoded Steam path from Program.cs assembly resolver
- Add ServerLauncher.cs — loads DedicatedServer via reflection to
  work around Harmony self-test deadlock on standalone Mono
- Update run-server.sh to use ServerLauncher instead of dotnet test
- Add StartupObject to resolve duplicate entry point (Program vs TestHost)
- Add missing System.Collections.Generic using
- Fix ElementLoader.path via Harmony prefix on CollectElementsFromYAML
- FileSystem.Initialize() for game YAML loading
- StubManifestSubstance via Harmony (bypass Unity SubstanceTable)
- Fix MISSING.STRINGS element names — use tag name (elementId) when
  localization strings not loaded
- Add App.config with useLegacyV2RuntimeActivationPolicy (needed for
  Harmony on standalone Mono)
- Remove ServerBootTest.cs — use ServerLauncher as entry point
- Remove DefaultWidth/Height constants — WorldGen sets size from settings
- Revert PatchesCompatibility.cs to main-ai state
- Remove useLegacyV2RuntimeActivationPolicy from App.config
- Fix grid rendering gaps between cells in visualizer
- Fix sub-pixel grid artifacts (Math.round instead of +0.5 overlap)
- Element names use tag.Name fallback (localization not available headless)
- Move width/height init to Boot() with clear comment
- Re-add ServerBootTest as temporary entry point until Unity Mono ready
MonoMod's DeterminePlatform() blocks forever on macOS Rosetta
because it spawns `uname` and StreamReader.ReadLine() hangs.
Pre-setting PlatformHelper.Current = MacOS via reflection before
any Harmony use skips the broken auto-detection.

Server now runs with plain `mono DedicatedServer.exe` —
no test runner needed.
@Lyraedan
Copy link

If the simulation is suppose to be running with no clients connected in a headless manner would this not mean a colony would just die out when no players are connected?

Also what's the plan with things such as colonists, AI, critters etc.

@edunad
Copy link

edunad commented Mar 21, 2026

If the simulation is suppose to be running with no clients connected in a headless manner would this not mean a colony would just die out when no players are connected?

Also what's the plan with things such as colonists, AI, critters etc.

It should probably auto-pause if clients aren't on the server (could be a option)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants