11#include < implot.h>
22#include " base.hh"
3+ #include " common/minhook.hh"
34#include " imgui.h"
45
6+ #include " common/logger.hh"
7+
58#include < deque>
69
710#include < Utils.hh>
811#include < CPools.hh>
912#include < type_traits>
1013
14+ static std::map<uint32_t , std::string> s_PoolsNameMap = {
15+ {0x0AB968F6 , " streamped req data" },
16+ {0x6E63BFF3 , " cpatrolnode" },
17+ {0x85FB462D , " pedprop req data" },
18+ {0x54753C86 , " cvehiclestreamrequestgfx" },
19+ {0xB4E04AA4 , " cdoorextension" },
20+ {0x1182232C , " cgamescripthandler" },
21+ {0xC2B5F089 , " cvehiclestreamrendergfx" },
22+ {0x2D370C34 , " streamped render data" },
23+ {0xD29EB05B , " fwcontainerlod" },
24+ {0x539C8EB8 , " pedprop render data" },
25+ {0x5E047C3E , " vehicleglasscomponententity" },
26+ {0x652A20AF , " targetting" },
27+ {0x4E2ADF9B , " itemsetbuffer" },
28+ {0x2FEAD7A6 , " fraginstnmgta" },
29+ {0x5047B2C4 , " cmoveped" },
30+ {0x8DA12117 , " peds" },
31+ {0x394AC584 , " pedintelligence" },
32+ {0xAC9F5436 , " cmovevehicle" },
33+ {0xBF69BB29 , " fwanimdirectorcomponentragdoll" },
34+ {0x210E10BE , " fwanimdirectorcomponentfacialrig" },
35+ {0x16A315A2 , " fwanimdirectorcomponentsyncedscene" },
36+ {0xBAE33CCF , " cweaponcomponentinfo" },
37+ {0x94E57350 , " fwdynamicentitycomponent" },
38+ {0x3CC59946 , " fwanimdirectorcomponentexpressions" },
39+ {0x7311A8D7 , " fwscriptguid" },
40+ {0xE7509171 , " quadtreenodes" },
41+ {0x3A2BC128 , " cweapon" },
42+ {0xCA5ED810 , " fwanimdirector" },
43+ {0xC79C63D2 , " fwanimdirectorcomponentmove" },
44+ {0x36776CCA , " fwanimdirectorcomponentcreature" },
45+ {0x698208CF , " tasksequenceinfo" },
46+ {0x975AC445 , " wheels" },
47+ {0x6851786C , " fraginstgta" },
48+ {0xEB9564E1 , " phinstgta" },
49+ {0x41663795 , " maxloadrequestedinfo" },
50+ {0x2EB2EE6E , " navmeshes" },
51+ };
52+
1153class PoolsDebugInterface : public DebugInterface
1254{
13- inline static CPool<void > sm_FakeCollidersPool;
14-
15- std::vector<int >
16- GetXValues ()
55+ constexpr static int GRAPH_WIDTH = 500 ;
56+
57+ class PoolData
1758 {
18- std::vector<int > vec;
19- for (int i = 0 ; i < 500 ; i++)
20- vec.push_back (i);
59+ public:
60+ std::string Name;
2161
22- return vec;
23- }
62+ std::function<std::pair<int , int > ()> GetFunction;
63+ std::vector<float > GraphValues;
64+ bool IsCritical = false ;
2465
25- template <typename T>
26- auto
27- Dereference (const T &v)
28- {
29- if constexpr (std::is_pointer_v<T>)
30- return Dereference (*v);
31- else
32- return v;
33- }
66+ bool AlwaysDisplay = false ;
67+ bool DisplayCritical = true ;
68+ bool DisplaySeparate = false ;
69+
70+ PoolData (const PoolData &other) = delete ;
71+ PoolData (PoolData &&other) = default ;
72+
73+ PoolData (std::string name, std::function<std::pair<int , int > ()> func,
74+ bool always = false , bool critical = true ,
75+ bool separate = false )
76+ : Name (name), GetFunction (func), AlwaysDisplay (always),
77+ DisplayCritical (critical), DisplaySeparate (separate)
78+ {
79+ }
80+
81+ template <typename T>
82+ PoolData (std::string name, CPool<T> *pool, bool always = false ,
83+ bool critical = true , bool separate = false )
84+ : GetFunction ([pool] () -> std::pair<int, int> {
85+ if (!pool)
86+ return {0 , 0 };
87+ return {pool->GetCount (), pool->m_nMaxElements };
88+ }),
89+ Name (name), AlwaysDisplay (always), DisplayCritical (critical),
90+ DisplaySeparate (separate)
91+ {
92+ }
93+
94+ template <typename T>
95+ PoolData (std::string name, CPool<T> **pool, bool always = false ,
96+ bool critical = true , bool separate = false )
97+ : GetFunction ([pool] () -> std::pair<int, int> {
98+ if (!pool || !(*pool))
99+ return {0 , 0 };
100+ return {(*pool)->GetCount (), (*pool)->m_nMaxElements };
101+ }),
102+ Name (name), AlwaysDisplay (always), DisplayCritical (critical),
103+ DisplaySeparate (separate)
104+ {
105+ }
106+
107+ void
108+ Update ()
109+ {
110+ auto [used, max] = GetFunction ();
111+
112+ if (max == 0 )
113+ return ;
114+
115+ GraphValues.push_back (used / static_cast <float > (max));
34116
35- template <typename T>
36- bool
37- CanDereference (T &&v)
117+ if (GraphValues.size () >= GRAPH_WIDTH)
118+ GraphValues.erase (GraphValues.begin ());
119+
120+ IsCritical = used > 10 && (GraphValues.back () > 0 .5f );
121+ }
122+
123+ bool
124+ ShouldDisplay ()
125+ {
126+ return AlwaysDisplay || (DisplayCritical && IsCritical);
127+ }
128+ };
129+
130+ inline static std::vector<PoolData> sm_Pools;
131+ inline static uint32_t sm_LastPool;
132+
133+ void
134+ UpdatePools ()
38135 {
39- if constexpr (std::is_pointer_v<T>)
40- return v && CanDereference (*v);
41- else
42- return true ;
136+ for (auto &i : sm_Pools)
137+ i.Update ();
43138 }
44139
45- template <auto &Pool>
46140 void
47- DrawPool ( const char *name )
141+ DrawMasterGraph ( )
48142 {
49- if (!CanDereference (Pool))
143+ if (!ImGui::CollapsingHeader (" Master Graph" ))
144+ return ;
145+
146+ ImPlot::SetNextPlotLimits (0 , 520 , 0 , 1 .2f , ImGuiCond_Always);
147+ if (!ImPlot::BeginPlot (" Master Graph" ))
50148 return ;
51-
52- int PoolUsage = Dereference (Pool).GetCount ();
53- int PoolSize = Dereference (Pool).m_nMaxElements ;
54149
55- static std::vector<int > x_Values = GetXValues ();
56- static std::vector<int > y_Values;
150+ static float One = 1 .0f ;
151+
152+ ImPlot::SetNextLineStyle (ImVec4 (1.0 , 0.0 , 0.0 , 1.0 ), 5 .0f );
153+ ImPlot::PlotHLines (" Max" , &One, 1 );
57154
58- y_Values. push_back ( Dereference (Pool). GetCount () );
155+ ImPlot::SetNextLineStyle (IMPLOT_AUTO_COL );
59156
60- if (y_Values.size () > 500 )
157+ static std::vector<float > x_Values = GetXValues ();
158+ for (auto &i : sm_Pools)
61159 {
62- y_Values.erase (y_Values.begin ());
160+ if (i.ShouldDisplay ())
161+ {
162+ ImPlot::SetNextLineStyle (IMPLOT_AUTO_COL, 2 .0f );
163+ ImPlot::PlotLine (i.Name .c_str (), x_Values.data (),
164+ i.GraphValues .data (),
165+ i.GraphValues .size ());
166+ }
63167 }
64168
65- if (!ImGui::CollapsingHeader (name))
169+ ImPlot::EndPlot ();
170+ }
171+
172+ void
173+ DrawPoolGraph (PoolData &data)
174+ {
175+ if (!ImGui::CollapsingHeader (data.Name .c_str ()))
66176 return ;
67177
68- ImPlot::SetNextPlotLimits (0 , 520 , 0 , PoolSize + 10 , ImGuiCond_Always);
69- if (ImPlot::BeginPlot (name))
70- {
71- ImPlot::SetNextLineStyle (ImVec4 (1.0 , 0.0 , 0.0 , 1.0 ));
72- ImPlot::PlotHLines (" Max" , &PoolSize, 1 );
178+ ImPlot::SetNextPlotLimits (0 , 520 , 0 , 1 .0f , ImGuiCond_Always);
73179
74- ImPlot::SetNextLineStyle (IMPLOT_AUTO_COL, 5.0 );
75- ImPlot::PlotLine (" Usage" , x_Values.data (), y_Values.data (),
76- y_Values.size ());
180+ if (!ImPlot::BeginPlot (data.Name .c_str ()))
181+ return ;
77182
78- ImPlot::SetNextLineStyle ();
79- ImPlot::EndPlot ();
80- }
183+ static float One = 1 .0f ;
184+ static std::vector<float > x_Values = GetXValues ();
81185
82- ImGui::ProgressBar (PoolUsage / static_cast <float > (PoolSize));
186+ ImPlot::SetNextLineStyle (ImVec4 (1.0 , 0.0 , 0.0 , 1.0 ));
187+ ImPlot::PlotHLines (" Max" , &One, 1 );
188+
189+ ImPlot::SetNextLineStyle (IMPLOT_AUTO_COL, 5 .0f );
190+
191+ ImPlot::PlotLine (" Usage" , x_Values.data (), data.GraphValues .data (),
192+ data.GraphValues .size ());
193+
194+ ImPlot::SetNextLineStyle ();
195+
196+ ImPlot::EndPlot ();
83197 }
84198
85199 void
86- ProcessPhInstPool ()
200+ DrawPools ()
201+ {
202+ UpdatePools ();
203+ DrawMasterGraph ();
204+ for (auto &i : sm_Pools)
205+ {
206+ if (i.DisplaySeparate )
207+ DrawPoolGraph (i);
208+ }
209+ }
210+
211+ std::vector<float >
212+ GetXValues ()
213+ {
214+ std::vector<float > vec;
215+ for (int i = 0 ; i < 500 ; i++)
216+ vec.push_back (i);
217+
218+ return vec;
219+ }
220+
221+ static std::pair<int , int >
222+ GetCollidersUsage ()
87223 {
88224 static char **phInstance = GetRelativeReference<char *> (
89225 " ? 8B 0D ? ? ? ? ? 83 64 ? ? 00 ? 0F B7 D1 ? 33 C9 E8" , 3 , 7 );
@@ -97,22 +233,46 @@ class PoolsDebugInterface : public DebugInterface
97233 }();
98234
99235 if (!*phInstance)
100- return ;
236+ return { 0 , 0 } ;
101237
102- sm_FakeCollidersPool.m_nCount = injector::ReadMemory<uint32_t > (
103- *phInstance + usedCollidersOffset);
104- sm_FakeCollidersPool.m_nMaxElements
105- = injector::ReadMemory<uint32_t > (*phInstance + maxCollidersOffset);
238+ return {
239+ injector::ReadMemory<uint32_t > (*phInstance + usedCollidersOffset),
240+ injector::ReadMemory<uint32_t > (*phInstance + maxCollidersOffset)};
106241 }
107242
108243 void
109244 Draw () override
110245 {
111- ProcessPhInstPool ();
246+ DrawPools ();
247+ }
112248
113- DrawPool<sm_FakeCollidersPool> (" Colliders" );
114- DrawPool<CPools::g_pVehicleStreamRequestGfxPool> (" Vehicle Stream Request GFX" );
115- DrawPool<CPools::g_pVehicleStructPool> (" Vehicle Struct" );
249+ template <auto &fwConfigManager__GetSizeOfPool>
250+ static uint32_t
251+ GetNextPoolName (void *p1, uint32_t hash, uint32_t p3)
252+ {
253+ sm_LastPool = hash;
254+ return fwConfigManager__GetSizeOfPool (p1, hash, p3);
255+ }
256+
257+ template <auto &CPool__Allocate>
258+ static void
259+ RegisterPool (CPool<void > *pool)
260+ {
261+ if (sm_Pools.size () == 0 )
262+ {
263+ sm_Pools.emplace_back (" colliders" , GetCollidersUsage, true ,
264+ true , true );
265+
266+ sm_Pools.emplace_back (" vehicle struct" ,
267+ CPools::g_pVehicleStructPool, true , true ,
268+ true );
269+ }
270+
271+ if (pool->m_nMaxElements > 10 && s_PoolsNameMap.count (sm_LastPool))
272+ sm_Pools.emplace_back (s_PoolsNameMap[sm_LastPool], pool, true ,
273+ true , true );
274+
275+ return CPool__Allocate (pool);
116276 }
117277
118278public:
@@ -123,4 +283,15 @@ class PoolsDebugInterface : public DebugInterface
123283 return " Pools" ;
124284 }
125285
286+ PoolsDebugInterface ()
287+ {
288+ REGISTER_MH_HOOK_BRANCH (" ba 67 ee cc f8 ? b8 10 00 00 00 e8 ? ? ? ?" ,
289+ 11 , GetNextPoolName, uint32_t , void *,
290+ uint32_t , uint32_t );
291+
292+ REGISTER_MH_HOOK (" ? 53 ? 83 ec 20 ? 83 39 00 ? 8b d9 75 ? 8b 41 14 0f "
293+ " af 41 10 ? 63 c8 " ,
294+ 0 , RegisterPool, void , CPool<void > *);
295+ }
296+
126297} inline g_PoolsDebugInterface;
0 commit comments