Skip to content

Latest commit

 

History

History
87 lines (72 loc) · 4.2 KB

File metadata and controls

87 lines (72 loc) · 4.2 KB

Internals

Target

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.

Layout

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

Why this project resolves types by name

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.

After a game update

./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.

Notes

  • Multiplayer is Netcode for GameObjects over Steam sockets. Anything on a NetworkSystem is server-authoritative — test features that touch networked state in singleplayer first.
  • Method bodies in dump/ are throw 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 isil to dump.sh or open GameAssembly.dll in Ghidra at the [Address(RVA = ...)] listed on the method.