| Game build | 24862398 (Win64), Unity 6000.0.65f1 |
| Scripting backend | IL2CPP, global-metadata.dat v31 |
| Loader | BepInEx 6.0.0-be.785 (Unity.IL2CPP, win-x64) |
| Plugin target | net6.0, no reference to any game assembly |
Developed against the Windows build, run both natively and under Proton on Linux; the mod
itself is a managed DLL and does not care which. The scripts resolve the install
themselves — see scripts/lib/gamedir.sh, or set GAME_DIR.
The build is not obfuscated — every type, method and field name in the metadata is
plaintext, so dump/cs/ reads like ordinary source.
src/VicMod/ the plugin
Plugin.cs entry point; loads features, one config toggle + error boundary each
Interop.cs name-based lookup into the Il2CppInterop proxy assemblies
ProbeEngine.cs the reflection + JSON half of the Probe feature
VMesh.cs the .vmesh reader
Features/ one file per feature
meshes/ the .vmesh files BodyMesh ships. Also the authoring source of record:
meshedit.sh --shipped reopens one as an editable .blend
scripts/
lib/gamedir.sh locate the game install; sourced by everything below
build.sh build + copy into the game
dump.sh Cpp2IL + ilspycmd -> dump/ (run after every game update)
log.sh tail BepInEx/LogOutput.log, filtered to VicMod
commands.sh regenerate docs/commands.md from the dump
meshexport.sh resources.assets -> work/mesh/<name>.vmesh, the stock extract
meshedit.sh a .vmesh -> an editable .blend (refuses to clobber; --force to insist)
meshinstall.sh an edited .blend -> repair pass -> src/VicMod/meshes/<name>.vmesh
lib/ the Python behind the three mesh scripts; run under Blender or uv
mesh.sh DEAD: the abandoned in-place resources.assets patch
meshsculpt.sh DEAD: drives the same abandoned route
docs/
features.md per-feature reference: what each changes and every config key
meshes.md the body mesh pipeline
internals.md this file
commands.md every console command in the build (API discovery aid)
work/ sculpting scratch, NOT in git -- extracts, .blend files, preview renders.
removed/ retired code, which IS in git because docs point at it
tools/ cpp2il binary, BepInEx zip (not in git)
dump/ decompiled game code (not in git)
CLAUDE.md orientation for a fresh session: hazards, current state, open threads
Il2CppInterop generates C# proxy assemblies from one specific build's metadata, and the generated member tokens shift between builds. A mod compiled against build A's proxies throws on build B even when the underlying game code is identical — which is why most of the Nexus mods for this game are dead rather than wrong.
Interop.cs looks types and methods up by name at runtime instead. It costs a dictionary
lookup at startup and survives updates that only move tokens. If a feature ever needs
strongly-typed access, set UseInteropRefs=true in VicMod.csproj after launching the
game once so BepInEx/interop/ exists — but prefer keeping features name-resolved.
./scripts/dump.sh && ./scripts/commands.sh
git diff docs/commands.md
Anything a feature named by string and can no longer find is logged as
[!] <Feature> failed to apply and was skipped — the game still boots.
If the body meshes changed, re-run ./scripts/meshexport.sh and redo the sculpt against the
new extraction: a .vmesh is a snapshot of one build's art, not something the game keeps in
sync, so a stale one silently reverts an art update on every body it replaces.
- Multiplayer is Netcode for GameObjects over Steam sockets. Anything on a
NetworkSystemis server-authoritative — test features that touch networked state in singleplayer first. - Method bodies in
dump/arethrow null— Cpp2IL recovered signatures and attributes but not IL for this build. Signatures are enough for name-based patching. For actual logic, add--output-as isiltodump.shor openGameAssembly.dllin Ghidra at the[Address(RVA = ...)]listed on the method.