Guidebook CSharp 04 Patches
Patch game methods with Harmony without hurting performance or the IL2CPP runtime. Rule source: docs/modding/harmony-il2cpp.md. Example neighbors: src/gregCore.Patches/ (RackPatch, ShopPatch, PlayerPatch, TimePatch, …).
Style: one task per class
Section titled “Style: one task per class”public sealed class RepairLogPatch : SafePatch{ // Explicit PatchAll from your OnLoad/OnReady; try/catch inside; // Prefix returns true (run original) or false (skip it) — deliberately.}- Derive from
SafePatch; explicitPatchAll, never blanket-apply. - Small defensive Prefix/Postfix pairs; emit events (
greg.RACK.*,greg.SYSTEM.ButtonCheckOut) instead of duplicating logic. - Dynamic bulk patching goes through
GregDynamicHookPatcher+HookIntegration(driven bygame_hooks.json); your hand-written patches cover what the dispatcher cannot.
Performance rules
Section titled “Performance rules”- No per-frame reflection: cache
Type.GetType/MethodInfoonce. - No
FindObjectsOfTypeinOnUpdate: cache holders; throttle scans in tiers (0.1 s / 1 s / 2 s / 30 s). - Event-state over polling (
PortSpeedMemorypattern); route bursts viaGregOperationQueue; budgets viaGregPerformanceGovernor/GregResourceMonitor/GregPerformancePatches(incl.WorldCanvasCuller, technician/footstep/indicator throttles).
IL2CPP pitfalls
Section titled “IL2CPP pitfalls”Il2CppReferenceArray: copy/extend properly (shop rows, dropdowns viaIl2CppSystem.Collections.Generic.List<string>).Nullable<Color>needs explicit handling;renderer.materialsclones — mutate the clone.- Never cache Il2Cpp objects long-term (GC moves them); re-resolve via inventory UIDs (Guidebook CSharp 05 Saves Shop).
- Inactive
DontDestroyOnLoadholders for must-keep state;DelegateSupport.ConvertDelegatefor managed→Il2Cpp callbacks.
After a game update
Section titled “After a game update”- Run the game once with the loader; re-copy
Il2CppAssemblies+net6intoreferences/. tools/GameApiGenerator/regenerate.sh→ reviewsrc/gregCore.GameApi/Generated/.scripts/Generate-GregHooksFromIl2CppDump.ps1→ reviewgame_hooks.json→ curateframework/greg_hooks.json.scripts/validate_contracts.py+scripts/check-coverage.sh+dotnet test; vanilla-first test (no mods → loads → enable yours).
Exercises
Section titled “Exercises”- Write a postfix that logs one shop checkout (
greg.SYSTEM.ButtonCheckOutexists — prefer subscribing; patch only what events cannot reach). - Convert a per-frame scan to a 1 s throttled cached scan; measure the log silence.
Checkpoint
Section titled “Checkpoint”- One explicit patch class, applied + logged (
PatchApplied), removable without residue.
Next: Guidebook CSharp 05 Saves Shop — sidecars, inventory, shop items.