Core components
The mod consists of these key architectural pieces:Plugin class
The entry point for the BepInEx mod loader. Located atPlugin.cs:12-33.
Load() method creates a Harmony instance and automatically patches all classes marked with [HarmonyPatch] attributes.
Static tracker pattern
All game object tracking uses static classes for simplicity and global access:- ChestTracker (
Plugin.cs:99-109) - Tracks total and unopened chests - ShadyGuyTracker (
Plugin.cs:112-124) - Tracks ShadyGuy spawns, interactions, and disappearances - ChargeShrineTracker (
Plugin.cs:127-139) - Tracks charge shrine states and completion - MoaiTracker (
Plugin.cs:141-151) - Tracks Moai shrine spawns and interactions
Reset() method:
OverlayManager
Manages the lifetime of the on-screen GUI overlay (Plugin.cs:37-95).
Key responsibilities:
- Creates and manages the overlay GameObject
- Persists across scene loads using
DontDestroyOnLoad - Provides cleanup methods for round transitions
- Coordinates tracker resets
ChestOverlay component
A Unity MonoBehaviour that renders the GUI overlay (Plugin.cs:154-240).
Features:
- Immediate mode GUI (OnGUI) rendering
- Semi-transparent background box
- Text shadows for readability
- Positioned at bottom-left of screen
- Displays all tracker values in real-time
Harmony patching strategy
SpawnTracker uses Postfix patches exclusively to observe game events without modifying behavior:- Spawn detection: Patches
SpawnInteractablesmethods to count spawned objects - Interaction tracking: Patches
Interact()methods on interactable types - State changes: Patches shrine
Complete()and ShadyGuyDisappear()methods - Round lifecycle: Patches
GameManagermethods for round start/end detection
Plugin.disableTracker flag to prevent tracking outside of active rounds.
Data flow
- Game initialization: BepInEx loads the Plugin, which applies Harmony patches
- Round start:
GameManagerpatches detect round start and enable tracking - Object spawn: Spawn patches increment tracker totals
- Player interaction: Interaction patches update tracker state
- UI update: ChestOverlay reads tracker values each frame in
OnGUI() - Round end: Death/destroy patches disable tracking and reset counters
Component diagram
Threading and lifecycle
All tracking happens on Unity’s main thread. The mod uses:- Static state: All trackers are static classes (no instances)
- Scene persistence: Overlay uses
DontDestroyOnLoadto survive scene changes - Cleanup hooks:
OnDisableandOnDestroycallSafeCleanup()to prevent leaks - Round isolation: Tracking is disabled between rounds via
disableTrackerflag
Extension points
To add tracking for new object types:- Create a new static tracker class following the existing pattern
- Add Harmony patches for spawn and interaction events
- Update
ChestOverlay.OnGUI()to display the new tracker - Add
Reset()call toOverlayManager.SafeCleanup()