Home / Forums / Phasmophobia Internal Menu: Reversing GhostAI, Sanity & Evidence States in Unity

UnreliableCode Community

Developer Research, Reverse Engineering & Coding Community

Release

Phasmophobia Internal Menu: Reversing GhostAI, Sanity & Evidence States in Unity

GhostHunter_x
Unity & Phasmo Modder
VIP
Rep: 275
Join Date: Apr 2023
Posts: 17
Thanks: 71
2y ago · Feb 18, 2024 3:40 PM
#1
Hey everyone,
Sharing an architectural breakdown of how to build a clean internal GUI menu for Phasmophobia (Unity IL2CPP/Mono runtime) using Dear ImGui and IL2CPP domain inspection.

1. Locating the GhostAI Instance:
In Phasmophobia, the main ghost behavior and state variables are managed by
CPP
GhostAI
and
CPP
GhostTraits
singletons:

CPP
// Conceptual C# / IL2CPP struct representation
public class GhostAI : MonoBehaviour {
    public GhostTraits ghostTraits;
    public GhostInteraction ghostInteraction;
    public bool isHunting;
    public float huntingSpeed;
    public GhostState currentState; // Idle, Wandering, Hunting, Interacting
}

public class GhostTraits {
    public GhostType ghostType; // Spirit, Wraith, Phantom, Demon, Revenant, etc.
    public GhostEvidence[] evidenceList; // EMF5, Fingerprints, Freezing, GhostOrb, etc.
    public float favoriteRoomTemperature;
}


2. Reading Player Sanity & Fuse Box Status:
Player sanity levels are stored in
CPP
PlayerSanity
or
CPP
PlayerData
:
CPP
float currentSanity = pPlayerInstance->playerSanity->sanityLevel;


3. Drawing the ImGui Menu Window:
CPP
void RenderPhasmoMenu() {
    ImGui::Begin("Phasmophobia Research Assistant v2.4", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
    
    if (ImGui::CollapsingHeader("Ghost Intel", ImGuiTreeNodeFlags_DefaultOpen)) {
        ImGui::Text("Ghost Type: %s", GetGhostTypeName(g_GhostAI->ghostTraits->ghostType));
        ImGui::Text("Current State: %s", g_GhostAI->isHunting ? "[!] HUNTING [!]" : "Passive / Wandering");
        ImGui::Text("Ghost Room: %s", g_GhostAI->favoriteRoomName);
        ImGui::ProgressBar(g_GhostAI->huntingSpeed / 3.0f, ImVec2(200, 0), "Hunting Speed");
    }
    
    if (ImGui::CollapsingHeader("Evidence Auto-Tracker")) {
        for (auto& evidence : g_GhostAI->ghostTraits->evidenceList) {
            ImGui::BulletText("Required: %s", GetEvidenceName(evidence));
        }
    }
    
    if (ImGui::CollapsingHeader("ESP & Visuals")) {
        ImGui::Checkbox("Draw Ghost 3D Box ESP", &g_Config.GhostESP);
        ImGui::Checkbox("Draw Fuse Box (Breaker) ESP", &g_Config.BreakerESP);
        ImGui::Checkbox("Draw Cursed Possessions (Tarot, Mirror, Ouija)", &g_Config.CursedESP);
        ImGui::Checkbox("Draw Bone / Evidence Item ESP", &g_Config.BoneESP);
    }
    
    ImGui::End();
}


Feel free to ask any questions about hooking the DirectX Present loop or resolving IL2CPP method pointers!
GhostHunter_x · Phasmophobia & Unity Reverser
GhostAI, Sanity, EMF & Evidence inspection
The following users thanked GhostHunter_x for this post:
ParanormalDev
MelonLoader / BepInEx Dev
MEMBER
Rep: 230
Join Date: Sep 2023
Posts: 21
Thanks: 58
2y ago · Feb 18, 2024 5:15 PM
#2
Super clean writeup! For anyone using MelonLoader or BepInEx on Unity games, you can also hook
CPP
GhostAI.Start()
and store the static reference in a cached field:
CSHARP
[HarmonyPatch(typeof(GhostAI), "Start")]
public class GhostAIPatch {
    public static GhostAI Instance;
    public static void Postfix(GhostAI __instance) {
        Instance = __instance;
    }
}

This avoids doing expensive
CODE
GameObject.FindObjectOfType<GhostAI>()
calls every frame inside your OnGUI/ImGui render loop!
ParanormalDev | MelonLoader & ImGui Modding
RustMechanic
Unity & IL2CPP Reverser
VIP
Rep: 295
Join Date: Nov 2022
Posts: 32
Thanks: 74
2y ago · Feb 18, 2024 7:30 PM
#3
Caching instances on
CODE
Start()
or
CODE
Awake()
via Harmony/IL2CPP hooks is always best practice in Unity games. Prevents GC pressure and stuttering.
RustMechanic | IL2CPP & Unity Engine Analysis
ZeroMemory
Member
MEMBER
Rep: 75
Join Date: Oct 2024
Posts: 32
Thanks: 18
2y ago · Feb 19, 2024 10:05 AM
#4
Originally Posted by @GhostHunter_x
Draw Cursed Possessions (Tarot, Mirror, Ouija)

This is awesome! Having ESP for the Bone and Cursed item makes finding the hidden objectives so much faster. Thanks for sharing the struct details!
ZeroMemory · Always experimenting