From 60f6db4fb6f48333133d1a553cfcd63b274406d3 Mon Sep 17 00:00:00 2001 From: Indra Date: Sun, 21 Jan 2024 17:05:55 +0100 Subject: [PATCH] Add event debug --- src/Hook.cpp | 2 + src/game/Game.cpp | 5 ++ src/game/Game.h | 2 + src/level/Event.cpp | 9 ++ src/level/Event.h | 22 +++++ src/level/Level.h | 111 +++++++++++++++++++++++++ src/level/Stream.h | 24 ++++++ src/modules/InstanceViewer.cpp | 2 +- src/modules/Level.cpp | 147 +++++++++++++++++++++++++++++++++ src/modules/Level.h | 20 +++++ 10 files changed, 343 insertions(+), 1 deletion(-) create mode 100644 src/level/Event.cpp create mode 100644 src/level/Event.h create mode 100644 src/level/Level.h create mode 100644 src/modules/Level.cpp create mode 100644 src/modules/Level.h diff --git a/src/Hook.cpp b/src/Hook.cpp index da8966f..7667dc3 100644 --- a/src/Hook.cpp +++ b/src/Hook.cpp @@ -15,6 +15,7 @@ //#include "modules/Draw.h" #include "modules/Log.h" #include "modules/ScriptLog.h" +#include "modules/Level.h" #include "cdc/render/PCDeviceManager.h" @@ -116,6 +117,7 @@ void Hook::RegisterModules() RegisterModule(); #ifndef TR8 + RegisterModule(); //RegisterModule(); //RegisterModule(); #else diff --git a/src/game/Game.cpp b/src/game/Game.cpp index 30d1eb2..fe09907 100644 --- a/src/game/Game.cpp +++ b/src/game/Game.cpp @@ -12,6 +12,11 @@ GameTracker* Game::GetGameTracker() return (GameTracker*)GET_ADDRESS(0x10E5370, 0x838330, 0x00E7F088); } +STracker* Game::GetStreamTracker() +{ + return (STracker*)GET_ADDRESS(0x11582F8, 0x8AE378, 0xDBAB40); +} + void GAMELOOP_RequestLevelChangeByName(char* name, GameTracker* gameTracker, int doneType) { auto addr = GET_ADDRESS(0x451970, 0xC61CFA, 0x5DF8C0); diff --git a/src/game/Game.h b/src/game/Game.h index 48e1058..9a4283f 100644 --- a/src/game/Game.h +++ b/src/game/Game.h @@ -1,6 +1,7 @@ #pragma once #include "instance/Instance.h" +#include "level/Stream.h" struct menu_t; struct MemCardInfo; @@ -111,6 +112,7 @@ class Game public: static Instance* GetPlayerInstance(); static GameTracker* GetGameTracker(); + static STracker* GetStreamTracker(); }; void GAMELOOP_RequestLevelChangeByName(char* name, GameTracker* gameTracker, int doneType); \ No newline at end of file diff --git a/src/level/Event.cpp b/src/level/Event.cpp new file mode 100644 index 0000000..04a2a7d --- /dev/null +++ b/src/level/Event.cpp @@ -0,0 +1,9 @@ +#include "Event.h" +#include "util/Hooking.h" + +void* RELOC_GetProcAddress(void* peData, char* lpszName) +{ + auto addr = GET_ADDRESS(0x464550, 0x4680C0, 0x000000); + + return Hooking::CallReturn(addr, peData, lpszName); +} \ No newline at end of file diff --git a/src/level/Event.h b/src/level/Event.h new file mode 100644 index 0000000..f362953 --- /dev/null +++ b/src/level/Event.h @@ -0,0 +1,22 @@ +#pragma once + +struct EventVar +{ + char* name; + int variable; +}; + +struct UnsavedVar +{ + char* name; + int* variable; +}; + +struct GlobalData +{ + char pad1[232]; + + int* eventVars; +}; + +void* RELOC_GetProcAddress(void* peData, char* lpszName); \ No newline at end of file diff --git a/src/level/Level.h b/src/level/Level.h new file mode 100644 index 0000000..464ffb8 --- /dev/null +++ b/src/level/Level.h @@ -0,0 +1,111 @@ +#pragma once + +#include "cdc/math/Vector.h" + +struct Intro; +struct StreamUnitPortal; +struct Signal; +struct Instance; +struct KDNode; + +struct IndexedFace +{ + unsigned __int16 i0; + unsigned __int16 i1; + unsigned __int16 i2; + + unsigned __int8 adjacencyFlags; + unsigned __int8 collisionFlags; + unsigned __int8 clientFlags; + unsigned __int8 materialType; +}; + +struct MeshVertex +{ + __int16 x; + __int16 y; + __int16 z; +}; + +struct MeshVertex32 +{ + float x; + float y; + float z; + float w; +}; + +struct BBox +{ + cdc::Vector3 bMin; + cdc::Vector3 bMax; +}; + +struct Mesh +{ + BBox m_box; + cdc::Vector3 m_position; + + void* m_vertices; + IndexedFace* m_faces; + KDNode* m_root; + + void* m_clientData; + + unsigned __int16 m_vertexType; + unsigned __int16 m_numNodes; + unsigned __int16 m_numFaces; + unsigned __int16 m_numVertices; + unsigned __int16 m_height; + unsigned __int16 m_numDegenerateFaces; + unsigned __int16 m_numNonManifoldEdges; +}; + +struct Level; + +struct TerrainGroup +{ + cdc::Vector3 globalOffset; + cdc::Vector3 localOffset; + + int flags; + int ID; + int uniqueID; + int splineID; + Instance* instanceSpline; + Level* level; + Mesh* mesh; + + char pad1[116]; +}; + +struct Terrain +{ + __int16 UnitChangeFlags; + __int16 spad; + + int numIntros; + Intro* introList; + + int numStreamUnitPortals; + StreamUnitPortal* streamUnitPortals; + + int numTerrainGroups; + TerrainGroup* terrainGroups; + + TerrainGroup* signalTerrainGroup; + Signal* signals; +}; + +struct Level +{ + Terrain* terrain; + + char pad1[140]; + + Signal* SignalListStart; + __int16* SignalIDList; + void* splineCameraData; + + void* relocModule; // Pointer to script executable +}; \ No newline at end of file diff --git a/src/level/Stream.h b/src/level/Stream.h index 965974d..5bd4085 100644 --- a/src/level/Stream.h +++ b/src/level/Stream.h @@ -1,6 +1,7 @@ #pragma once #include "instance/Object.h" +#include "level/Level.h" #if TRAE || TR7 #define MAX_UNIT_NAME_LENGTH 20 @@ -8,8 +9,31 @@ #define MAX_UNIT_NAME_LENGTH 128 #endif +#define MAX_STREAM_UNITS 8 + struct ResolveObject; +struct StreamUnit +{ + int StreamUnitID; + + char used; + char unitHidden; + __int16 unitFlags; + + Level* level; + char baseAreaName[20]; + + ResolveObject* resolveObj; + + char pad1[56]; +}; + +struct STracker +{ + StreamUnit StreamList[MAX_STREAM_UNITS]; +}; + struct ObjectTracker { ResolveObject* resolveObj; diff --git a/src/modules/InstanceViewer.cpp b/src/modules/InstanceViewer.cpp index 5674d3b..bc1e455 100644 --- a/src/modules/InstanceViewer.cpp +++ b/src/modules/InstanceViewer.cpp @@ -21,7 +21,7 @@ void InstanceViewer::OnDraw() if (m_show) { ImGui::Begin("Instances", &m_show); - ImGui::Columns(2, "instances"); + ImGui::Columns(2); // Filter ImGui::InputText("Name", m_filter, sizeof(m_filter)); diff --git a/src/modules/Level.cpp b/src/modules/Level.cpp new file mode 100644 index 0000000..1fd1d7f --- /dev/null +++ b/src/modules/Level.cpp @@ -0,0 +1,147 @@ +#include +#include + +#include "Level.h" +#include "level/Stream.h" +#include "level/Event.h" +#include "game/Game.h" +#include "util/Hooking.h" + +static bool s_disableScript = false; +static void (*s_STREAM_FinishLoad)(StreamUnit*); + +static void STREAM_FinishLoad(StreamUnit* streamUnit) +{ + if (s_disableScript) + { + streamUnit->level->relocModule = nullptr; + } + + s_STREAM_FinishLoad(streamUnit); +} + +LevelModule::LevelModule() +{ + // Insert hook + auto addr = GET_ADDRESS(0x5D5640, 0x5DB680, 0x000000); + + MH_CreateHook((void*)addr, STREAM_FinishLoad, (void**)&s_STREAM_FinishLoad); + MH_EnableHook(MH_ALL_HOOKS); +} + +void LevelModule::OnMenu() +{ + if (ImGui::BeginMenu("Level")) + { + ImGui::MenuItem("Disable script", nullptr, &s_disableScript); + ImGui::MenuItem("Event debug", nullptr, &m_eventDebug); + + ImGui::EndMenu(); + } +} + +void LevelModule::OnDraw() +{ + if (m_eventDebug) + { + DrawEventDebug(); + } +} + +void LevelModule::DrawEventDebug() +{ + ImGui::Begin("Event debug", &m_eventDebug); + ImGui::Columns(2); + + auto stream = Game::GetStreamTracker(); + + // Level list + ImGui::BeginChild("LevelsTree"); + + for (int i = 0; i < MAX_STREAM_UNITS; i++) + { + auto unit = &stream->StreamList[i]; + + if (unit->used != 2) + { + continue; + } + + if (ImGui::TreeNodeEx((void*)unit, ImGuiTreeNodeFlags_Leaf, "%s", unit->baseAreaName)) + { + if (ImGui::IsItemClicked()) + { + m_selected = unit; + } + + ImGui::TreePop(); + } + } + + ImGui::EndChild(); + + // Event debug + ImGui::NextColumn(); + + if (m_selected && m_selected->used != 2) + { + m_selected = nullptr; + } + + if (m_selected) + { + ImGui::BeginChild("EventDebug"); + + DrawEventDebug(m_selected); + + ImGui::EndChild(); + } + + ImGui::End(); +} + +void LevelModule::DrawEventDebug(StreamUnit* unit) +{ + auto level = unit->level; + + if (!level->relocModule) + { + return; + } + + // Get the event debug export + auto eventVars = (EventVar*)RELOC_GetProcAddress(level->relocModule, "EventDebug"); + + if (eventVars) + { + auto globalData = (GlobalData*)GET_ADDRESS(0x1076980, 0x7C8A50, 0x000000); + auto i = 0; + + // Display all event variables + while (true) + { + auto var = &eventVars[i++]; + + if (var->name == nullptr) + break; + + ImGui::Text("%d %s = %d", var->variable, var->name, globalData->eventVars[var->variable]); + } + + // Display all unsaved variables + auto unsavedVars = (UnsavedVar*)eventVars; + while (true) + { + auto var = &unsavedVars[i++]; + + if (var->name == nullptr || var->variable == nullptr) + break; + + ImGui::Text("%s %d", var->name, *var->variable); + } + } + else + { + ImGui::Text("No event debug for this level"); + } +} \ No newline at end of file diff --git a/src/modules/Level.h b/src/modules/Level.h new file mode 100644 index 0000000..0b0f367 --- /dev/null +++ b/src/modules/Level.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Module.h" +#include "level/Stream.h" + +class LevelModule : public Module +{ +private: + bool m_eventDebug = false; + StreamUnit* m_selected = nullptr; + + void DrawEventDebug(); + void DrawEventDebug(StreamUnit* unit); + +public: + LevelModule(); + + void OnMenu(); + void OnDraw(); +}; \ No newline at end of file