From 84e7729ca045c05e4add7f05d09d032833e39a7b Mon Sep 17 00:00:00 2001
From: Amos <48657826+Mauler125@users.noreply.github.com>
Date: Tue, 4 Jan 2022 11:53:54 +0100
Subject: [PATCH] Add client and debug utilities + cleanup

---
 r5dev/client/cdll_engine_int.h        |  4 ++-
 r5dev/common/opcodes.cpp              |  3 +-
 r5dev/common/opcodes.h                | 13 --------
 r5dev/dedicated.vcxproj               |  2 --
 r5dev/dedicated.vcxproj.filters       |  6 ----
 r5dev/engine/baseclientstate.cpp      | 46 ++++++++++++++++++++++++++-
 r5dev/engine/baseclientstate.h        | 29 ++++++++++++++++-
 r5dev/engine/host_cmd.h               |  7 ++--
 r5dev/engine/host_state.cpp           |  6 +++-
 r5dev/engine/sys_dll2.h               |  2 +-
 r5dev/materialsystem/materialsystem.h | 29 +++++++++++++++++
 r5dev/mathlib/color.h                 | 15 +++++++++
 r5dev/public/include/utility.h        |  1 +
 r5dev/public/utility.cpp              | 16 ++++++++++
 r5dev/r5dev.vcxproj                   |  2 ++
 r5dev/r5dev.vcxproj.filters           |  9 ++++++
 16 files changed, 161 insertions(+), 29 deletions(-)
 create mode 100644 r5dev/materialsystem/materialsystem.h
 create mode 100644 r5dev/mathlib/color.h

diff --git a/r5dev/client/cdll_engine_int.h b/r5dev/client/cdll_engine_int.h
index d56bd275..f019d8b9 100644
--- a/r5dev/client/cdll_engine_int.h
+++ b/r5dev/client/cdll_engine_int.h
@@ -1,7 +1,6 @@
 #pragma once
 #include "tier0/basetypes.h"
 
-
 enum class ClientFrameStage_t : int
 {
 	FRAME_UNDEFINED = -1, // (haven't run any frames yet)
@@ -50,6 +49,8 @@ namespace
 	ADDRESS p_CHLClient_PostInit = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x48\x83\x3D\x00\x00\x00\x00\x00\x48\x8D\x05\x00\x00\x00\x00", "xxxxxxx?????xxx????");
 	void* (*CHLClient_PostInit)() = (void* (*)())p_CHLClient_PostInit.GetPtr(); /*48 83 EC 28 48 83 3D ? ? ? ? ? 48 8D 05 ? ? ? ?*/
 #endif
+
+	bool* scr_drawloading = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x80\x3D\x00\x00\x00\x00\x00\x74\x14\x66\x0F\x6E\x05\x00\x00\x00\x00", "xx?????xxxxxx????").ResolveRelativeAddress(0x2, 0x7).RCast<bool*>();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -66,6 +67,7 @@ class HDll_Engine_Int : public IDetour
 	{
 		std::cout << "| FUN: CHLClient::FrameStageNotify          : 0x" << std::hex << std::uppercase << p_CHLClient_FrameStageNotify.GetPtr() << std::setw(npad) << " |" << std::endl;
 		std::cout << "| FUN: CHLClient::PostInit                  : 0x" << std::hex << std::uppercase << p_CHLClient_PostInit.GetPtr()         << std::setw(npad) << " |" << std::endl;
+		std::cout << "| VAR: scr_drawloading                      : 0x" << std::hex << std::uppercase << scr_drawloading                       << std::setw(0)    << " |" << std::endl;
 		std::cout << "+----------------------------------------------------------------+" << std::endl;
 	}
 };
diff --git a/r5dev/common/opcodes.cpp b/r5dev/common/opcodes.cpp
index 5a1e0281..02c806e9 100644
--- a/r5dev/common/opcodes.cpp
+++ b/r5dev/common/opcodes.cpp
@@ -6,6 +6,7 @@
 #include "tier0/basetypes.h"
 #include "common/opcodes.h"
 #include "engine/host_cmd.h"
+#include "materialsystem/materialsystem.h"
 #include "bsplib/bsplib.h"
 #include "ebisusdk/EbisuSDK.h"
 
@@ -126,8 +127,8 @@ void Dedicated_Init()
 	//-------------------------------------------------------------------------
 	// RUNTIME: EBISUSDK
 	//-------------------------------------------------------------------------
-	p_EbisuSDK_Init_Tier0.Offset(0x0B).Patch({ 0xE9, 0x63, 0x02, 0x00, 0x00, 0x00 }); // JNZ --> JMP | Prevent EbisuSDK from initializing on the engine and server.
 	p_EbisuSDK_SetState.Offset(0x0E).Patch({ 0xE9, 0xCB, 0x03, 0x00, 0x00 });         // JNZ --> JMP | Prevent EbisuSDK from initializing on the engine and server.
+	p_EbisuSDK_Init_Tier0.Offset(0x0B).Patch({ 0xE9, 0x63, 0x02, 0x00, 0x00, 0x00 }); // JNZ --> JMP | Prevent EbisuSDK from initializing on the engine and server.
 
 	//-------------------------------------------------------------------------
 	// RUNTIME: FAIRFIGHT
diff --git a/r5dev/common/opcodes.h b/r5dev/common/opcodes.h
index dc4fc2ba..eaaa5ffb 100644
--- a/r5dev/common/opcodes.h
+++ b/r5dev/common/opcodes.h
@@ -57,15 +57,6 @@ namespace
 		ADDRESS CShaderSystem__Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x20\xC6\x41\x10\x00", "xxxx?xxxx?xxxxxxxxx");
 		// 0x1403DF870 // 48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 20 C6 41 10 00 //
 
-	//-------------------------------------------------------------------------
-	// CMATERIALSYSTEM
-	//-------------------------------------------------------------------------
-		ADDRESS CMaterialSystem__Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x55\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x83\xEC\x70\x48\x83\x3D\x00\x00\x00\x00\x00", "xxxx?xxxxxxxxxxxxxxxxxx?????");
-		// 0x1403BBFD0 // 48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC 70 48 83 3D ? ? ? ? ? //
-
-		ADDRESS InitMaterialSystem = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8B\x01\xFF\x90\x00\x00\x00\x00\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8B\x01\xFF\x90\x00\x00\x00\x00", "xxxxxxx????xxx????xxxxx????xxx????xxx????xxxxx????"); //
-		// 0x14024B390 // 48 83 EC 28 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? 48 8B 01 FF 90 ? ? ? ? 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? 48 8B 01 FF 90 ? ? ? ? //
-
 	//-------------------------------------------------------------------------
 	// RUNTIME: BSP_LUMP
 	//-------------------------------------------------------------------------
@@ -75,7 +66,6 @@ namespace
 		ADDRESS CollisionBSPData_LinkPhysics = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x57\x48\x81\xEC\x00\x00\x00\x00\x48\x8B\xF9\x33\xED", "xxxx?xxxx?xxxx????xxxxx"); // case 1: only gets called on changelevel, needs more research, function gets called by CModelLoader virtual function.
 		// 0x140256480 // 48 89 5C 24 ? 48 89 6C 24 ? 57 48 81 EC ? ? ? ? 48 8B F9 33 ED //
 
-
 	//-------------------------------------------------------------------------
 	// CSTUDIORENDERCONTEXT
 	//-------------------------------------------------------------------------
@@ -153,9 +143,6 @@ class HOpcodes : public IDetour
 		std::cout << "+----------------------------------------------------------------+" << std::endl;
 		std::cout << "| FUN: CShaderSystem::Init                  : 0x" << std::hex << std::uppercase << CShaderSystem__Init.GetPtr()                 << std::setw(npad) << " |" << std::endl;
 		std::cout << "+----------------------------------------------------------------+" << std::endl;
-		std::cout << "| FUN: CMaterialSystem::Init                : 0x" << std::hex << std::uppercase << CMaterialSystem__Init.GetPtr()               << std::setw(npad) << " |" << std::endl;
-		std::cout << "| FUN: InitMaterialSystem                   : 0x" << std::hex << std::uppercase << InitMaterialSystem.GetPtr()                  << std::setw(npad) << " |" << std::endl;
-		std::cout << "+----------------------------------------------------------------+" << std::endl;
 		std::cout << "| FUN: CollisionBSPData_LoadAllLumps        : 0x" << std::hex << std::uppercase << CollisionBSPData_LoadAllLumps.GetPtr()       << std::setw(npad) << " |" << std::endl;
 		std::cout << "| FUN: CollisionBSPData_LinkPhysics         : 0x" << std::hex << std::uppercase << CollisionBSPData_LinkPhysics.GetPtr()        << std::setw(npad) << " |" << std::endl;
 		std::cout << "+----------------------------------------------------------------+" << std::endl;
diff --git a/r5dev/dedicated.vcxproj b/r5dev/dedicated.vcxproj
index c8745802..91f0fb26 100644
--- a/r5dev/dedicated.vcxproj
+++ b/r5dev/dedicated.vcxproj
@@ -181,7 +181,6 @@
     <ClInclude Include="core\stdafx.h" />
     <ClInclude Include="ebisusdk\EbisuSDK.h" />
     <ClInclude Include="engine\baseclient.h" />
-    <ClInclude Include="engine\baseclientstate.h" />
     <ClInclude Include="engine\host_cmd.h" />
     <ClInclude Include="engine\host_state.h" />
     <ClInclude Include="engine\net_chan.h" />
@@ -339,7 +338,6 @@
     </ClCompile>
     <ClCompile Include="ebisusdk\EbisuSDK.cpp" />
     <ClCompile Include="engine\baseclient.cpp" />
-    <ClCompile Include="engine\baseclientstate.cpp" />
     <ClCompile Include="engine\host_cmd.cpp" />
     <ClCompile Include="engine\host_state.cpp" />
     <ClCompile Include="engine\net_chan.cpp" />
diff --git a/r5dev/dedicated.vcxproj.filters b/r5dev/dedicated.vcxproj.filters
index 6c025bbc..b9a70f9a 100644
--- a/r5dev/dedicated.vcxproj.filters
+++ b/r5dev/dedicated.vcxproj.filters
@@ -126,9 +126,6 @@
     <ClInclude Include="ebisusdk\EbisuSDK.h">
       <Filter>sdk\ebisusdk</Filter>
     </ClInclude>
-    <ClInclude Include="engine\baseclientstate.h">
-      <Filter>sdk\engine</Filter>
-    </ClInclude>
     <ClInclude Include="engine\host_state.h">
       <Filter>sdk\engine</Filter>
     </ClInclude>
@@ -608,9 +605,6 @@
     <ClCompile Include="engine\baseclient.cpp">
       <Filter>sdk\engine</Filter>
     </ClCompile>
-    <ClCompile Include="engine\baseclientstate.cpp">
-      <Filter>sdk\engine</Filter>
-    </ClCompile>
     <ClCompile Include="launcher\IApplication.cpp">
       <Filter>sdk\launcher</Filter>
     </ClCompile>
diff --git a/r5dev/engine/baseclientstate.cpp b/r5dev/engine/baseclientstate.cpp
index 9d9576b4..5b9c443c 100644
--- a/r5dev/engine/baseclientstate.cpp
+++ b/r5dev/engine/baseclientstate.cpp
@@ -5,5 +5,49 @@
 //===========================================================================//
 
 #include "core/stdafx.h"
+#include "client/cdll_engine_int.h"
+#include "engine/debugoverlay.h"
 #include "engine/baseclientstate.h"
-//TODO
+
+
+//------------------------------------------------------------------------------
+// Purpose: returns true if client simulation is paused
+//------------------------------------------------------------------------------
+bool CBaseClientState::IsPaused()
+{
+	return *m_bPaused;
+}
+
+// Technically doesn't belong here.
+//------------------------------------------------------------------------------
+// Purpose: gets the client time
+//------------------------------------------------------------------------------
+float CBaseClientState::GetClientTime()
+{
+    if (*scr_drawloading)
+    {
+        return (float)(int)*host_tickcount * (float)*client_debugdraw_int_unk;
+    }
+    else
+    {
+        return *(float*)client_debugdraw_float_unk;
+    }
+}
+
+//------------------------------------------------------------------------------
+// Purpose: gets the client simulation tick count
+//------------------------------------------------------------------------------
+int CBaseClientState::GetClientTickCount() const
+{
+    return *host_tickcount;
+}
+
+//------------------------------------------------------------------------------
+// Purpose: sets the client simulation tick count
+//------------------------------------------------------------------------------
+void CBaseClientState::SetClientTickCount(int tick)
+{
+    *host_tickcount = tick;
+}
+
+CBaseClientState* g_pBaseClientState = new CBaseClientState();
diff --git a/r5dev/engine/baseclientstate.h b/r5dev/engine/baseclientstate.h
index 3f44032f..79dffc1a 100644
--- a/r5dev/engine/baseclientstate.h
+++ b/r5dev/engine/baseclientstate.h
@@ -1,5 +1,6 @@
 #pragma once
 #include "tier0/basetypes.h"
+#include "engine/debugoverlay.h"
 
 namespace
 {
@@ -16,6 +17,30 @@ namespace
 #endif
 }
 
+namespace
+{
+#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1)
+	bool* cl_m_bPaused = p_DrawAllOverlays.Offset(0x90).FindPatternSelf("80 3D ? ? ? 0B ?", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x2).RCast<bool*>();
+#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3)
+	bool* cl_m_bPaused = p_DrawAllOverlays.Offset(0x70).FindPatternSelf("80 3D ? ? ? 01 ?", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x7).RCast<bool*>();
+#endif
+	int* cl_host_tickcount = p_DrawAllOverlays.Offset(0xC0).FindPatternSelf("66 0F 6E", ADDRESS::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x4, 0x8).RCast<int*>();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+class CBaseClientState
+{
+public:
+	bool* m_bPaused = cl_m_bPaused; // pauzes the client side simulation in apex.
+	int* host_tickcount = cl_host_tickcount; // client simulation tick count.
+
+	bool IsPaused();
+	float GetClientTime();
+	int GetClientTickCount() const;	// Get the client tick count.
+	void SetClientTickCount(int tick); // Set the client tick count.
+};
+
+extern CBaseClientState* g_pBaseClientState;
 
 ///////////////////////////////////////////////////////////////////////////////
 class HClientState : public IDetour
@@ -23,7 +48,9 @@ class HClientState : public IDetour
 	virtual void debugp()
 	{
 		//std::cout << "| FUN: CClientState::CheckForResend         : 0x" << std::hex << std::uppercase << p_CClientState__CheckForResend.GetPtr() << std::setw(npad) << " |" << std::endl;
-		//std::cout << "+----------------------------------------------------------------+" << std::endl;
+		std::cout << "| VAR: cl_m_bPaused                         : 0x" << std::hex << std::uppercase << cl_m_bPaused      << std::setw(0) << " |" << std::endl;
+		std::cout << "| FUN: cl_host_tickcount                    : 0x" << std::hex << std::uppercase << cl_host_tickcount << std::setw(npad) << " |" << std::endl;
+		std::cout << "+----------------------------------------------------------------+" << std::endl;
 	}
 };
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/r5dev/engine/host_cmd.h b/r5dev/engine/host_cmd.h
index 828c0f59..79769b84 100644
--- a/r5dev/engine/host_cmd.h
+++ b/r5dev/engine/host_cmd.h
@@ -10,6 +10,8 @@ namespace
 	ADDRESS p_Host_Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x48\x89\x7C\x24\x00\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\xAC\x24\x00\x00\x00\x00\xB8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x2B\xE0\x48\x8B\xD9", "xxxx?xxxx?xxxx?xxxxxxxxxxxxx????x????x????xxxxxx");
 	void* (*Host_Init)(bool* bDedicated) = (void* (*)(bool*))p_Host_Init.GetPtr(); /*48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 55 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? B8 ? ? ? ? E8 ? ? ? ? 48 2B E0 48 8B D9*/
 #endif
+	ADDRESS p_malloc_internal = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\xE9\x00\x00\x00\x00\xCC\xCC\xCC\x40\x53\x48\x83\xEC\x20\x48\x8D\x05\x00\x00\x00\x00", "x????xxxxxxxxxxxx????");
+	void* (*malloc_internal)(void* pPool, int64_t size) = (void* (*)(void*, int64_t))p_malloc_internal.GetPtr(); /*E9 ? ? ? ? CC CC CC 40 53 48 83 EC 20 48 8D 05 ? ? ? ?*/
 }
 
 namespace
@@ -26,8 +28,9 @@ class HHostCmd : public IDetour
 {
 	virtual void debugp()
 	{
-		std::cout << "| FUN: Host_Init                            : 0x" << std::hex << std::uppercase << p_Host_Init.GetPtr()   << std::setw(npad) << " |" << std::endl;
-		std::cout << "| VAR: g_pMallocPool                        : 0x" << std::hex << std::uppercase << g_pMallocPool.GetPtr() << std::setw(npad) << " |" << std::endl;
+		std::cout << "| FUN: Host_Init                            : 0x" << std::hex << std::uppercase << p_Host_Init.GetPtr()       << std::setw(npad) << " |" << std::endl;
+		std::cout << "| FUN: malloc_internal                      : 0x" << std::hex << std::uppercase << p_malloc_internal.GetPtr() << std::setw(npad) << " |" << std::endl;
+		std::cout << "| VAR: g_pMallocPool                        : 0x" << std::hex << std::uppercase << g_pMallocPool.GetPtr()     << std::setw(npad) << " |" << std::endl;
 		std::cout << "+----------------------------------------------------------------+" << std::endl;
 	}
 };
diff --git a/r5dev/engine/host_state.cpp b/r5dev/engine/host_state.cpp
index 8122b1d1..48996e75 100644
--- a/r5dev/engine/host_state.cpp
+++ b/r5dev/engine/host_state.cpp
@@ -26,7 +26,11 @@ void KeepAliveToPylon()
 				g_pCvar->FindVar("hostport")->m_pzsCurrentValue,
 				g_pCvar->FindVar("mp_gamemode")->m_pzsCurrentValue,
 				false,
-				std::to_string(*g_nRemoteFunctionCallsChecksum), // BUG BUG: Checksum is null on dedi
+
+				// BUG BUG: Checksum is null on dedi
+				// ADDITIONAL NOTES: seems to be related to scripts, this also happens when the listen server is started but the client from the same process never connects.
+				// Checksum only gets set on the server if the client from its own process connects to it.
+				std::to_string(*g_nRemoteFunctionCallsChecksum),
 				std::string(),
 				g_szNetKey.c_str()
 			}
diff --git a/r5dev/engine/sys_dll2.h b/r5dev/engine/sys_dll2.h
index eedac0c1..edca632d 100644
--- a/r5dev/engine/sys_dll2.h
+++ b/r5dev/engine/sys_dll2.h
@@ -29,7 +29,7 @@ class HSys_Dll2 : public IDetour
 {
 	virtual void debugp()
 	{
-		std::cout << "| FUN: CEngineAPI_Connect                   : 0x" << std::hex << std::uppercase << p_CEngineAPI_Connect.GetPtr() << std::setw(npad) << " |" << std::endl;
+		std::cout << "| FUN: CEngineAPI::Connect                  : 0x" << std::hex << std::uppercase << p_CEngineAPI_Connect.GetPtr() << std::setw(npad) << " |" << std::endl;
 		std::cout << "| FUN: PakFile_Init                         : 0x" << std::hex << std::uppercase << p_PakFile_Init.GetPtr()       << std::setw(npad) << " |" << std::endl;
 		std::cout << "| VAR: g_pMapVPKCache                       : 0x" << std::hex << std::uppercase << g_pMapVPKCache.GetPtr()       << std::setw(npad) << " |" << std::endl;
 		std::cout << "+----------------------------------------------------------------+" << std::endl;
diff --git a/r5dev/materialsystem/materialsystem.h b/r5dev/materialsystem/materialsystem.h
new file mode 100644
index 00000000..558d8af6
--- /dev/null
+++ b/r5dev/materialsystem/materialsystem.h
@@ -0,0 +1,29 @@
+#pragma once
+
+namespace
+{
+	/* ==== MATERIALSYSTEM ================================================================================================================================================== */
+	ADDRESS CMaterialSystem__Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x55\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x83\xEC\x70\x48\x83\x3D\x00\x00\x00\x00\x00", "xxxx?xxxxxxxxxxxxxxxxxx?????");
+	// 0x1403BBFD0 // 48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC 70 48 83 3D ? ? ? ? ? //
+
+	ADDRESS InitMaterialSystem = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8B\x01\xFF\x90\x00\x00\x00\x00\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\x48\x8B\x01\xFF\x90\x00\x00\x00\x00", "xxxxxxx????xxx????xxxxx????xxx????xxx????xxxxx????"); //
+	// 0x14024B390 // 48 83 EC 28 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? 48 8B 01 FF 90 ? ? ? ? 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? 48 8B 01 FF 90 ? ? ? ? //
+
+	void* g_pMaterialSystem = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x8B\x0D\x00\x00\x00\x00\x48\x85\xC9\x74\x11\x48\x8B\x01\x48\x8D\x15\x00\x00\x00\x00", "xxx????xxxxxxxxxxx????").ResolveRelativeAddressSelf(0x3, 0x7).RCast<void*>();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+class HMaterialSystem : public IDetour
+{
+	virtual void debugp()
+	{
+		std::cout << "| FUN: CMaterialSystem::Init                : 0x" << std::hex << std::uppercase << CMaterialSystem__Init.GetPtr() << std::setw(npad) << " |" << std::endl;
+		std::cout << "| FUN: InitMaterialSystem                   : 0x" << std::hex << std::uppercase << InitMaterialSystem.GetPtr()    << std::setw(npad) << " |" << std::endl;
+		std::cout << "| VAR: g_pMaterialSystem                    : 0x" << std::hex << std::uppercase << g_pMaterialSystem              << std::setw(0)    << " |" << std::endl;
+		std::cout << "+----------------------------------------------------------------+" << std::endl;
+	}
+};
+///////////////////////////////////////////////////////////////////////////////
+
+void DebugOverlays_Attach();
+REGISTER(HMaterialSystem);
diff --git a/r5dev/mathlib/color.h b/r5dev/mathlib/color.h
new file mode 100644
index 00000000..1abead26
--- /dev/null
+++ b/r5dev/mathlib/color.h
@@ -0,0 +1,15 @@
+#pragma once
+
+class Color
+{
+public:
+	Color(int r, int g, int b, int a)
+	{
+		_color[0] = (unsigned char)r;
+		_color[1] = (unsigned char)g;
+		_color[2] = (unsigned char)b;
+		_color[3] = (unsigned char)a;
+	}
+private:
+	unsigned char _color[4];
+};
diff --git a/r5dev/public/include/utility.h b/r5dev/public/include/utility.h
index f2863811..692f5a73 100644
--- a/r5dev/public/include/utility.h
+++ b/r5dev/public/include/utility.h
@@ -3,6 +3,7 @@
 
 /////////////////////////////////////////////////////////////////////////////
 // Internals
+BOOL IsBadReadPtrV2(void* ptr);
 BOOL FileExists(const char* szPath);
 MODULEINFO GetModuleInfo(const char* szModule);
 DWORD64 FindPatternSIMD(const char* szModule, const unsigned char* szPattern, const char* szMask);
diff --git a/r5dev/public/utility.cpp b/r5dev/public/utility.cpp
index c603bc6d..c6886076 100644
--- a/r5dev/public/utility.cpp
+++ b/r5dev/public/utility.cpp
@@ -13,6 +13,22 @@ BOOL FileExists(const char* szPath)
     return std::filesystem::exists(szPath);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// For checking if pointer is valid or bad.
+BOOL IsBadReadPtrV2(void* ptr)
+{
+    MEMORY_BASIC_INFORMATION mbi = { 0 };
+    if (::VirtualQuery(ptr, &mbi, sizeof(mbi)))
+    {
+        DWORD mask = (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY);
+        bool b = !(mbi.Protect & mask);
+        // check the page is not a guard page
+        if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true;
+        return b;
+    }
+    return true;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // For getting information about the executing module.
 MODULEINFO GetModuleInfo(const char* szModule)
diff --git a/r5dev/r5dev.vcxproj b/r5dev/r5dev.vcxproj
index a584ca24..f02675d0 100644
--- a/r5dev/r5dev.vcxproj
+++ b/r5dev/r5dev.vcxproj
@@ -137,7 +137,9 @@
     <ClInclude Include="inputsystem\ButtonCode.h" />
     <ClInclude Include="inputsystem\inputsystem.h" />
     <ClInclude Include="launcher\IApplication.h" />
+    <ClInclude Include="materialsystem\materialsystem.h" />
     <ClInclude Include="mathlib\adler32.h" />
+    <ClInclude Include="mathlib\color.h" />
     <ClInclude Include="mathlib\crc32.h" />
     <ClInclude Include="mathlib\IceKey.H" />
     <ClInclude Include="mathlib\parallel_for.h" />
diff --git a/r5dev/r5dev.vcxproj.filters b/r5dev/r5dev.vcxproj.filters
index 20aa9f02..921368fd 100644
--- a/r5dev/r5dev.vcxproj.filters
+++ b/r5dev/r5dev.vcxproj.filters
@@ -121,6 +121,9 @@
     <Filter Include="sdk\bsplib">
       <UniqueIdentifier>{336e3141-0276-4cd5-a836-585eef681b7b}</UniqueIdentifier>
     </Filter>
+    <Filter Include="sdk\materialsystem">
+      <UniqueIdentifier>{55bb4f60-5f5a-4780-a7a2-b3db51c53680}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="client\client.cpp">
@@ -845,6 +848,12 @@
     <ClInclude Include="windows\system.h">
       <Filter>windows</Filter>
     </ClInclude>
+    <ClInclude Include="mathlib\color.h">
+      <Filter>sdk\mathlib</Filter>
+    </ClInclude>
+    <ClInclude Include="materialsystem\materialsystem.h">
+      <Filter>sdk\materialsystem</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="r5dev.def" />