Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ASTRA228b/Experimental/llms.txt

Use this file to discover all available pages before exploring further.

Experimental is a BepInEx plugin that bootstraps itself into Gorilla Tag by creating two persistent GameObject hierarchies at startup, then drives all mod logic through Unity’s standard Update, FixedUpdate, and OnGUI MonoBehaviour callbacks. Understanding this structure is essential for adding new mods or debugging existing ones.

BepInEx Entry Point — Plugin

The plugin is identified by the BepInEx attribute:
[BepInPlugin("Astras.Mods.Experimental", "Experimental", "0.0.4")]
public class Plugin : BaseUnityPlugin
Plugin itself is a thin bootstrapper. All real work is delegated to the components it attaches to persistent GameObjects.

Startup Sequence

Plugin.Awake()
  ├─ new GameObject("Experimental.UIS")
  │    ├─ AddComponent<Main>()               ← IMGUI window + mod orchestration
  │    └─ AddComponent<ControllerSystemManager>()
  └─ DontDestroyOnLoad(go)

Plugin.Start()
  └─ PatchLoader.Apply()                     ← Harmony patches
Awake runs before Start, so the persistent objects and their components exist before any Harmony patches are applied.

Persistent GameObjects

Experimental creates two DontDestroyOnLoad GameObjects that survive scene transitions:
Created directly in Plugin.Awake(). Hosts the two primary MonoBehaviours:
ComponentRole
MainIMGUI window rendering, mod tab dispatch, Update / FixedUpdate orchestration
ControllerSystemManagerCreates the second persistent object (see below)
Created inside ControllerSystemManager.Awake(). Hosts the two secondary MonoBehaviours:
ComponentRole
ATurnModControllerSmooth and snap turn logic, runs in FixedUpdate
PitGeoManagerScene-object search (Update) and surface-multiplier application (FixedUpdate)
Both GameObjects are marked DontDestroyOnLoad, so they persist across every Gorilla Tag map load and Photon room transition without needing to be re-created.

Update Loop Breakdown

Each Unity callback has a distinct responsibility:
Runs every GUI render frame.
  1. On the first call, checks the SLoaded flag and calls GlobalStyles.INIT() once to initialize all shared GUIStyle objects — lazy initialization is used because IMGUI styles cannot be created outside of a GUI event.
  2. Renders the main mod window using GUILayout.Window.
  3. Calls each sub-mod’s UI method directly (PullModUI.MakeUI(), ApredsUI.MakePredsUI(), PSAModUI.MakePSAModUI(), etc.) so each can draw its own controls.
Runs every frame (variable rate).
  • Polls the E key to toggle the main menu window open/closed.
  • Calls ApredsUI.RunMod() — the Apreds locomotion mod’s per-frame logic.
Runs at a fixed physics timestep (default 50 Hz).Calls, in order:
CallMod
PullModUI.RunMods()Pull / attract locomotion
GorillaTimeUI.RunTMod()Gorilla Time slow-motion effect
PSAModUI.RunPSAMod()PSA (position-set assist) mod
VelMaxUI.RunVMod()Velocity cap / max speed
WallWalkUI.RunWalkerMod()Wall-walk surface detection
Handles smooth-turn (continuous rotation) and snap-turn (discrete angle steps) independently of Main. Running in its own component on a separate GameObject means turn logic is isolated from the main mod window and cannot be accidentally disabled by UI state.
  • Update: searches the scene for target geometry objects by name.
  • FixedUpdate: applies the configured surface friction / speed multiplier to any geometry found by Update.

Harmony Patch System

All Harmony patches are applied in a single call during Plugin.Start():
public static void Apply()
{
    Harmony VALLL = new Harmony(Constantss.GUID);
    VALLL.PatchAll();
}
PatchAll() scans all types in the assembly for methods decorated with [HarmonyPatch] and applies them automatically. Current patch file — JoinAndLeave.cs Contains JoinManager, a MonoBehaviour whose Update method polls PhotonNetwork.InRoom each frame to detect room state transitions (join and leave events), then fires OnScreenNotify.SendIT(...) to display the appropriate on-screen message.
To add a new Harmony patch, create a new class with [HarmonyPatch] attributes in the assembly. PatchLoader.Apply() will pick it up automatically — no registration step required.

Shared State — GlobalVars

GlobalVars acts as the mod’s central state store: a static class holding flags, cached references, and configuration values that multiple mods and UI classes need to read or write. Because all mod logic runs on Unity’s main thread, no locking is required.
Avoid caching GlobalVars references in local variables across frames. Always read directly from the static fields to ensure you see the most current value, especially for flags that can be toggled by user input each frame.

Build docs developers (and LLMs) love