diff --git a/.gitignore b/.gitignore
index 9491a2f..94baacb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -360,4 +360,7 @@ MigrationBackup/
.ionide/
# Fody - auto-generated XML schema
-FodyWeavers.xsd
\ No newline at end of file
+FodyWeavers.xsd
+tf2source
+.vscode
+source-sdk-2013
\ No newline at end of file
diff --git a/TextmodeTF2/TextmodeTF2.vcxproj b/TextmodeTF2/TextmodeTF2.vcxproj
index 9a3a74d..838e482 100644
--- a/TextmodeTF2/TextmodeTF2.vcxproj
+++ b/TextmodeTF2/TextmodeTF2.vcxproj
@@ -228,10 +228,15 @@
+
+
+
+
+
@@ -241,13 +246,21 @@
+
+
+
+
+
+
+
+
@@ -261,6 +274,8 @@
+
+
@@ -275,6 +290,8 @@
+
+
diff --git a/TextmodeTF2/src/BytePatches/BytePatches.cpp b/TextmodeTF2/src/BytePatches/BytePatches.cpp
index cac6686..f718055 100644
--- a/TextmodeTF2/src/BytePatches/BytePatches.cpp
+++ b/TextmodeTF2/src/BytePatches/BytePatches.cpp
@@ -1,6 +1,7 @@
#include "BytePatches.h"
#include "../Core/Core.h"
+#include
BytePatch::BytePatch(const char* sModule, const char* sSignature, int iOffset, const char* sPatch)
{
@@ -27,15 +28,40 @@ bool BytePatch::Initialize()
if (m_bIsPatched)
return true;
- m_pAddress = LPVOID(U::Memory.FindSignature(m_sModule, m_sSignature));
- if (!m_pAddress)
+ const auto vMatches = U::Memory.FindSignatures(m_sModule, m_sSignature, 2);
+ if (vMatches.empty())
{
SDK::Output("BytePatches", std::format("Failed to find signature for bytepatch: {} in {}", m_sSignature, m_sModule).c_str());
U::Core.AppendFailText(std::format("BytePatch::Initialize() failed to initialize:\n {}\n {}", m_sModule, m_sSignature).c_str());
return false;
}
+ if (vMatches.size() != 1)
+ {
+ SDK::Output("BytePatches", std::format("Ambiguous signature for bytepatch ({} matches): {} in {}", vMatches.size(), m_sSignature, m_sModule).c_str());
+ U::Core.AppendFailText(std::format("BytePatch::Initialize() ambiguous signature:\n {}\n {}\n {} matches", m_sModule, m_sSignature, vMatches.size()).c_str());
+ return false;
+ }
+
+ const auto hMod = GetModuleHandleA(m_sModule);
+ MODULEINFO module_info;
+ if (!hMod || !GetModuleInformation(GetCurrentProcess(), hMod, &module_info, sizeof(MODULEINFO)))
+ {
+ SDK::Output("BytePatches", std::format("Failed to query module info for {}", m_sModule).c_str());
+ U::Core.AppendFailText(std::format("BytePatch::Initialize() failed module info:\n {}", m_sModule).c_str());
+ return false;
+ }
- m_pAddress = LPVOID(uintptr_t(m_pAddress) + m_iOffset);
+ const auto uModuleBase = uintptr_t(hMod);
+ const auto uModuleEnd = uModuleBase + module_info.SizeOfImage;
+ const auto uAddress = uintptr_t(vMatches[0]) + m_iOffset;
+ if (uAddress < uModuleBase || uAddress + m_iSize > uModuleEnd || uAddress + m_iSize < uAddress)
+ {
+ SDK::Output("BytePatches", std::format("Refusing out-of-module bytepatch write: {:#x} ({})", uAddress, m_sModule).c_str());
+ U::Core.AppendFailText(std::format("BytePatch::Initialize() out-of-range write blocked:\n {}\n {}\n {:#x}", m_sModule, m_sSignature, uAddress).c_str());
+ return false;
+ }
+
+ m_pAddress = LPVOID(uAddress);
DWORD flNewProtect, flOldProtect;
VirtualProtect(m_pAddress, m_iSize, PAGE_EXECUTE_READWRITE, &flNewProtect);
@@ -45,7 +71,6 @@ bool BytePatch::Initialize()
Write(m_vPatch);
SDK::Output("BytePatches", std::format("Successfully patched {:#x} ('{}', '{}')!", uintptr_t(m_pAddress), m_sModule, m_sSignature).c_str());
- U::Core.AppendSuccessText("BytePatches", std::format("Successfully patched {:#x} ('{}', '{}')!", uintptr_t(m_pAddress), m_sModule, m_sSignature).c_str());
return m_bIsPatched = true;
}
@@ -64,6 +89,10 @@ bool CBytePatches::Initialize(const char* cModule)
for (auto& patch : m_mPatches[cModule])
if (!patch.Initialize())
bFail = true;
+
+ if (!bFail)
+ SDK::Output("BytePatches", std::format("Successfully initialized all byte patches for {}!", cModule).c_str());
+
return !bFail;
}
@@ -72,4 +101,4 @@ void CBytePatches::Unload()
for (auto [_, vPatches] : m_mPatches)
for(auto& tPatch : vPatches)
tPatch.Unload();
-}
\ No newline at end of file
+}
diff --git a/TextmodeTF2/src/BytePatches/BytePatches.h b/TextmodeTF2/src/BytePatches/BytePatches.h
index ad9b49e..77e7a8c 100644
--- a/TextmodeTF2/src/BytePatches/BytePatches.h
+++ b/TextmodeTF2/src/BytePatches/BytePatches.h
@@ -41,37 +41,89 @@ class CBytePatches
// Force Con_DebugLog to run
BytePatch("engine.dll", "74 ? 48 8D 54 24 ? 48 8D 0D ? ? ? ? E8 ? ? ? ? 38 1D", 0x0, "90 90"),
+ // CVideoModeCommon::UpdateWindow
+ // Prevents crash during window update in textmode by skipping one callsite safely.
+ BytePatch("engine.dll", "E8 ? ? ? ? EB ? B1 ?", 0x0, "90 90 90 90 90"),
+
+ // Fixes crash in engine.dll (CVideoModeCommon::GetModeCount or similar)
+ BytePatch("engine.dll", "8B 44 D0 ? C3 CC", 0x0, "31 C0 C3 90 90 90"),
+
+ // S_Init
+ // Signature intentionally anchored through the -nosound branch to avoid multi-hit false matches.
+ BytePatch("engine.dll", "45 33 C0 48 8D 15 ? ? ? ? 48 8B C8 4C 8B 08 41 FF 51 18 48 85 C0 74 ? E8 ? ? ? ? 45 33 C0 48 89 05 ? ? ? ? 48 8D 15", 0x17, "90 90"),
+
+ // Hard bypass for fps_max 30 limit in sub_18020CB60 (engine.dll+0x20CC0C)
+ // Matches: F3 0F 10 40 54 0F 2F 05 ?? ?? ?? ?? 73 ??
+ // We patch the 'jnb' (73) to 'jmp' (EB) to skip the 30fps clamp
+ BytePatch("engine.dll", "F3 0F 10 40 54 0F 2F 05 ?? ?? ?? ?? 73 ??", 0xC, "EB"),
+
+ // SCR_UpdateScreen
+ BytePatch("engine.dll", "40 55 41 54 41 56 41 57 48 8D 6C 24 ? 48 81 EC 88 00 00 00 48 8B 05 ? ? ? ? 45 33 E4 4C 89 65 ? 45 8B FC", 0x0, "31 C0 C3"),
+
+ // CEngineVGui::Simulate
+ BytePatch("engine.dll", "41 57 48 81 EC A0 00 00 00 4C 8B F9 48 8B 0D ? ? ? ? 48 8B 01 FF 90 20 01 00 00 49 83 BF B8 00 00 00 00", 0x0, "31 C0 C3"),
+
+ // CL_DecayLights
+ BytePatch("engine.dll", "48 83 EC 48 0F 29 74 24 30 48 8D 0D ? ? ? ? 0F 29 7C 24 20 E8 ? ? ? ? 0F 28 F8 0F 57 F6 0F 2F FE 0F 86 ? ? ? ?", 0x0, "C3"),
+
+ // _Host_RunFrame -> _Host_RunFrame_Render callsite
+ BytePatch("engine.dll", "45 84 E4 0F 84 ? ? ? ? E8 ? ? ? ? 48 8B 05 ? ? ? ? 4C 8D 25 ? ? ? ? 4C 89 7D ? 48 8D 15", 0x9, "90 90 90 90 90"),
+
+ // _Host_RunFrame_Sound callsite
+ BytePatch("engine.dll", "83 3D ? ? ? ? 06 F2 0F 11 05 ? ? ? ? 75 09 48 8D 0D ? ? ? ? EB 02 33 C9 E8 ? ? ? ? FF 15 ? ? ? ? F2 0F 10 0D", 0x1C, "90 90 90 90 90"),
+
+ // _Host_RunFrame_Client voice gate callsite
+ BytePatch("engine.dll", "F3 0F 10 05 ? ? ? ? E8 ? ? ? ? E8 ? ? ? ? 84 C0 0F 84 ? ? ? ? 0F 57 C0 C6 44 24 ? 01", 0xD, "31 C0 90 90 90"),
+
+ // _Host_RunFrame_Input -> ClientDLL_ProcessInput callsite
+ BytePatch("engine.dll", "FF 15 ? ? ? ? F2 0F 11 05 ? ? ? ? E8 ? ? ? ? FF 15 ? ? ? ? F2 0F 11 05 ? ? ? ? E8 ? ? ? ?", 0xE, "90 90 90 90 90"),
+
+ // _Host_RunFrame non-threaded path -> CL_RunPrediction(PREDICTION_NORMAL)
+ BytePatch("engine.dll", "48 8B 01 FF 50 18 B9 01 00 00 00 E8 ? ? ? ? E8 ? ? ? ? F3 0F 10 05 ? ? ? ? E8 ? ? ? ? 48 85 F6 74 ? 45 33 C9", 0xB, "90 90 90 90 90"),
+
+ // _Host_RunFrame threaded path -> CL_RunPrediction(PREDICTION_NORMAL)
+ BytePatch("engine.dll", "B9 01 00 00 00 F3 0F 10 05 ? ? ? ? F3 0F 5E 05 ? ? ? ? F3 0F 11 05 ? ? ? ? E8 ? ? ? ? E8 ? ? ? ? 48 8D 0D ? ? ? ? C6 05", 0x1D, "90 90 90 90 90"),
+
+ // _Host_RunFrame non-threaded path -> CL_ExtraMouseUpdate
+ BytePatch("engine.dll", "F3 0F 10 05 ? ? ? ? E8 ? ? ? ? 48 85 F6 74 ? 45 33 C9 44 89 7C 24 20 45 33 C0 48 8B D3 48 8B CE FF 96 A8 00 00 00", 0x8, "90 90 90 90 90"),
+
+ // _Host_RunFrame threaded path -> CL_ExtraMouseUpdate
+ BytePatch("engine.dll", "E8 ? ? ? ? F3 0F 11 05 ? ? ? ? E8 ? ? ? ? F2 0F 10 05 ? ? ? ? 66 0F 5A C0 44 89 35 ? ? ? ? 89 35 ? ? ? ? F3 0F 11 05", 0xD, "90 90 90 90 90"),
+
+ // _Host_RunFrame fallback sleep path
+ BytePatch("engine.dll", "48 8B 05 ? ? ? ? 8B 48 58 E8 ? ? ? ? 8B 0D ? ? ? ? 85 C9 74 05 E8 ? ? ? ? E8", 0xF, "B9 01 00 00 00 90"),
+
+ // _Host_RunFrame tick loop -> toolframework->Think callsite
+ BytePatch("engine.dll", "40 38 3D ? ? ? ? 75 08 0F B6 CB E8 ? ? ? ? 48 8B 0D ? ? ? ? 0F B6 D3 48 8B 01 FF 90 D8 00 00 00 F2 0F 10 0D ? ? ? ?", 0x1E, "90 90 90 90 90 90"),
+
// evil cathook's plan b implementation
// Mod_LoadLighting
// nulls out lighting data loading for maps
- BytePatch("engine.dll", "40 53 48 83 EC 20 48 8B D9 48 63 09 85 C9 75 18", 0x0, "C3"),
+ BytePatch("engine.dll", "40 53 48 83 EC 20 48 8B D9 48 63 09 85 C9 75 18 48 8B 05 ? ? ? ? 48 C7 80 20 01 00 00 00 00 00 00", 0x0, "31 C0 C3"),
// Sprite_LoadModel
// nulls out sprite model loading
- BytePatch("engine.dll", "48 89 5C 24 08 48 89 74 24 18 57 41 56 41 57 48", 0x0, "C3"),
+ BytePatch("engine.dll", "48 89 5C 24 08 48 89 74 24 18 57 41 56 41 57 48 81 EC 50 01 00 00 83 4A 10 01 33 DB 48 8B 0D ? ? ? ? 48 8B FA", 0x0, "C3"),
// Mod_LoadWorldlights
// nulls out world light loading
- BytePatch("engine.dll", "48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57", 0x0, "C3"),
+ BytePatch("engine.dll", "40 56 41 56 41 57 48 83 EC 50 4C 8B 05 ? ? ? ? 33 F6 44 0F B6 FA 4C 8B F1 49 89 B0 38 01 00 00 48 63 01 85 C0 75 18", 0x0, "31 C0 C3"),
// Mod_LoadTexinfo
// forces mat_loadtextures 0 logic to skip material loading
- BytePatch("engine.dll", "0F 84 ? ? ? ? 48 63 7E 44", 0x0, "90 E9"),
+ BytePatch("engine.dll", "0F 84 ? ? ? ? 48 63 7E 44 85 FF 0F 88 ? ? ? ? 48 63 44 24 48", 0x0, "90 E9"),
}},
{"materialsystem",
{
// CMaterialSystem::Init
// Returns 1 (INIT_OK) to prevent material system initialization but allow engine to continue anywyay
- BytePatch("materialsystem.dll", "40 53 48 83 EC 20 48 8B D9 48 8B 0D ? ? ? ? 48 8B 01 FF 90 ? ? ? ? 48 8B 0D", 0x0, "B8 01 00 00 00 C3"),
+ BytePatch("materialsystem.dll", "40 53 48 81 EC 70 01 00 00 48 83 3D ? ? ? ? ? 48 8B D9 74 ? 80 79 08 00 74", 0x0, "B8 01 00 00 00 C3"),
// CMaterialSystem::BeginFrame
// bye bye frame rendering!
- BytePatch("materialsystem.dll", "48 8B 0D ? ? ? ? 48 8B 01 48 FF A0 ? ? ? ? CC", 0x0, "C3"),
+ BytePatch("materialsystem.dll", "40 57 48 81 EC C0 00 00 00 0F 29 B4 24 ? ? ? ? 48 8B F9 0F 28 F1 FF 15 ? ? ? ? 84 C0 0F 84", 0x0, "C3"),
- // CMaterialSystem::FindMaterial
- // returns NULL for every material lookup
- BytePatch("materialsystem.dll", "48 8B F9 48 8B CA 49 8B D8 FF 10 4C 8B C0 48 8D 15 ? ? ? ? 48 8D 4C 24 20", 0x0, "31 C0 C3"),
}},
{"client",
{
@@ -86,6 +138,15 @@ class CBytePatches
// CViewRender::Render
BytePatch("client.dll", "48 89 50 ? 55 57 41 56", 0x0, "31 C0 C3"),
+ // CHLClient::HudUpdate -> GetClientVoiceMgr()->Frame(frametime)
+ BytePatch("client.dll", "E8 ? ? ? ? 48 8B C8 0F 28 CE E8 ? ? ? ? 0F B6 D3 48 8D 0D ? ? ? ? E8 ? ? ? ?", 0xB, "90 90 90 90 90"),
+
+ // CHLClient::HudUpdate -> vgui::GetAnimationController()->UpdateAnimations(engine->Time())
+ BytePatch("client.dll", "48 8B 0D ? ? ? ? 48 8B 01 FF 50 70 0F 28 F0 E8 ? ? ? ? 48 8B C8 0F 28 CE E8 ? ? ? ? 48 8B 05 ? ? ? ?", 0x1B, "90 90 90 90 90"),
+
+ // CHLClient::HudUpdate -> C_BaseTempEntity::CheckDynamicTempEnts
+ BytePatch("client.dll", "48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? 4C 8B C0 FF 13 E8 ? ? ? ? 48 8B 0D ? ? ? ? 48 8B 01 FF 90 D8 00 00 00", 0x13, "90 90 90 90 90"),
+
// This fixes the datacache.dll crash
BytePatch("client.dll", "4D 85 F6 0F 84 ? ? ? ? 49 8B CE E8 ? ? ? ? 83 F8", 0x0, "83 F6 00"),
@@ -137,13 +198,30 @@ class CBytePatches
// Fixes crash
BytePatch("client.dll", "45 85 C0 78 3E 4C 8B 11 45 3B 82 E8 00 00 00 7D 32", 0x0, "4C 8B 11 4D 85 D2 74 3B 45 3B 82 E8 00 00 00 73 32"),
+
+ // Fixes crash in client.dll+0x57cc59v
+ BytePatch("client.dll", "8B 89 ? ? ? ? 85 C9 0F 84 ? ? ? ? 41 BF ? ? ? ?", 0x0, "31 C9 90 90 90 90"),
+
+ // Fixes crash in CHudTextMessage (make index guard unconditional across all 3 duplicated blocks)
+ BytePatch("client.dll", "83 E8 01 78 13 48 63 C8 0F B6 04 39 3C 0A 74 04 3C 0D 75 04 44 88 3C 39 41 B8 00 02 00 00 48 8D 95 40 0B 00 00", 0x3, "EB"),
+ BytePatch("client.dll", "83 E8 01 78 13 48 63 C8 0F B6 04 39 3C 0A 74 04 3C 0D 75 04 44 88 3C 39 41 B8 00 02 00 00 48 8D 95 40 0D 00 00", 0x3, "EB"),
+ BytePatch("client.dll", "83 E8 01 78 13 48 63 C8 0F B6 04 39 3C 0A 74 04 3C 0D 75 04 44 88 3C 39 41 B8 00 02 00 00 48 8D 95 40 0F 00 00", 0x3, "EB"),
}},
{"datacache",
{
// CDataCacheSection::Unlock CRASHFIX!
BytePatch("datacache.dll", "48 89 5C 24 18 48 89 7C 24 20 41 56 48 83 EC 20 F6 81 E0 00 00 00 04", 0x41, "90 90 90 90 90"),
+
+ // Fixes crash in datacache.dll+0xf2b3 (likely FindMDL or similar)
+ BytePatch("datacache.dll", "4E 8B 44 C0 10 4D 85 C0 0F 84 80 00 00 00", 0x0, "45 31 C0 90 90 4D 85 C0 0F 84 80 00 00 00"),
+ }},
+ {"gameui",
+ {
+ BytePatch("GameUI.dll", "80 79 08 00 75 03 32 C0 C3 48 8B 49 10 48 8B 01 48 FF A0 10 01 00 00", 0x0, "32 C0 C3"),
+
+ BytePatch("GameUI.dll", "48 8B 49 10 48 8B 01 48 FF A0 10 01 00 00", 0x4, "32 C0 C3 90 90 90 90 90 90 90"),
}}
};
};
-ADD_FEATURE_CUSTOM(CBytePatches, BytePatches, U);
\ No newline at end of file
+ADD_FEATURE_CUSTOM(CBytePatches, BytePatches, U);
diff --git a/TextmodeTF2/src/Core/Core.cpp b/TextmodeTF2/src/Core/Core.cpp
index e9e2971..554b77d 100644
--- a/TextmodeTF2/src/Core/Core.cpp
+++ b/TextmodeTF2/src/Core/Core.cpp
@@ -2,6 +2,7 @@
#include "../SDK/SDK.h"
#include "../BytePatches/BytePatches.h"
+#include "../Hooks/VPhysics.h"
#include
#define LOAD_WAIT 0 - m_bTimeout
@@ -122,6 +123,41 @@ int CCore::LoadEngine()
if (!U::Hooks.Initialize("CDebugOverlay_AddLineOverlay")) return LOAD_FAIL;
bRenderHooksInit = true;
}
+
+ if (!G::CEngineSoundClient_EmitSoundInternalAddr)
+ G::CEngineSoundClient_EmitSoundInternalAddr = U::Memory.FindSignature("engine.dll", "48 8B C4 44 89 48 20 55 41 57 48 8D 68 C8 48 81 EC ?? ?? ?? ??");
+ if (G::CEngineSoundClient_EmitSoundInternalAddr)
+ U::Hooks.Initialize("CEngineSoundClient_EmitSoundInternal");
+
+ if (!G::R_DrawDecalsAllAddr)
+ G::R_DrawDecalsAllAddr = U::Memory.FindSignature("engine.dll", "48 89 4C 24 08 55 48 8D AC 24 ?? ?? ?? ?? B8 ?? ?? ?? ?? E8");
+ if (G::R_DrawDecalsAllAddr)
+ U::Hooks.Initialize("R_DrawDecalsAll");
+
+ if (!G::CShadowMgr_RenderShadowsAddr)
+ G::CShadowMgr_RenderShadowsAddr = U::Memory.FindSignature("engine.dll", "4C 8B DC 55 41 57 48 83 EC ?? 48 8B 05 ?? ?? ?? ?? 45 33 FF");
+ if (G::CShadowMgr_RenderShadowsAddr)
+ U::Hooks.Initialize("CShadowMgr_RenderShadows");
+
+ if (!G::SVC_TempEntities_ProcessAddr)
+ G::SVC_TempEntities_ProcessAddr = U::Memory.FindSignature("engine.dll", "48 8B D1 48 8B 49 20 48 8B 01 48 FF A0 C0 00 00 00");
+ if (G::SVC_TempEntities_ProcessAddr)
+ U::Hooks.Initialize("SVC_TempEntities_Process");
+
+ if (!G::SVC_GameEvent_ProcessAddr)
+ G::SVC_GameEvent_ProcessAddr = U::Memory.FindSignature("engine.dll", "48 8B D1 48 8B 49 20 48 8B 01 48 FF A0 A0 00 00 00");
+ if (G::SVC_GameEvent_ProcessAddr)
+ U::Hooks.Initialize("SVC_GameEvent_Process");
+
+ if (!G::SVC_Sounds_ProcessAddr)
+ G::SVC_Sounds_ProcessAddr = U::Memory.FindSignature("engine.dll", "48 8B D1 48 8B 49 20 48 8B 01 48 FF A0 78 00 00 00");
+ if (G::SVC_Sounds_ProcessAddr)
+ U::Hooks.Initialize("SVC_Sounds_Process");
+
+ if (!G::SVC_BSPDecal_ProcessAddr)
+ G::SVC_BSPDecal_ProcessAddr = U::Memory.FindSignature("engine.dll", "48 8B D1 48 8B 49 20 48 8B 01 48 FF A0 98 00 00 00");
+ if (G::SVC_BSPDecal_ProcessAddr)
+ U::Hooks.Initialize("SVC_BSPDecal_Process");
}
static bool bBytePatchesInit{ false };
@@ -153,6 +189,28 @@ int CCore::LoadMatSys()
if (!U::Hooks.Initialize(cHook))
return LOAD_FAIL;
+ if (I::StudioRender)
+ {
+ G::IStudioRender_DrawModelAddr = reinterpret_cast(U::Memory.GetVFunc(I::StudioRender, 29));
+ G::IStudioRender_DrawModelStaticPropAddr = reinterpret_cast(U::Memory.GetVFunc(I::StudioRender, 30));
+ G::IStudioRender_DrawStaticPropDecalsAddr = reinterpret_cast(U::Memory.GetVFunc(I::StudioRender, 31));
+ G::IStudioRender_DrawStaticPropShadowsAddr = reinterpret_cast(U::Memory.GetVFunc(I::StudioRender, 32));
+ G::IStudioRender_AddDecalAddr = reinterpret_cast(U::Memory.GetVFunc(I::StudioRender, 36));
+ G::IStudioRender_AddShadowAddr = reinterpret_cast(U::Memory.GetVFunc(I::StudioRender, 39));
+ G::IStudioRender_DrawModelArrayAddr = reinterpret_cast(U::Memory.GetVFunc(I::StudioRender, 46));
+
+ U::Hooks.Initialize("IStudioRender_DrawModel");
+ U::Hooks.Initialize("IStudioRender_DrawModelStaticProp");
+ U::Hooks.Initialize("IStudioRender_DrawStaticPropDecals");
+ U::Hooks.Initialize("IStudioRender_DrawStaticPropShadows");
+ U::Hooks.Initialize("IStudioRender_AddDecal");
+ U::Hooks.Initialize("IStudioRender_AddShadow");
+ U::Hooks.Initialize("IStudioRender_DrawModelArray");
+ }
+
+ if (!U::BytePatches.Initialize("materialsystem"))
+ return LOAD_FAIL;
+
return m_bMatSysLoaded = true;
}
@@ -161,9 +219,38 @@ int CCore::LoadClient()
if (!U::BytePatches.Initialize("client"))
return LOAD_WAIT;
+ // IBaseClientDLL::FrameStageNotify
+ if (!G::IBaseClientDLL_FrameStageNotifyAddr)
+ {
+ if (auto pClient = U::Memory.FindInterface("client.dll", "VClient017"))
+ G::IBaseClientDLL_FrameStageNotifyAddr = reinterpret_cast(U::Memory.GetVFunc(pClient, 35));
+ }
+ if (G::IBaseClientDLL_FrameStageNotifyAddr)
+ U::Hooks.Initialize("IBaseClientDLL_FrameStageNotify");
+
+ // IPanel::PaintTraverse
+ if (!G::IPanel_PaintTraverseAddr)
+ {
+ if (auto pPanel = U::Memory.FindInterface("vgui2.dll", "VGUI_Panel009"))
+ G::IPanel_PaintTraverseAddr = reinterpret_cast(U::Memory.GetVFunc(pPanel, 41));
+ }
+ if (G::IPanel_PaintTraverseAddr)
+ U::Hooks.Initialize("IPanel_PaintTraverse");
+
return m_bClientLoaded = true;
}
+int CCore::LoadGameUI()
+{
+ if (!GetModuleHandleA("GameUI.dll"))
+ return LOAD_WAIT;
+
+ if (!U::BytePatches.Initialize("gameui"))
+ return LOAD_FAIL;
+
+ return m_bGameUILoaded = true;
+}
+
int CCore::LoadParticles()
{
if (!G::CParticleSystemMgr_DrawRenderCacheAddr)
@@ -186,7 +273,7 @@ int CCore::LoadParticles()
m_bParticlesLoaded = true;
}
- return LOAD_WAIT;
+ return m_bParticlesLoaded ? 1 : LOAD_WAIT;
}
int CCore::LoadMDLCache()
@@ -198,9 +285,47 @@ int CCore::LoadMDLCache()
if (!U::Hooks.Initialize("IMDLCache_ProcessDataIntoCache"))
return LOAD_FAIL;
+ if (!U::Hooks.Initialize("IMDLCache_GetHardwareData"))
+ return LOAD_FAIL;
+
+ if (!U::Hooks.Initialize("IMDLCache_GetVertexData"))
+ return LOAD_FAIL;
+
+ if (!U::Hooks.Initialize("IMDLCache_TouchAllData"))
+ return LOAD_FAIL;
+
+ if (!U::BytePatches.Initialize("datacache"))
+ return LOAD_FAIL;
+
return m_bMDLCacheLoaded = true;
}
+int CCore::LoadVideoServices()
+{
+ I::VideoServices = reinterpret_cast(U::Memory.FindInterface("video_services.dll", "IVideoServices002"));
+ if (!I::VideoServices)
+ return LOAD_WAIT;
+
+ if (!U::Hooks.Initialize("IVideoServices_CreateVideoMaterial"))
+ return LOAD_FAIL;
+
+ if (!U::Hooks.Initialize("IVideoServices_PlayVideoFileFullScreen"))
+ return LOAD_FAIL;
+
+ return m_bVideoServicesLoaded = true;
+}
+
+int CCore::LoadVPhysics()
+{
+ G::Physics = reinterpret_cast(U::Memory.FindInterface("vphysics.dll", "VPhysics031"));
+ if (!G::Physics)
+ return LOAD_WAIT;
+
+ Hooks::VPhysics::Initialize();
+
+ return m_bVPhysicsLoaded = true;
+}
+
void CCore::Load()
{
G::CurrentPath = std::filesystem::current_path().string() + "\\TextmodeTF2";
@@ -237,7 +362,11 @@ void CCore::Load()
m_bTimeout = GetModuleHandleA("filesystem_stdio.dll") &&
GetModuleHandleA("engine.dll") &&
GetModuleHandleA("materialsystem.dll") &&
- GetModuleHandleA("client.dll");
+ GetModuleHandleA("client.dll") &&
+ GetModuleHandleA("GameUI.dll") &&
+ GetModuleHandleA("datacache.dll") &&
+ GetModuleHandleA("video_services.dll") &&
+ GetModuleHandleA("vphysics.dll");
int iFilesystem = m_bFilesystemLoaded ? 1 : LoadFilesystem();
CHECK(iFilesystem, "Failed to load file system")
@@ -248,15 +377,28 @@ void CCore::Load()
int iClient = m_bClientLoaded ? 1 : LoadClient();
CHECK(iClient, "Failed to load client")
+ int iGameUI = m_bGameUILoaded ? 1 : LoadGameUI();
+ CHECK(iGameUI, "Failed to load gameui")
+
int iParticles = m_bParticlesLoaded ? 1 : LoadParticles();
CHECK(iParticles, "Failed to load particle system")
int iMDLCache = m_bMDLCacheLoaded ? 1 : LoadMDLCache();
CHECK(iMDLCache, "Failed to load MDL cache")
+
+ int iVideoServices = m_bVideoServicesLoaded ? 1 : LoadVideoServices();
+ CHECK(iVideoServices, "Failed to load video services")
+
+ int iVPhysics = m_bVPhysicsLoaded ? 1 : LoadVPhysics();
+ CHECK(iVPhysics, "Failed to load vphysics")
}
- while (!m_bFilesystemLoaded || !m_bEngineLoaded || !m_bMatSysLoaded || !m_bClientLoaded || !m_bParticlesLoaded || !m_bMDLCacheLoaded);
+ while (!m_bFilesystemLoaded || !m_bEngineLoaded || !m_bMatSysLoaded || !m_bClientLoaded || !m_bGameUILoaded || !m_bParticlesLoaded || !m_bMDLCacheLoaded || !m_bVideoServicesLoaded || !m_bVPhysicsLoaded);
SDK::Output("TextmodeTF2", std::format("Loaded in {} seconds", SDK::PlatFloatTime()).c_str());
+
+ // Final verification log
+ SDK::Output("Core", "Initialization complete. All bytepatches and hooks applied.");
+
}
void CCore::Loop()
@@ -285,4 +427,4 @@ void CCore::Unload()
file << ssFailStream.str();
file.close();
return;
-}
\ No newline at end of file
+}
diff --git a/TextmodeTF2/src/Core/Core.h b/TextmodeTF2/src/Core/Core.h
index 7441cee..e03d96a 100644
--- a/TextmodeTF2/src/Core/Core.h
+++ b/TextmodeTF2/src/Core/Core.h
@@ -17,16 +17,19 @@ class CCore
bool m_bUnload = false;
bool m_bTimeout = false;
private:
- bool m_bFilesystemLoaded = false, m_bEngineLoaded = false, m_bMatSysLoaded = false, m_bClientLoaded = false, m_bParticlesLoaded = false, m_bMDLCacheLoaded = false;
+ bool m_bFilesystemLoaded = false, m_bEngineLoaded = false, m_bMatSysLoaded = false, m_bClientLoaded = false, m_bGameUILoaded = false, m_bParticlesLoaded = false, m_bMDLCacheLoaded = false, m_bVideoServicesLoaded = false, m_bVPhysicsLoaded = false;
int LoadFilesystem();
int LoadEngine();
int LoadMatSys();
int LoadClient();
+ int LoadGameUI();
int LoadParticles();
int LoadMDLCache();
+ int LoadVideoServices();
+ int LoadVPhysics();
std::stringstream ssFailStream;
};
-ADD_FEATURE_CUSTOM(CCore, Core, U);
\ No newline at end of file
+ADD_FEATURE_CUSTOM(CCore, Core, U);
diff --git a/TextmodeTF2/src/Hooks/CEngineSoundClient_EmitSoundInternal.cpp b/TextmodeTF2/src/Hooks/CEngineSoundClient_EmitSoundInternal.cpp
new file mode 100644
index 0000000..e2145e9
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/CEngineSoundClient_EmitSoundInternal.cpp
@@ -0,0 +1,7 @@
+#include "../Utils/Hooks/Hooks.h"
+#include "../SDK/SDK.h"
+
+MAKE_HOOK(CEngineSoundClient_EmitSoundInternal, G::CEngineSoundClient_EmitSoundInternalAddr, void, void* rcx, void* rdx, void* r8, void* r9, void* pSample, float flVolume, int iSoundLevel, int iFlags, int iPitch, int iSpecialDSP, void *pOrigin, void *pDirection, void* pUtlVecOrigins, bool bUpdatePositions, float soundtime, int speakerentity)
+{
+ return;
+}
diff --git a/TextmodeTF2/src/Hooks/CShadowMgr_RenderShadows.cpp b/TextmodeTF2/src/Hooks/CShadowMgr_RenderShadows.cpp
new file mode 100644
index 0000000..9b1d26c
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/CShadowMgr_RenderShadows.cpp
@@ -0,0 +1,7 @@
+#include "../Utils/Hooks/Hooks.h"
+#include "../SDK/SDK.h"
+
+MAKE_HOOK(CShadowMgr_RenderShadows, G::CShadowMgr_RenderShadowsAddr, void, void* rcx, void* rdx, void* r8, void* r9)
+{
+ return;
+}
diff --git a/TextmodeTF2/src/Hooks/IBaseClientDLL_FrameStageNotify.cpp b/TextmodeTF2/src/Hooks/IBaseClientDLL_FrameStageNotify.cpp
new file mode 100644
index 0000000..a2dea9b
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/IBaseClientDLL_FrameStageNotify.cpp
@@ -0,0 +1,11 @@
+#include "../Utils/Hooks/Hooks.h"
+#include "../SDK/SDK.h"
+
+// void IBaseClientDLL::FrameStageNotify(ClientFrameStage_t curStage)
+MAKE_HOOK(IBaseClientDLL_FrameStageNotify, G::IBaseClientDLL_FrameStageNotifyAddr, void, void* rcx, ClientFrameStage_t curStage)
+{
+ if (curStage == FRAME_RENDER_START || curStage == FRAME_RENDER_END)
+ return;
+
+ CALL_ORIGINAL(rcx, curStage);
+}
diff --git a/TextmodeTF2/src/Hooks/IMDLCache_Hooks.cpp b/TextmodeTF2/src/Hooks/IMDLCache_Hooks.cpp
new file mode 100644
index 0000000..d79892b
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/IMDLCache_Hooks.cpp
@@ -0,0 +1,19 @@
+#include "../SDK/SDK.h"
+
+MAKE_HOOK(IMDLCache_GetHardwareData, U::Memory.FindSignature("datacache.dll", "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 48 8B 05 ? ? ? ?"), void*,
+ void* rcx, MDLHandle_t handle)
+{
+ return nullptr;
+}
+
+MAKE_HOOK(IMDLCache_GetVertexData, U::Memory.FindSignature("datacache.dll", "48 83 EC 28 48 8B 05 ? ? ? ? 83 78 58 00"), void*,
+ void* rcx, MDLHandle_t handle)
+{
+ return nullptr;
+}
+
+MAKE_HOOK(IMDLCache_TouchAllData, U::Memory.GetVFunc(reinterpret_cast(G::IMDLCache), 45), bool,
+ void* rcx, MDLHandle_t handle)
+{
+ return true;
+}
diff --git a/TextmodeTF2/src/Hooks/IMDLCache_ProcessDataIntoCache.cpp b/TextmodeTF2/src/Hooks/IMDLCache_ProcessDataIntoCache.cpp
index 351f554..e20f79b 100644
--- a/TextmodeTF2/src/Hooks/IMDLCache_ProcessDataIntoCache.cpp
+++ b/TextmodeTF2/src/Hooks/IMDLCache_ProcessDataIntoCache.cpp
@@ -3,12 +3,8 @@
MAKE_HOOK(IMDLCache_ProcessDataIntoCache, U::Memory.GetVFunc(reinterpret_cast(G::IMDLCache), 33), bool,
void* rcx, MDLHandle_t handle, MDLCacheDataType_t type, void* pData, int nDataSize, bool bAsync)
{
- if (type == MDLCACHE_VERTEXES)
- {
- const char* pszModelName = G::IMDLCache->GetModelName(handle);
- if (pszModelName && SDK::BlacklistFile(pszModelName))
- return true;
- }
+ if (type == MDLCACHE_VERTEXES || type == MDLCACHE_STUDIOHWDATA)
+ return true;
return CALL_ORIGINAL(rcx, handle, type, pData, nDataSize, bAsync);
}
diff --git a/TextmodeTF2/src/Hooks/IMaterialSystem_Hooks.cpp b/TextmodeTF2/src/Hooks/IMaterialSystem_Hooks.cpp
index 57c12a8..a7989a0 100644
--- a/TextmodeTF2/src/Hooks/IMaterialSystem_Hooks.cpp
+++ b/TextmodeTF2/src/Hooks/IMaterialSystem_Hooks.cpp
@@ -11,15 +11,15 @@ MAKE_HOOK(IMaterialSystem_FindMaterial, U::Memory.GetVFunc(I::MaterialSystem, 71
{
if (SDK::BlacklistFile(pMaterialName))
{
- if (std::strstr(pMaterialName, "engine/defaultcubemap"))
- {
- return CALL_ORIGINAL(rcx, "debug/debugempty", pTextureGroupName, false, nullptr);
- }
-
return CALL_ORIGINAL(rcx, "debug/debugempty", pTextureGroupName, false, nullptr);
}
- return CALL_ORIGINAL(rcx, pMaterialName, pTextureGroupName, complain, pComplainPrefix);
+ if (auto pMaterial = CALL_ORIGINAL(rcx, pMaterialName, pTextureGroupName, complain, pComplainPrefix))
+ {
+ return pMaterial;
+ }
+
+ return CALL_ORIGINAL(rcx, "debug/debugempty", pTextureGroupName, false, nullptr);
}
MAKE_HOOK(IMaterialSystem_FindTexture, U::Memory.GetVFunc(I::MaterialSystem, 79), ITexture*, // 79
@@ -30,7 +30,12 @@ MAKE_HOOK(IMaterialSystem_FindTexture, U::Memory.GetVFunc(I::MaterialSystem, 79)
return CALL_ORIGINAL(rcx, "error", pTextureGroupName, false, nAdditionalCreationFlags);
}
- return CALL_ORIGINAL(rcx, pTextureName, pTextureGroupName, complain, nAdditionalCreationFlags);
+ if (auto pTexture = CALL_ORIGINAL(rcx, pTextureName, pTextureGroupName, complain, nAdditionalCreationFlags))
+ {
+ return pTexture;
+ }
+
+ return CALL_ORIGINAL(rcx, "error", pTextureGroupName, false, nAdditionalCreationFlags);
}
MAKE_HOOK(IMaterialSystem_CreateRenderTargetTexture, U::Memory.GetVFunc(I::MaterialSystem, 84), ITexture*, // 84
@@ -59,4 +64,4 @@ MAKE_HOOK(IMaterialSystem_CreateNamedRenderTargetTextureEx2, U::Memory.GetVFunc(
void* rcx, const char* pRTName, int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat format, MaterialRenderTargetDepth_t depth, unsigned int textureFlags, unsigned int renderTargetFlags)
{
return CALL_ORIGINAL(rcx, pRTName, 1, 1, sizeMode, format, depth, textureFlags, renderTargetFlags);
-}
\ No newline at end of file
+}
diff --git a/TextmodeTF2/src/Hooks/IPanel_PaintTraverse.cpp b/TextmodeTF2/src/Hooks/IPanel_PaintTraverse.cpp
new file mode 100644
index 0000000..4b54753
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/IPanel_PaintTraverse.cpp
@@ -0,0 +1,8 @@
+#include "../Utils/Hooks/Hooks.h"
+#include "../SDK/SDK.h"
+
+// void IPanel::PaintTraverse(VPANEL vguiPanel, bool forceRepaint, bool allowForce)
+MAKE_HOOK(IPanel_PaintTraverse, G::IPanel_PaintTraverseAddr, void, void* rcx, VPANEL vguiPanel, bool forceRepaint, bool allowForce)
+{
+ return;
+}
diff --git a/TextmodeTF2/src/Hooks/IStudioRender_Hooks.cpp b/TextmodeTF2/src/Hooks/IStudioRender_Hooks.cpp
new file mode 100644
index 0000000..eff9820
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/IStudioRender_Hooks.cpp
@@ -0,0 +1,45 @@
+#include "../Utils/Hooks/Hooks.h"
+#include "../SDK/SDK.h"
+#include "../SDK/Definitions/Interfaces/IStudioRender.h"
+
+// void IStudioRender::DrawModel(DrawModelResults_t *pResults, const DrawModelInfo_t& info, matrix3x4_t *pBoneToWorld, float *pFlexWeights, float *pFlexDelayedWeights, const Vector &modelOrigin, int flags)
+MAKE_HOOK(IStudioRender_DrawModel, G::IStudioRender_DrawModelAddr, void, void* rcx, void* pResults, void* info, void* pBoneToWorld, void* pFlexWeights, void* pFlexDelayedWeights, void* modelOrigin, int flags)
+{
+ return;
+}
+
+// void IStudioRender::DrawModelStaticProp(const DrawModelInfo_t& drawInfo, const matrix3x4_t &modelToWorld, int flags)
+MAKE_HOOK(IStudioRender_DrawModelStaticProp, G::IStudioRender_DrawModelStaticPropAddr, void, void* rcx, void* drawInfo, void* modelToWorld, int flags)
+{
+ return;
+}
+
+// void IStudioRender::DrawStaticPropDecals(const DrawModelInfo_t &drawInfo, const matrix3x4_t &modelToWorld)
+MAKE_HOOK(IStudioRender_DrawStaticPropDecals, G::IStudioRender_DrawStaticPropDecalsAddr, void, void* rcx, void* drawInfo, void* modelToWorld)
+{
+ return;
+}
+
+// void IStudioRender::DrawStaticPropShadows(const DrawModelInfo_t &drawInfo, const matrix3x4_t &modelToWorld, int flags)
+MAKE_HOOK(IStudioRender_DrawStaticPropShadows, G::IStudioRender_DrawStaticPropShadowsAddr, void, void* rcx, void* drawInfo, void* modelToWorld, int flags)
+{
+ return;
+}
+
+// void IStudioRender::AddDecal(StudioDecalHandle_t handle, studiohdr_t *pStudioHdr, matrix3x4_t *pBoneToWorld, const Ray_t & ray, const Vector& decalUp, IMaterial* pDecalMaterial, float radius, int body, bool noPokethru, int maxLODToDecal)
+MAKE_HOOK(IStudioRender_AddDecal, G::IStudioRender_AddDecalAddr, void, void* rcx, void* handle, void* pStudioHdr, void* pBoneToWorld, void* ray, void* decalUp, void* pDecalMaterial, float radius, int body, bool noPokethru, int maxLODToDecal)
+{
+ return;
+}
+
+// void IStudioRender::AddShadow(IMaterial* pMaterial, void* pProxyData, FlashlightState_t *m_pFlashlightState, VMatrix *pWorldToTexture, ITexture *pFlashlightDepthTexture)
+MAKE_HOOK(IStudioRender_AddShadow, G::IStudioRender_AddShadowAddr, void, void* rcx, void* pMaterial, void* pProxyData, void* m_pFlashlightState, void* pWorldToTexture, void* pFlashlightDepthTexture)
+{
+ return;
+}
+
+// void IStudioRender::DrawModelArray(const DrawModelInfo_t &drawInfo, int arrayCount, model_array_instance_t *pInstanceData, int instanceStride, int flags)
+MAKE_HOOK(IStudioRender_DrawModelArray, G::IStudioRender_DrawModelArrayAddr, void, void* rcx, void* drawInfo, int arrayCount, void* pInstanceData, int instanceStride, int flags)
+{
+ return;
+}
diff --git a/TextmodeTF2/src/Hooks/IVideoServices_Hooks.cpp b/TextmodeTF2/src/Hooks/IVideoServices_Hooks.cpp
new file mode 100644
index 0000000..56d514c
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/IVideoServices_Hooks.cpp
@@ -0,0 +1,16 @@
+#include "../SDK/SDK.h"
+#include "../SDK/Definitions/Interfaces/IVideoServices.h"
+
+// IVideoMaterial* CreateVideoMaterial(const char* pMaterialName, const char* pVideoFileName, const char* pPathID = nullptr, VideoPlaybackFlags_t playbackFlags = 0, VideoSystem_t videoSystem = VideoSystem::DETERMINE_FROM_FILE_EXTENSION, bool PlayAlternateIfNotAvailable = true)
+MAKE_HOOK(IVideoServices_CreateVideoMaterial, U::Memory.GetVFunc(I::VideoServices, 18), IVideoMaterial*, // 18
+ void* rcx, const char* pMaterialName, const char* pVideoFileName, const char* pPathID, VideoPlaybackFlags_t playbackFlags, VideoSystem_t videoSystem, bool PlayAlternateIfNotAvailable)
+{
+ return nullptr;
+}
+
+// VideoResult_t PlayVideoFileFullScreen(const char* pFileName, const char* pPathID, void* mainWindow, int windowWidth, int windowHeight, int desktopWidth, int desktopHeight, bool windowed, float forcedMinTime, VideoPlaybackFlags_t playbackFlags = 0, VideoSystem_t videoSystem = VideoSystem::DETERMINE_FROM_FILE_EXTENSION, bool PlayAlternateIfNotAvailable = true)
+MAKE_HOOK(IVideoServices_PlayVideoFileFullScreen, U::Memory.GetVFunc(I::VideoServices, 24), VideoResult_t, // 24
+ void* rcx, const char* pFileName, const char* pPathID, void* mainWindow, int windowWidth, int windowHeight, int desktopWidth, int desktopHeight, bool windowed, float forcedMinTime, VideoPlaybackFlags_t playbackFlags, VideoSystem_t videoSystem, bool PlayAlternateIfNotAvailable)
+{
+ return VideoResult::SUCCESS;
+}
diff --git a/TextmodeTF2/src/Hooks/R_DrawDecalsAll.cpp b/TextmodeTF2/src/Hooks/R_DrawDecalsAll.cpp
new file mode 100644
index 0000000..69bc21c
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/R_DrawDecalsAll.cpp
@@ -0,0 +1,7 @@
+#include "../Utils/Hooks/Hooks.h"
+#include "../SDK/SDK.h"
+
+MAKE_HOOK(R_DrawDecalsAll, G::R_DrawDecalsAllAddr, void, void* rcx, void* rdx, void* r8, void* r9)
+{
+ return;
+}
diff --git a/TextmodeTF2/src/Hooks/SVC_BSPDecal_Process.cpp b/TextmodeTF2/src/Hooks/SVC_BSPDecal_Process.cpp
new file mode 100644
index 0000000..aa1ad70
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/SVC_BSPDecal_Process.cpp
@@ -0,0 +1,7 @@
+#include "../Utils/Hooks/Hooks.h"
+#include "../SDK/SDK.h"
+
+MAKE_HOOK(SVC_BSPDecal_Process, G::SVC_BSPDecal_ProcessAddr, bool, void* rcx)
+{
+ return true;
+}
diff --git a/TextmodeTF2/src/Hooks/SVC_GameEvent_Process.cpp b/TextmodeTF2/src/Hooks/SVC_GameEvent_Process.cpp
new file mode 100644
index 0000000..ef473a7
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/SVC_GameEvent_Process.cpp
@@ -0,0 +1,7 @@
+#include "../Utils/Hooks/Hooks.h"
+#include "../SDK/SDK.h"
+
+MAKE_HOOK(SVC_GameEvent_Process, G::SVC_GameEvent_ProcessAddr, bool, void* rcx)
+{
+ return true;
+}
diff --git a/TextmodeTF2/src/Hooks/SVC_Sounds_Process.cpp b/TextmodeTF2/src/Hooks/SVC_Sounds_Process.cpp
new file mode 100644
index 0000000..3624896
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/SVC_Sounds_Process.cpp
@@ -0,0 +1,7 @@
+#include "../Utils/Hooks/Hooks.h"
+#include "../SDK/SDK.h"
+
+MAKE_HOOK(SVC_Sounds_Process, G::SVC_Sounds_ProcessAddr, bool, void* rcx)
+{
+ return true;
+}
diff --git a/TextmodeTF2/src/Hooks/SVC_TempEntities_Process.cpp b/TextmodeTF2/src/Hooks/SVC_TempEntities_Process.cpp
new file mode 100644
index 0000000..7189052
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/SVC_TempEntities_Process.cpp
@@ -0,0 +1,7 @@
+#include "../Utils/Hooks/Hooks.h"
+#include "../SDK/SDK.h"
+
+MAKE_HOOK(SVC_TempEntities_Process, G::SVC_TempEntities_ProcessAddr, bool, void* rcx)
+{
+ return true;
+}
diff --git a/TextmodeTF2/src/Hooks/VPhysics.cpp b/TextmodeTF2/src/Hooks/VPhysics.cpp
new file mode 100644
index 0000000..43bd7bd
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/VPhysics.cpp
@@ -0,0 +1,72 @@
+#include "VPhysics.h"
+#include "../SDK/SDK.h"
+
+MAKE_HOOK(hkCreateFluidController, NULL, IPhysicsFluidController*, IPhysicsEnvironment* rcx, IPhysicsObject* pFluidObject, fluidparams_t* pParams)
+{
+ // Null out fluid simulation creation
+ // This prevents water physics and other fluid interactions
+ return nullptr;
+}
+
+MAKE_HOOK(hkCreateRagdollConstraint, NULL, IPhysicsConstraint*, IPhysicsEnvironment* rcx, IPhysicsObject* pReferenceObject, IPhysicsObject* pAttachedObject, IPhysicsConstraintGroup* pGroup, const constraint_ragdollparams_t& ragdoll)
+{
+ // Null out ragdoll constraint creation
+ // This effectively disables ragdoll physics
+ return nullptr;
+}
+
+MAKE_HOOK(hkDestroyConstraint, NULL, void, IPhysicsEnvironment* rcx, IPhysicsConstraint* pConstraint)
+{
+ // Handle null constraint destruction safely
+ if (!pConstraint)
+ return;
+
+ CALL_ORIGINAL(rcx, pConstraint);
+}
+
+void Hooks::VPhysics::Initialize()
+{
+ if (!G::Physics)
+ {
+ SDK::Output("VPhysics", "Interface not found, skipping hooks");
+ return;
+ }
+
+ // Create a dummy environment to get the vtable address
+ // This works because all instances of CPhysicsEnvironment share the same vtable
+ IPhysicsEnvironment* pEnv = G::Physics->CreateEnvironment();
+ if (!pEnv)
+ {
+ SDK::Output("VPhysics", "Failed to create dummy environment");
+ return;
+ }
+
+ void** vtable = *reinterpret_cast(pEnv);
+
+ // Initialize hooks using the vtable from the dummy environment
+ // Indices:
+ // CreateFluidController: 10
+ // CreateRagdollConstraint: 12
+ // DestroyConstraint: 23
+
+ // We use the 'address' parameter of MAKE_HOOK as a placeholder (NULL)
+ // and manually create the hook using the vtable address.
+ // However, the MAKE_HOOK macro expects 'address' to be used in Init().
+ // We need to bypass the standard Init() or manually set the address.
+
+ // Let's use the CHook::Create directly for these since we have dynamic addresses
+
+ // Hook CreateFluidController (Index 10)
+ hkCreateFluidController::Hook.Create(vtable[10], hkCreateFluidController::Func);
+
+ // Hook CreateRagdollConstraint (Index 12)
+ hkCreateRagdollConstraint::Hook.Create(vtable[12], hkCreateRagdollConstraint::Func);
+
+ // Hook DestroyConstraint (Index 23)
+ hkDestroyConstraint::Hook.Create(vtable[23], hkDestroyConstraint::Func);
+
+ SDK::Output("VPhysics", "Hooks initialized");
+
+ // Clean up the dummy environment
+ G::Physics->DestroyEnvironment(pEnv);
+}
diff --git a/TextmodeTF2/src/Hooks/VPhysics.h b/TextmodeTF2/src/Hooks/VPhysics.h
new file mode 100644
index 0000000..e1c7a72
--- /dev/null
+++ b/TextmodeTF2/src/Hooks/VPhysics.h
@@ -0,0 +1,10 @@
+#pragma once
+#include "../SDK/SDK.h"
+
+namespace Hooks
+{
+ namespace VPhysics
+ {
+ void Initialize();
+ }
+}
diff --git a/TextmodeTF2/src/SDK/Definitions/Definitions.h b/TextmodeTF2/src/SDK/Definitions/Definitions.h
index 682eff5..4629f99 100644
--- a/TextmodeTF2/src/SDK/Definitions/Definitions.h
+++ b/TextmodeTF2/src/SDK/Definitions/Definitions.h
@@ -60,4 +60,18 @@ struct FileAsyncRequest_t
};
typedef void * FileHandle_t;
-typedef void * FileCacheHandle_t;
\ No newline at end of file
+typedef void * FileCacheHandle_t;
+
+enum ClientFrameStage_t
+{
+ FRAME_UNDEFINED = -1,
+ FRAME_START,
+ FRAME_NET_UPDATE_START,
+ FRAME_NET_UPDATE_POSTDATAUPDATE_START,
+ FRAME_NET_UPDATE_POSTDATAUPDATE_END,
+ FRAME_NET_UPDATE_END,
+ FRAME_RENDER_START,
+ FRAME_RENDER_END
+};
+
+typedef unsigned int VPANEL;
\ No newline at end of file
diff --git a/TextmodeTF2/src/SDK/Definitions/Interfaces.h b/TextmodeTF2/src/SDK/Definitions/Interfaces.h
index ed27963..4c779c0 100644
--- a/TextmodeTF2/src/SDK/Definitions/Interfaces.h
+++ b/TextmodeTF2/src/SDK/Definitions/Interfaces.h
@@ -3,5 +3,11 @@
#include "../../Utils/Feature/Feature.h"
#include "Interfaces/IMaterialSystem.h"
#include "Interfaces/IMDLCache.h"
+#include "Interfaces/IStudioRender.h"
+#include "Interfaces/IVideoServices.h"
+#include "Interfaces/IPhysics.h"
-MAKE_INTERFACE_VERSION(IMDLCache, MDLCache, "datacache.dll", "MDLCache004");
\ No newline at end of file
+MAKE_INTERFACE_VERSION(IMDLCache, MDLCache, "datacache.dll", "MDLCache004");
+MAKE_INTERFACE_VERSION(IStudioRender, StudioRender, "studiorender.dll", "VStudioRender025");
+MAKE_INTERFACE_VERSION(IVideoServices, VideoServices, "video_services.dll", "IVideoServices002");
+MAKE_INTERFACE_VERSION(IPhysics, Physics, "vphysics.dll", "VPhysics031");
\ No newline at end of file
diff --git a/TextmodeTF2/src/SDK/Definitions/Interfaces/IMDLCache.h b/TextmodeTF2/src/SDK/Definitions/Interfaces/IMDLCache.h
index 7bea4e6..a544479 100644
--- a/TextmodeTF2/src/SDK/Definitions/Interfaces/IMDLCache.h
+++ b/TextmodeTF2/src/SDK/Definitions/Interfaces/IMDLCache.h
@@ -37,7 +37,7 @@ class IMDLCache : public IAppSystem
virtual void* GetVirtualModel(MDLHandle_t handle) = 0;
virtual int GetAutoplayList(MDLHandle_t handle, unsigned short** pOut) = 0;
virtual void* GetVertexData(MDLHandle_t handle) = 0;
- virtual void TouchAllData(MDLHandle_t handle) = 0;
+ virtual void TouchAllData_Old(MDLHandle_t handle) = 0;
virtual void SetUserData(MDLHandle_t handle, void* pData) = 0;
virtual void* GetUserData(MDLHandle_t handle) = 0;
virtual bool IsErrorModel(MDLHandle_t handle) = 0;
@@ -55,5 +55,15 @@ class IMDLCache : public IAppSystem
virtual bool SetAsyncLoad(MDLCacheDataType_t type, bool bAsync) = 0;
virtual void BeginMapLoad() = 0;
virtual void EndMapLoad() = 0;
- virtual bool ProcessDataIntoCache(MDLHandle_t handle, MDLCacheDataType_t type, void* pData, int nDataSize, bool bAsync) = 0;
+ virtual void MarkAsLoaded(MDLHandle_t handle) = 0;
+ virtual void InitPreloadData(bool rebuild) = 0;
+ virtual void ShutdownPreloadData() = 0;
+ virtual bool IsDataLoaded(MDLHandle_t handle, MDLCacheDataType_t type) = 0;
+ virtual int* GetFrameUnlockCounterPtr(MDLCacheDataType_t type) = 0;
+ virtual void* LockStudioHdr(MDLHandle_t handle) = 0;
+ virtual void UnlockStudioHdr(MDLHandle_t handle) = 0;
+ virtual bool PreloadModel(MDLHandle_t handle) = 0;
+ virtual void ResetErrorModelStatus(MDLHandle_t handle) = 0;
+ virtual void MarkFrame() = 0;
+ virtual bool TouchAllData(MDLHandle_t handle) = 0;
};
diff --git a/TextmodeTF2/src/SDK/Definitions/Interfaces/IStudioRender.h b/TextmodeTF2/src/SDK/Definitions/Interfaces/IStudioRender.h
new file mode 100644
index 0000000..db71b49
--- /dev/null
+++ b/TextmodeTF2/src/SDK/Definitions/Interfaces/IStudioRender.h
@@ -0,0 +1,122 @@
+#pragma once
+#include "Interface.h"
+#include "../Misc/IAppSystem.h"
+
+// Forward declarations
+struct studiohdr_t;
+struct studiohwdata_t;
+struct Vector;
+struct Vector4D;
+struct Vector2D;
+struct LightDesc_t;
+struct Ray_t;
+struct matrix3x4_t;
+class IMaterial;
+class IMesh;
+struct IPooledVBAllocator;
+class ITexture;
+struct FlashlightState_t;
+struct VMatrix;
+struct vertexFileHeader_t;
+
+typedef void* StudioDecalHandle_t;
+#define STUDIORENDER_DECAL_INVALID ((StudioDecalHandle_t)0)
+
+struct DrawModelResults_t;
+struct DrawModelInfo_t;
+struct GetTriangles_Output_t;
+struct model_array_instance_t;
+
+struct StudioRenderConfig_t
+{
+ float fEyeShiftX;
+ float fEyeShiftY;
+ float fEyeShiftZ;
+ float fEyeSize;
+ float fEyeGlintPixelWidthLODThreshold;
+ int maxDecalsPerModel;
+ int drawEntities;
+ int skin;
+ int fullbright;
+ bool bEyeMove : 1;
+ bool bSoftwareSkin : 1;
+ bool bNoHardware : 1;
+ bool bNoSoftware : 1;
+ bool bTeeth : 1;
+ bool bEyes : 1;
+ bool bFlex : 1;
+ bool bWireframe : 1;
+ bool bDrawNormals : 1;
+ bool bDrawTangentFrame : 1;
+ bool bDrawZBufferedWireframe : 1;
+ bool bSoftwareLighting : 1;
+ bool bShowEnvCubemapOnly : 1;
+ bool bWireframeDecals : 1;
+ int m_nReserved[4];
+};
+
+enum OverrideType_t
+{
+ OVERRIDE_NORMAL = 0,
+ OVERRIDE_BUILD_SHADOWS,
+ OVERRIDE_DEPTH_WRITE,
+ OVERRIDE_SSAO_DEPTH_WRITE,
+};
+
+class IStudioRender : public IAppSystem
+{
+public:
+ virtual void BeginFrame(void) = 0;
+ virtual void EndFrame(void) = 0;
+ virtual void Mat_Stub(void* pMatSys) = 0;
+ virtual void UpdateConfig(const StudioRenderConfig_t& config) = 0;
+ virtual void GetCurrentConfig(StudioRenderConfig_t& config) = 0;
+ virtual bool LoadModel(studiohdr_t* pStudioHdr, void* pVtxData, studiohwdata_t* pHardwareData) = 0;
+ virtual void UnloadModel(studiohwdata_t* pHardwareData) = 0;
+ virtual void RefreshStudioHdr(studiohdr_t* pStudioHdr, studiohwdata_t* pHardwareData) = 0;
+ virtual void SetEyeViewTarget(const studiohdr_t* pStudioHdr, int nBodyIndex, const Vector& worldPosition) = 0;
+ virtual int GetNumAmbientLightSamples() = 0;
+ virtual const Vector* GetAmbientLightDirections() = 0;
+ virtual void SetAmbientLightColors(const Vector4D* pAmbientOnlyColors) = 0;
+ virtual void SetAmbientLightColors(const Vector* pAmbientOnlyColors) = 0;
+ virtual void SetLocalLights(int numLights, const LightDesc_t* pLights) = 0;
+ virtual void SetViewState(const Vector& viewOrigin, const Vector& viewRight, const Vector& viewUp, const Vector& viewPlaneNormal) = 0;
+ virtual void LockFlexWeights(int nWeightCount, float** ppFlexWeights, float** ppFlexDelayedWeights = nullptr) = 0;
+ virtual void UnlockFlexWeights() = 0;
+ virtual matrix3x4_t* LockBoneMatrices(int nBoneCount) = 0;
+ virtual void UnlockBoneMatrices() = 0;
+ virtual int GetNumLODs(const studiohwdata_t& hardwareData) const = 0;
+ virtual float GetLODSwitchValue(const studiohwdata_t& hardwareData, int lod) const = 0;
+ virtual void SetLODSwitchValue(studiohwdata_t& hardwareData, int lod, float switchValue) = 0;
+ virtual void SetColorModulation(float const* pColor) = 0;
+ virtual void SetAlphaModulation(float flAlpha) = 0;
+
+ // Index 29
+ virtual void DrawModel(DrawModelResults_t* pResults, const DrawModelInfo_t& info, matrix3x4_t* pBoneToWorld, float* pFlexWeights, float* pFlexDelayedWeights, const Vector& modelOrigin, int flags = 0) = 0;
+
+ // Index 30
+ virtual void DrawModelStaticProp(const DrawModelInfo_t& drawInfo, const matrix3x4_t& modelToWorld, int flags = 0) = 0;
+
+ // Index 31
+ virtual void DrawStaticPropDecals(const DrawModelInfo_t& drawInfo, const matrix3x4_t& modelToWorld) = 0;
+
+ // Index 32
+ virtual void DrawStaticPropShadows(const DrawModelInfo_t& drawInfo, const matrix3x4_t& modelToWorld, int flags) = 0;
+
+ virtual void ForcedMaterialOverride(IMaterial* newMaterial, OverrideType_t nOverrideType = OVERRIDE_NORMAL) = 0;
+ virtual StudioDecalHandle_t CreateDecalList(studiohwdata_t* pHardwareData) = 0;
+ virtual void DestroyDecalList(StudioDecalHandle_t handle) = 0;
+ virtual void AddDecal(StudioDecalHandle_t handle, studiohdr_t* pStudioHdr, matrix3x4_t* pBoneToWorld, const Ray_t& ray, const Vector& decalUp, IMaterial* pDecalMaterial, float radius, int body, bool noPokethru = false, int maxLODToDecal = -1) = 0;
+ virtual void ComputeLighting(const Vector* pAmbient, int lightCount, LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting) = 0;
+ virtual void ComputeLightingConstDirectional(const Vector* pAmbient, int lightCount, LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting, float flDirectionalAmount) = 0;
+ virtual void AddShadow(IMaterial* pMaterial, void* pProxyData, FlashlightState_t* m_pFlashlightState = nullptr, VMatrix* pWorldToTexture = nullptr, ITexture* pFlashlightDepthTexture = nullptr) = 0;
+ virtual void ClearAllShadows() = 0;
+ virtual int ComputeModelLod(studiohwdata_t* pHardwareData, float unitSphereSize, float* pMetric = nullptr) = 0;
+ virtual void GetPerfStats(DrawModelResults_t* pResults, const DrawModelInfo_t& info, void* pSpewBuf = nullptr) const = 0;
+ virtual void GetTriangles(const DrawModelInfo_t& info, matrix3x4_t* pBoneToWorld, GetTriangles_Output_t& out) = 0;
+ virtual int GetMaterialList(studiohdr_t* pStudioHdr, int count, IMaterial** ppMaterials) = 0;
+ virtual int GetMaterialListFromBodyAndSkin(void* studio, int nSkin, int nBody, int nCountOutputMaterials, IMaterial** ppOutputMaterials) = 0;
+
+ // Index 47 (approx)
+ virtual void DrawModelArray(const DrawModelInfo_t& drawInfo, int arrayCount, model_array_instance_t* pInstanceData, int instanceStride, int flags = 0) = 0;
+};
diff --git a/TextmodeTF2/src/SDK/Definitions/Interfaces/IVideoServices.h b/TextmodeTF2/src/SDK/Definitions/Interfaces/IVideoServices.h
new file mode 100644
index 0000000..36cdf55
--- /dev/null
+++ b/TextmodeTF2/src/SDK/Definitions/Interfaces/IVideoServices.h
@@ -0,0 +1,119 @@
+#pragma once
+#include "Interface.h"
+#include "../Misc/IAppSystem.h"
+
+//-----------------------------------------------------------------------------
+// enums used when dealing with video services
+//-----------------------------------------------------------------------------
+
+namespace VideoResult
+{
+ enum EVideoResult_t
+ {
+ SUCCESS = 0,
+
+ SYSTEM_NOT_AVAILABLE,
+ CODEC_NOT_AVAILABLE,
+ FEATURE_NOT_AVAILABLE,
+
+ UNKNOWN_OPERATION,
+ ILLEGAL_OPERATION,
+ OPERATION_NOT_SUPPORTED,
+
+ BAD_INPUT_PARAMETERS,
+ OPERATION_ALREADY_PERFORMED,
+ OPERATION_OUT_OF_SEQUENCE,
+
+ VIDEO_ERROR_OCCURED,
+ FILE_ERROR_OCCURED,
+ AUDIO_ERROR_OCCURED,
+ SYSTEM_ERROR_OCCURED,
+ INITIALIZATION_ERROR_OCCURED,
+ SHUTDOWN_ERROR_OCCURED,
+
+ MATERIAL_NOT_FOUND,
+ RECORDER_NOT_FOUND,
+ VIDEO_FILE_NOT_FOUND,
+ VIDEO_SYSTEM_NOT_FOUND,
+ };
+};
+typedef VideoResult::EVideoResult_t VideoResult_t;
+
+namespace VideoSystem
+{
+ enum EVideoSystem_t
+ {
+ ALL_VIDEO_SYSTEMS = -2,
+ DETERMINE_FROM_FILE_EXTENSION = -1,
+ NONE = 0,
+
+ BINK,
+ };
+}
+typedef VideoSystem::EVideoSystem_t VideoSystem_t;
+
+typedef int VideoSystemStatus_t;
+typedef int VideoSystemFeature_t;
+typedef int VideoEncodeCodec_t;
+typedef int VideoPlaybackFlags_t;
+typedef int VideoSoundDeviceOperation_t;
+
+class IVideoMaterial;
+class IVideoRecorder;
+
+//-----------------------------------------------------------------------------
+// Main VIDEO_SERVICES interface
+//-----------------------------------------------------------------------------
+#define VIDEO_SERVICES_INTERFACE_VERSION "IVideoServices002"
+
+
+class IVideoServices : public IAppSystem
+{
+public:
+ // Query the available video systems
+ virtual int GetAvailableVideoSystemCount() = 0;
+ virtual VideoSystem_t GetAvailableVideoSystem(int n) = 0;
+
+ virtual bool IsVideoSystemAvailable(VideoSystem_t videoSystem) = 0;
+ virtual VideoSystemStatus_t GetVideoSystemStatus(VideoSystem_t videoSystem) = 0;
+ virtual VideoSystemFeature_t GetVideoSystemFeatures(VideoSystem_t videoSystem) = 0;
+ virtual const char* GetVideoSystemName(VideoSystem_t videoSystem) = 0;
+
+ virtual VideoSystem_t FindNextSystemWithFeature(VideoSystemFeature_t features, VideoSystem_t startAfter = VideoSystem::NONE) = 0;
+
+ virtual VideoResult_t GetLastResult() = 0;
+
+ // deal with video file extensions and video system mappings
+ virtual int GetSupportedFileExtensionCount(VideoSystem_t videoSystem) = 0;
+ virtual const char* GetSupportedFileExtension(VideoSystem_t videoSystem, int extNum = 0) = 0;
+ virtual VideoSystemFeature_t GetSupportedFileExtensionFeatures(VideoSystem_t videoSystem, int extNum = 0) = 0;
+
+ virtual VideoSystem_t LocateVideoSystemForPlayingFile(const char* pFileName, VideoSystemFeature_t playMode = 0) = 0;
+ virtual VideoResult_t LocatePlayableVideoFile(const char* pSearchFileName, const char* pPathID, VideoSystem_t* pPlaybackSystem, char* pPlaybackFileName, int fileNameMaxLen, VideoSystemFeature_t playMode = 0) = 0;
+
+ // Create/destroy a video material
+ virtual IVideoMaterial* CreateVideoMaterial(const char* pMaterialName, const char* pVideoFileName, const char* pPathID = nullptr,
+ VideoPlaybackFlags_t playbackFlags = 0,
+ VideoSystem_t videoSystem = VideoSystem::DETERMINE_FROM_FILE_EXTENSION, bool PlayAlternateIfNotAvailable = true) = 0;
+
+ virtual VideoResult_t DestroyVideoMaterial(IVideoMaterial* pVideoMaterial) = 0;
+ virtual int GetUniqueMaterialID() = 0;
+
+ // Create/destroy a video encoder
+ virtual VideoResult_t IsRecordCodecAvailable(VideoSystem_t videoSystem, VideoEncodeCodec_t codec) = 0;
+
+ virtual IVideoRecorder* CreateVideoRecorder(VideoSystem_t videoSystem) = 0;
+ virtual VideoResult_t DestroyVideoRecorder(IVideoRecorder* pVideoRecorder) = 0;
+
+ // Plays a given video file until it completes or the user presses ESC, SPACE, or ENTER
+ virtual VideoResult_t PlayVideoFileFullScreen(const char* pFileName, const char* pPathID, void* mainWindow, int windowWidth, int windowHeight, int desktopWidth, int desktopHeight, bool windowed, float forcedMinTime,
+ VideoPlaybackFlags_t playbackFlags = 0,
+ VideoSystem_t videoSystem = VideoSystem::DETERMINE_FROM_FILE_EXTENSION, bool PlayAlternateIfNotAvailable = true) = 0;
+
+ // Sets the sound devices that the video will decode to
+ virtual VideoResult_t SoundDeviceCommand(VideoSoundDeviceOperation_t operation, void* pDevice = nullptr, void* pData = nullptr, VideoSystem_t videoSystem = VideoSystem::ALL_VIDEO_SYSTEMS) = 0;
+
+ // Get the (localized) name of a codec as a string
+ virtual const wchar_t* GetCodecName(VideoEncodeCodec_t nCodec) = 0;
+
+};
diff --git a/TextmodeTF2/src/SDK/Globals.h b/TextmodeTF2/src/SDK/Globals.h
index 8d3750a..16ed412 100644
--- a/TextmodeTF2/src/SDK/Globals.h
+++ b/TextmodeTF2/src/SDK/Globals.h
@@ -30,5 +30,21 @@ namespace G
inline uintptr_t CDebugOverlay_AddBoxOverlayAddr{};
inline uintptr_t CDebugOverlay_AddLineOverlayAddr{};
inline uintptr_t CParticleSystemMgr_ReadParticleConfigFileAddr{};
+ inline uintptr_t CEngineSoundClient_EmitSoundInternalAddr{};
+ inline uintptr_t R_DrawDecalsAllAddr{};
+ inline uintptr_t CShadowMgr_RenderShadowsAddr{};
+ inline uintptr_t SVC_TempEntities_ProcessAddr{};
+inline uintptr_t SVC_GameEvent_ProcessAddr{};
+inline uintptr_t SVC_Sounds_ProcessAddr{};
+inline uintptr_t SVC_BSPDecal_ProcessAddr{};
+ inline uintptr_t IBaseClientDLL_FrameStageNotifyAddr{};
+ inline uintptr_t IPanel_PaintTraverseAddr{};
+ inline uintptr_t IStudioRender_DrawModelAddr{};
+ inline uintptr_t IStudioRender_DrawModelStaticPropAddr{};
+ inline uintptr_t IStudioRender_DrawStaticPropDecalsAddr{};
+ inline uintptr_t IStudioRender_DrawStaticPropShadowsAddr{};
+ inline uintptr_t IStudioRender_AddDecalAddr{};
+ inline uintptr_t IStudioRender_AddShadowAddr{};
+ inline uintptr_t IStudioRender_DrawModelArrayAddr{};
inline IMDLCache* IMDLCache{};
};
\ No newline at end of file
diff --git a/TextmodeTF2/src/SDK/Interfaces/IPhysics.h b/TextmodeTF2/src/SDK/Interfaces/IPhysics.h
new file mode 100644
index 0000000..f173806
--- /dev/null
+++ b/TextmodeTF2/src/SDK/Interfaces/IPhysics.h
@@ -0,0 +1,80 @@
+#pragma once
+#include "../Globals.h"
+
+// Forward declarations
+struct Vector;
+struct QAngle;
+
+// Indices for IPhysicsEnvironment (VPhysics030)
+// CreateFluidController: 10
+// CreateRagdollConstraint: 12
+// DestroyConstraint: 23
+
+class IPhysicsObject;
+class IPhysicsFluidController;
+class IPhysicsConstraint;
+class IPhysicsConstraintGroup;
+struct fluidparams_t;
+struct constraint_ragdollparams_t;
+struct constraint_groupparams_t;
+
+class IPhysicsEnvironment
+{
+public:
+ virtual void Unused0() = 0; // Destructor
+ virtual void SetDebugOverlay( void* debugOverlayFactory ) = 0;
+ virtual void* GetDebugOverlay( void ) = 0;
+ virtual void SetGravity( const Vector &gravityVector ) = 0;
+ virtual void GetGravity( Vector &gravityVector ) = 0;
+ virtual void SetAirDensity( float density ) = 0;
+ virtual float GetAirDensity( void ) = 0;
+ virtual IPhysicsObject *CreatePolyObject( const void *pCollisionModel, int materialIndex, const Vector &position, const QAngle &angles, void *pParams ) = 0;
+ virtual IPhysicsObject *CreatePolyObjectStatic( const void *pCollisionModel, int materialIndex, const Vector &position, const QAngle &angles, void *pParams ) = 0;
+ virtual IPhysicsObject *CreateSphereObject( float radius, int materialIndex, const Vector &position, const QAngle &angles, void *pParams, bool isStatic ) = 0;
+
+ // Index 10
+ virtual IPhysicsFluidController *CreateFluidController( IPhysicsObject *pFluidObject, fluidparams_t *pParams ) = 0;
+
+ virtual void* CreateSpring( IPhysicsObject *pObjectStart, IPhysicsObject *pObjectEnd, void *pParams ) = 0;
+
+ // Index 12
+ virtual IPhysicsConstraint *CreateRagdollConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ragdollparams_t &ragdoll ) = 0;
+
+ virtual IPhysicsConstraint *CreateHingeConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const void *hinge ) = 0;
+ virtual IPhysicsConstraint *CreateFixedConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const void *fixed ) = 0;
+ virtual IPhysicsConstraint *CreateSlidingConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const void *sliding ) = 0;
+ virtual IPhysicsConstraint *CreateBallsocketConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const void *ballsocket ) = 0;
+ virtual IPhysicsConstraint *CreatePulleyConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const void *pulley ) = 0;
+ virtual IPhysicsConstraint *CreateLengthConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const void *length ) = 0;
+
+ virtual IPhysicsConstraintGroup *CreateConstraintGroup( const constraint_groupparams_t &groupParams ) = 0;
+
+ virtual void DestroyObject( IPhysicsObject * ) = 0;
+ virtual void DestroySpring( void * ) = 0;
+ virtual void DestroyFluidController( IPhysicsFluidController * ) = 0;
+
+ // Index 23
+ virtual void DestroyConstraint( IPhysicsConstraint * ) = 0;
+};
+
+class IPhysics
+{
+public:
+ // IAppSystem
+ virtual void Unused0() = 0;
+ virtual void Unused1() = 0;
+ virtual void Unused2() = 0;
+ virtual void Unused3() = 0;
+ virtual void Unused4() = 0;
+
+ // IPhysics
+ virtual IPhysicsEnvironment *CreateEnvironment( void ) = 0;
+ virtual void DestroyEnvironment( IPhysicsEnvironment * ) = 0;
+ virtual IPhysicsEnvironment *GetActiveEnvironmentByIndex( int index ) = 0;
+};
+
+namespace G
+{
+ inline IPhysics* Physics = nullptr;
+ inline IPhysicsEnvironment* PhysicsEnvironment = nullptr;
+}
diff --git a/TextmodeTF2/src/Utils/CrashLog/CrashLog.cpp b/TextmodeTF2/src/Utils/CrashLog/CrashLog.cpp
index 65d0921..61fa8a4 100644
--- a/TextmodeTF2/src/Utils/CrashLog/CrashLog.cpp
+++ b/TextmodeTF2/src/Utils/CrashLog/CrashLog.cpp
@@ -26,6 +26,9 @@ static PVOID s_pHandle;
static LPVOID s_lpParam;
static std::unordered_map s_mAddresses = {};
static int s_iExceptions = 0;
+#ifdef _DEBUG
+static LONG s_lShowingCrashDialog = 0;
+#endif
static std::deque StackTrace(PCONTEXT pContext)
{
@@ -124,6 +127,7 @@ static LONG APIENTRY ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
case STATUS_ACCESS_VIOLATION: sError = "ACCESS VIOLATION"; break;
case STATUS_STACK_OVERFLOW: sError = "STACK OVERFLOW"; break;
case STATUS_HEAP_CORRUPTION: sError = "HEAP CORRUPTION"; break;
+ case 0x4001000A: // DBG_PRINTEXCEPTION_WIDE_C (OutputDebugStringW)
case MS_VC_EXCEPTION:
case DBG_PRINTEXCEPTION_C: return EXCEPTION_EXECUTE_HANDLER;
}
@@ -190,6 +194,15 @@ static LONG APIENTRY ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
}
catch (...) {}
+#ifdef _DEBUG
+ if (InterlockedCompareExchange(&s_lShowingCrashDialog, 1, 0) == 0)
+ {
+ const std::string sCrashText = ssErrorStream.str();
+ MessageBoxA(nullptr, sCrashText.c_str(), "TextmodeTF2 Exception", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_SYSTEMMODAL);
+ InterlockedExchange(&s_lShowingCrashDialog, 0);
+ }
+#endif
+
return EXCEPTION_EXECUTE_HANDLER;
}
@@ -201,4 +214,4 @@ void CrashLog::Initialize(LPVOID lpParam)
void CrashLog::Unload()
{
RemoveVectoredExceptionHandler(s_pHandle);
-}
\ No newline at end of file
+}
diff --git a/TextmodeTF2/src/Utils/Interfaces/Interfaces.h b/TextmodeTF2/src/Utils/Interfaces/Interfaces.h
index b73ffb7..27011bc 100644
--- a/TextmodeTF2/src/Utils/Interfaces/Interfaces.h
+++ b/TextmodeTF2/src/Utils/Interfaces/Interfaces.h
@@ -1,5 +1,5 @@
#pragma once
-#include "../../Utils/Feature/Feature.h"
+#include "../Feature/Feature.h"
#include
struct InterfaceInit_t
diff --git a/TextmodeTF2/src/Utils/Memory/Memory.cpp b/TextmodeTF2/src/Utils/Memory/Memory.cpp
index 7233858..b2e34c2 100644
--- a/TextmodeTF2/src/Utils/Memory/Memory.cpp
+++ b/TextmodeTF2/src/Utils/Memory/Memory.cpp
@@ -52,29 +52,43 @@ std::vector CMemory::PatternToInt(const char* szPattern)
uintptr_t CMemory::FindSignature(const char* szModule, const char* szPattern)
{
+ const auto vMatches = FindSignatures(szModule, szPattern, 1);
+ if (!vMatches.empty())
+ return vMatches[0];
+
+ return 0x0;
+}
+
+std::vector CMemory::FindSignatures(const char* szModule, const char* szPattern, size_t nMaxMatches)
+{
+ std::vector vMatches = {};
+
if (const auto hMod = GetModuleHandleA(szModule))
{
// Get module information to search in the given module
MODULEINFO module_info;
if (!GetModuleInformation(GetCurrentProcess(), hMod, &module_info, sizeof(MODULEINFO)))
- return {};
+ return vMatches;
// The region where we will search for the byte sequence
const auto image_size = module_info.SizeOfImage;
// Check if the image is faulty
if (!image_size)
- return {};
+ return vMatches;
// Convert IDA-Style signature to a byte sequence
const auto pattern_bytes = PatternToInt(szPattern);
const auto signature_size = pattern_bytes.size();
+ if (!signature_size || signature_size > image_size)
+ return vMatches;
+
const int* signature_bytes = pattern_bytes.data();
const auto image_bytes = reinterpret_cast(hMod);
// Now loop through all bytes and check if the byte sequence matches
- for (auto i = 0ul; i < image_size - signature_size; ++i)
+ for (auto i = 0ul; i <= image_size - signature_size; ++i)
{
auto byte_sequence_found = true;
@@ -90,13 +104,15 @@ uintptr_t CMemory::FindSignature(const char* szModule, const char* szPattern)
}
if (byte_sequence_found)
- return { reinterpret_cast(&image_bytes[i]) };
+ {
+ vMatches.push_back(reinterpret_cast(&image_bytes[i]));
+ if (nMaxMatches && vMatches.size() >= nMaxMatches)
+ break;
+ }
}
-
- return {};
}
- return 0x0;
+ return vMatches;
}
using CreateInterfaceFn = void* (*)(const char* pName, int* pReturnCode);
@@ -135,4 +151,4 @@ uintptr_t CMemory::GetOffsetFromBase(uintptr_t uAddress)
uintptr_t uBase = uintptr_t(hModule);
return uAddress - uBase;
-}
\ No newline at end of file
+}
diff --git a/TextmodeTF2/src/Utils/Memory/Memory.h b/TextmodeTF2/src/Utils/Memory/Memory.h
index fd0ff1b..32c26a3 100644
--- a/TextmodeTF2/src/Utils/Memory/Memory.h
+++ b/TextmodeTF2/src/Utils/Memory/Memory.h
@@ -10,6 +10,7 @@ class CMemory
public:
std::vector PatternToByte(const char* szPattern);
std::vector PatternToInt(const char* szPattern);
+ std::vector FindSignatures(const char* szModule, const char* szPattern, size_t nMaxMatches = 0);
uintptr_t FindSignature(const char* szModule, const char* szPattern);
PVOID FindInterface(const char* szModule, const char* szObject);
std::string GetModuleOffset(void* pAddress) { return GetModuleOffset(uintptr_t(pAddress)); };
@@ -37,4 +38,4 @@ class CMemory
}
};
-ADD_FEATURE_CUSTOM(CMemory, Memory, U)
\ No newline at end of file
+ADD_FEATURE_CUSTOM(CMemory, Memory, U)