From 67486135944c44e7a4dec6021edfbbe862ae9b2b Mon Sep 17 00:00:00 2001 From: mlemlody Date: Sun, 11 Jan 2026 20:47:58 +0100 Subject: [PATCH 1/6] better --- TextmodeTF2/TextmodeTF2.vcxproj | 11 ++- TextmodeTF2/src/BytePatches/BytePatches.cpp | 4 +- TextmodeTF2/src/BytePatches/BytePatches.h | 32 ++++++++ TextmodeTF2/src/Core/Core.cpp | 61 ++++++++++++++- TextmodeTF2/src/Core/Core.h | 3 +- .../src/Hooks/CDebugOverlay_AddBoxOverlay.cpp | 8 ++ .../Hooks/CDebugOverlay_AddLineOverlay.cpp | 8 ++ .../Hooks/CModelLoader_GetModelForName.cpp | 20 +++++ .../Hooks/CModelRender_DrawModelExecute.cpp | 8 ++ .../Hooks/CParticleCollection_Simulate.cpp | 8 ++ .../CParticleSystemMgr_DrawRenderCache.cpp | 8 ++ .../Hooks/CStaticPropMgr_DrawStaticProps.cpp | 8 ++ .../CStaticPropMgr_UnserializeStaticProps.cpp | 8 ++ TextmodeTF2/src/Hooks/S_PrecacheSound.cpp | 8 ++ TextmodeTF2/src/SDK/Globals.h | 9 +++ TextmodeTF2/src/SDK/SDK.cpp | 75 ++++++++++++++++--- TextmodeTF2/src/Utils/Hooks/Hooks.cpp | 12 +++ .../src/Utils/Interfaces/Interfaces.cpp | 28 ++++--- 18 files changed, 296 insertions(+), 23 deletions(-) create mode 100644 TextmodeTF2/src/Hooks/CDebugOverlay_AddBoxOverlay.cpp create mode 100644 TextmodeTF2/src/Hooks/CDebugOverlay_AddLineOverlay.cpp create mode 100644 TextmodeTF2/src/Hooks/CModelLoader_GetModelForName.cpp create mode 100644 TextmodeTF2/src/Hooks/CModelRender_DrawModelExecute.cpp create mode 100644 TextmodeTF2/src/Hooks/CParticleCollection_Simulate.cpp create mode 100644 TextmodeTF2/src/Hooks/CParticleSystemMgr_DrawRenderCache.cpp create mode 100644 TextmodeTF2/src/Hooks/CStaticPropMgr_DrawStaticProps.cpp create mode 100644 TextmodeTF2/src/Hooks/CStaticPropMgr_UnserializeStaticProps.cpp create mode 100644 TextmodeTF2/src/Hooks/S_PrecacheSound.cpp diff --git a/TextmodeTF2/TextmodeTF2.vcxproj b/TextmodeTF2/TextmodeTF2.vcxproj index 507fd80..a5e566f 100644 --- a/TextmodeTF2/TextmodeTF2.vcxproj +++ b/TextmodeTF2/TextmodeTF2.vcxproj @@ -1,4 +1,4 @@ - + @@ -226,11 +226,20 @@ + + + + + + + + + diff --git a/TextmodeTF2/src/BytePatches/BytePatches.cpp b/TextmodeTF2/src/BytePatches/BytePatches.cpp index 598aebe..cac6686 100644 --- a/TextmodeTF2/src/BytePatches/BytePatches.cpp +++ b/TextmodeTF2/src/BytePatches/BytePatches.cpp @@ -30,6 +30,7 @@ bool BytePatch::Initialize() m_pAddress = LPVOID(U::Memory.FindSignature(m_sModule, m_sSignature)); if (!m_pAddress) { + 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; } @@ -43,7 +44,8 @@ bool BytePatch::Initialize() Write(m_vPatch); - U::Core.AppendSuccessText("BytePatches", std::format("Successfully patched {:#x} ('{}', '{}')!", uintptr_t(m_pAddress) + m_iOffset, m_sModule, m_sSignature).c_str()); + 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; } diff --git a/TextmodeTF2/src/BytePatches/BytePatches.h b/TextmodeTF2/src/BytePatches/BytePatches.h index 2206a6d..c4e8daf 100644 --- a/TextmodeTF2/src/BytePatches/BytePatches.h +++ b/TextmodeTF2/src/BytePatches/BytePatches.h @@ -40,6 +40,38 @@ class CBytePatches BytePatch("engine.dll", "0F 85 ? ? ? ? 48 8D 15 ? ? ? ? B9", 0x0, "0F 81"), // Force Con_DebugLog to run BytePatch("engine.dll", "74 ? 48 8D 54 24 ? 48 8D 0D ? ? ? ? E8 ? ? ? ? 38 1D", 0x0, "90 90"), + + // evil cathook's plan b implementation + + // Mod_LoadLighting (sub_180102C50) + // 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"), + + // Sprite_LoadModel (sub_180105390) + // 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"), + + // Mod_LoadWorldlights (sub_1801025E0) + // 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"), + + // Mod_LoadTexinfo (sub_180103E30) + // forces mat_loadtextures 0 logic to skip material loading + BytePatch("engine.dll", "0F 84 ? ? ? ? 48 63 7E 44", 0x0, "90 E9"), + }}, + {"materialsystem", + { + // CMaterialSystem::Init (sub_180017050) + // 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"), + + // CMaterialSystem::BeginFrame (sub_180015630) + // bye bye frame rendering! + BytePatch("materialsystem.dll", "48 8B 0D ? ? ? ? 48 8B 01 48 FF A0 ? ? ? ? CC", 0x0, "C3"), + + // CMaterialSystem::FindMaterial (sub_180017310) + // 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", { diff --git a/TextmodeTF2/src/Core/Core.cpp b/TextmodeTF2/src/Core/Core.cpp index 81e04c2..dada0ed 100644 --- a/TextmodeTF2/src/Core/Core.cpp +++ b/TextmodeTF2/src/Core/Core.cpp @@ -8,6 +8,8 @@ #define LOAD_FAIL -1 #define CHECK(x, sFailMessage) if (x == LOAD_FAIL) {m_bUnload = true; SDK::Output("TextmodeTF2", sFailMessage); return;} +// TODO: null subsystems (Particle, Material, Model partially, Sound and etc.) + void CCore::AppendFailText(const char* sMessage, bool bCritical) { if (!m_bTimeout && !bCritical) @@ -93,12 +95,43 @@ int CCore::LoadEngine() } } + static bool bRenderHooksInit{ false }; + if (!bRenderHooksInit) + { + if (!G::CStaticPropMgr_DrawStaticPropsAddr) + G::CStaticPropMgr_DrawStaticPropsAddr = U::Memory.FindSignature("engine.dll", "4C 8B DC 49 89 5B 08 49 89 6B 10 49 89 73 18 57 41 54 41 55 41 56 41 57 48 83 EC 70 4C 8B 3D ? ? ? ? 33 FF"); + if (!G::CStaticPropMgr_UnserializeStaticPropsAddr) + G::CStaticPropMgr_UnserializeStaticPropsAddr = U::Memory.FindSignature("engine.dll", "40 57 48 81 EC E0 00 00 00 80 B9 98 00 00 00 00"); + if (!G::S_PrecacheSoundAddr) + G::S_PrecacheSoundAddr = U::Memory.FindSignature("engine.dll", "4C 8B DC 49 89 5B 08 49 89 73 18 57 48 83 EC 50"); + if (!G::CModelLoader_GetModelForNameAddr) + G::CModelLoader_GetModelForNameAddr = U::Memory.FindSignature("engine.dll", "44 89 44 24 18 53 48 83 EC 20 48 8B D9 E8 ?? ?? ?? ?? 4C 8D 44 24 40"); + if (!G::CModelRender_DrawModelExecuteAddr) + G::CModelRender_DrawModelExecuteAddr = U::Memory.FindSignature("engine.dll", "4C 89 4C 24 20 48 89 4C 24 08 55 53 56 57 41 54 41 56 41 57 48 8D AC 24 D0 FD FF FF 48 81 EC 30 03 00 00 41 8B 70 40"); + if (!G::CDebugOverlay_AddBoxOverlayAddr) + G::CDebugOverlay_AddBoxOverlayAddr = U::Memory.FindSignature("engine.dll", "48 89 74 24 18 4C 89 74 24 20 41 57 48 81 EC 80 00 00 00 48 8D 0D ? ? ? ? 49 8B F1 4D 8B F0 4C 8B FA E8 ? ? ? ? 84 C0"); + if (!G::CDebugOverlay_AddLineOverlayAddr) + G::CDebugOverlay_AddLineOverlayAddr = U::Memory.FindSignature("engine.dll", "4C 8B DC 53 55 56 57 41 56 48 81 EC 80 00 00 00 49 8D 43 30 0F 29 74 24 70 48 89 81 10 04 00 00 48 8D 69 10"); + + if (G::CStaticPropMgr_DrawStaticPropsAddr && G::CStaticPropMgr_UnserializeStaticPropsAddr && G::S_PrecacheSoundAddr && G::CModelLoader_GetModelForNameAddr && G::CModelRender_DrawModelExecuteAddr && G::CDebugOverlay_AddBoxOverlayAddr && G::CDebugOverlay_AddLineOverlayAddr) + { + if (!U::Hooks.Initialize("CStaticPropMgr_DrawStaticProps")) return LOAD_FAIL; + if (!U::Hooks.Initialize("CStaticPropMgr_UnserializeStaticProps")) return LOAD_FAIL; + if (!U::Hooks.Initialize("S_PrecacheSound")) return LOAD_FAIL; + if (!U::Hooks.Initialize("CModelLoader_GetModelForName")) return LOAD_FAIL; + if (!U::Hooks.Initialize("CModelRender_DrawModelExecute")) return LOAD_FAIL; + if (!U::Hooks.Initialize("CDebugOverlay_AddBoxOverlay")) return LOAD_FAIL; + if (!U::Hooks.Initialize("CDebugOverlay_AddLineOverlay")) return LOAD_FAIL; + bRenderHooksInit = true; + } + } + static bool bBytePatchesInit{ false }; if (!bBytePatchesInit && U::BytePatches.Initialize("engine")) bBytePatchesInit = true; - if(!bStartupGraphicHookInit || !bInsecureBypassInit || !bTextmodeInit || !bCon_DebugLogInit || !bBytePatchesInit) + if(!bStartupGraphicHookInit || !bInsecureBypassInit || !bTextmodeInit || !bCon_DebugLogInit || !bBytePatchesInit || !bRenderHooksInit) return LOAD_WAIT; return m_bEngineLoaded = true; @@ -133,9 +166,30 @@ int CCore::LoadClient() return m_bClientLoaded = true; } +int CCore::LoadParticles() +{ + if (!G::CParticleSystemMgr_DrawRenderCacheAddr) + G::CParticleSystemMgr_DrawRenderCacheAddr = U::Memory.FindSignature("client.dll", "48 8B C4 88 50 10 48 89 48 08 55 57 41 55 41 57 48 8D A8 28 FD FF FF"); + + if (!G::CParticleCollection_SimulateAddr) + G::CParticleCollection_SimulateAddr = U::Memory.FindSignature("client.dll", "48 8B C4 44 88 40 18 57 41 56 48 81 EC 08 01 00 00"); + + if (G::CParticleSystemMgr_DrawRenderCacheAddr && G::CParticleCollection_SimulateAddr) + { + if (!U::Hooks.Initialize("CParticleSystemMgr_DrawRenderCache")) + return LOAD_FAIL; + if (!U::Hooks.Initialize("CParticleCollection_Simulate")) + return LOAD_FAIL; + return m_bParticlesLoaded = true; + } + + return LOAD_WAIT; +} + void CCore::Load() { G::CurrentPath = std::filesystem::current_path().string() + "\\TextmodeTF2"; + SDK::Output("Core", "Initializing logging..."); char* cBotID = nullptr; if (_dupenv_s(&cBotID, nullptr, "BOTID") == 0 && cBotID) { @@ -178,8 +232,11 @@ void CCore::Load() CHECK(iMatSys, "Failed to load material system") int iClient = m_bClientLoaded ? 1 : LoadClient(); CHECK(iClient, "Failed to load client") + + int iParticles = m_bParticlesLoaded ? 1 : LoadParticles(); + CHECK(iParticles, "Failed to load particle system") } - while (!m_bFilesystemLoaded || !m_bEngineLoaded || !m_bMatSysLoaded || !m_bClientLoaded); + while (!m_bFilesystemLoaded || !m_bEngineLoaded || !m_bMatSysLoaded || !m_bClientLoaded || !m_bParticlesLoaded); SDK::Output("TextmodeTF2", std::format("Loaded in {} seconds", SDK::PlatFloatTime()).c_str()); } diff --git a/TextmodeTF2/src/Core/Core.h b/TextmodeTF2/src/Core/Core.h index 14aaeb9..215b3ba 100644 --- a/TextmodeTF2/src/Core/Core.h +++ b/TextmodeTF2/src/Core/Core.h @@ -17,12 +17,13 @@ class CCore bool m_bUnload = false; bool m_bTimeout = false; private: - bool m_bFilesystemLoaded = false, m_bEngineLoaded = false, m_bMatSysLoaded = false, m_bClientLoaded = false; + bool m_bFilesystemLoaded = false, m_bEngineLoaded = false, m_bMatSysLoaded = false, m_bClientLoaded = false, m_bParticlesLoaded = false; int LoadFilesystem(); int LoadEngine(); int LoadMatSys(); int LoadClient(); + int LoadParticles(); std::stringstream ssFailStream; }; diff --git a/TextmodeTF2/src/Hooks/CDebugOverlay_AddBoxOverlay.cpp b/TextmodeTF2/src/Hooks/CDebugOverlay_AddBoxOverlay.cpp new file mode 100644 index 0000000..61b32a7 --- /dev/null +++ b/TextmodeTF2/src/Hooks/CDebugOverlay_AddBoxOverlay.cpp @@ -0,0 +1,8 @@ +#include "../Utils/Hooks/Hooks.h" +#include "../SDK/SDK.h" + +// void CDebugOverlay::AddBoxOverlay(const Vector& origin, const Vector& mins, const Vector& max, QAngle const& orientation, int r, int g, int b, int a, float duration) +MAKE_HOOK(CDebugOverlay_AddBoxOverlay, G::CDebugOverlay_AddBoxOverlayAddr, void, void* rcx, const void* origin, const void* mins, const void* max, const void* orientation, int r, int g, int b, int a, float duration) +{ + return; +} diff --git a/TextmodeTF2/src/Hooks/CDebugOverlay_AddLineOverlay.cpp b/TextmodeTF2/src/Hooks/CDebugOverlay_AddLineOverlay.cpp new file mode 100644 index 0000000..b619545 --- /dev/null +++ b/TextmodeTF2/src/Hooks/CDebugOverlay_AddLineOverlay.cpp @@ -0,0 +1,8 @@ +#include "../Utils/Hooks/Hooks.h" +#include "../SDK/SDK.h" + +// void CDebugOverlay::AddLineOverlay(const Vector& origin, const Vector& dest, int r, int g, int b, bool noDepthTest, float duration) +MAKE_HOOK(CDebugOverlay_AddLineOverlay, G::CDebugOverlay_AddLineOverlayAddr, void, void* rcx, const void* origin, const void* dest, int r, int g, int b, bool noDepthTest, float duration) +{ + return; +} diff --git a/TextmodeTF2/src/Hooks/CModelLoader_GetModelForName.cpp b/TextmodeTF2/src/Hooks/CModelLoader_GetModelForName.cpp new file mode 100644 index 0000000..79abb61 --- /dev/null +++ b/TextmodeTF2/src/Hooks/CModelLoader_GetModelForName.cpp @@ -0,0 +1,20 @@ +#include "../Utils/Hooks/Hooks.h" +#include "../SDK/SDK.h" + +// model_t *CModelLoader::GetModelForName( const char *name, REFERENCETYPE referencetype ) +MAKE_HOOK(CModelLoader_GetModelForName, G::CModelLoader_GetModelForNameAddr, void*, void* rcx, const char* name, int referencetype) +{ + if (SDK::BlacklistFile(name)) + { + return CALL_ORIGINAL(rcx, "models/empty.mdl", referencetype); + } + + void* pModel = CALL_ORIGINAL(rcx, name, referencetype); + + if (!pModel && name) + { + pModel = CALL_ORIGINAL(rcx, "models/empty.mdl", referencetype); + } + + return pModel; +} diff --git a/TextmodeTF2/src/Hooks/CModelRender_DrawModelExecute.cpp b/TextmodeTF2/src/Hooks/CModelRender_DrawModelExecute.cpp new file mode 100644 index 0000000..cc58fda --- /dev/null +++ b/TextmodeTF2/src/Hooks/CModelRender_DrawModelExecute.cpp @@ -0,0 +1,8 @@ +#include "../Utils/Hooks/Hooks.h" +#include "../SDK/SDK.h" + +// void CModelRender::DrawModelExecute( const DrawModelState_t &state, const ModelRenderInfo_t &pInfo, matrix3x4_t *pCustomBoneToWorld ) +MAKE_HOOK(CModelRender_DrawModelExecute, G::CModelRender_DrawModelExecuteAddr, void, void* rcx, void* state, void* pInfo, void* pCustomBoneToWorld) +{ + return; +} diff --git a/TextmodeTF2/src/Hooks/CParticleCollection_Simulate.cpp b/TextmodeTF2/src/Hooks/CParticleCollection_Simulate.cpp new file mode 100644 index 0000000..0b40397 --- /dev/null +++ b/TextmodeTF2/src/Hooks/CParticleCollection_Simulate.cpp @@ -0,0 +1,8 @@ +#include "../Utils/Hooks/Hooks.h" +#include "../SDK/SDK.h" + +// CParticleCollection::Simulate(float flTime) +MAKE_HOOK(CParticleCollection_Simulate, G::CParticleCollection_SimulateAddr, void, void* rcx, float flTime) +{ + return; +} diff --git a/TextmodeTF2/src/Hooks/CParticleSystemMgr_DrawRenderCache.cpp b/TextmodeTF2/src/Hooks/CParticleSystemMgr_DrawRenderCache.cpp new file mode 100644 index 0000000..a85c172 --- /dev/null +++ b/TextmodeTF2/src/Hooks/CParticleSystemMgr_DrawRenderCache.cpp @@ -0,0 +1,8 @@ +#include "../Utils/Hooks/Hooks.h" +#include "../SDK/SDK.h" + +// CParticleSystemMgr::DrawRenderCache(bool bInclusionMode) +MAKE_HOOK(CParticleSystemMgr_DrawRenderCache, G::CParticleSystemMgr_DrawRenderCacheAddr, void, void* rcx, bool bInclusionMode) +{ + return; +} diff --git a/TextmodeTF2/src/Hooks/CStaticPropMgr_DrawStaticProps.cpp b/TextmodeTF2/src/Hooks/CStaticPropMgr_DrawStaticProps.cpp new file mode 100644 index 0000000..6b1f17a --- /dev/null +++ b/TextmodeTF2/src/Hooks/CStaticPropMgr_DrawStaticProps.cpp @@ -0,0 +1,8 @@ +#include "../Utils/Hooks/Hooks.h" +#include "../SDK/SDK.h" + +// void CStaticPropMgr::DrawStaticProps( IClientRenderable **pProps, int count, bool bShadowDepth, bool drawVCollideWireframe ) +MAKE_HOOK(CStaticPropMgr_DrawStaticProps, G::CStaticPropMgr_DrawStaticPropsAddr, void, void* rcx, void* pProps, int count, bool bShadowDepth, bool drawVCollideWireframe) +{ + return; +} diff --git a/TextmodeTF2/src/Hooks/CStaticPropMgr_UnserializeStaticProps.cpp b/TextmodeTF2/src/Hooks/CStaticPropMgr_UnserializeStaticProps.cpp new file mode 100644 index 0000000..bee987f --- /dev/null +++ b/TextmodeTF2/src/Hooks/CStaticPropMgr_UnserializeStaticProps.cpp @@ -0,0 +1,8 @@ +#include "../Utils/Hooks/Hooks.h" +#include "../SDK/SDK.h" + +// void CStaticPropMgr::UnserializeStaticProps() +MAKE_HOOK(CStaticPropMgr_UnserializeStaticProps, G::CStaticPropMgr_UnserializeStaticPropsAddr, void, void* rcx) +{ + return; +} diff --git a/TextmodeTF2/src/Hooks/S_PrecacheSound.cpp b/TextmodeTF2/src/Hooks/S_PrecacheSound.cpp new file mode 100644 index 0000000..dc11560 --- /dev/null +++ b/TextmodeTF2/src/Hooks/S_PrecacheSound.cpp @@ -0,0 +1,8 @@ +#include "../Utils/Hooks/Hooks.h" +#include "../SDK/SDK.h" + +// CSfxTable *S_PrecacheSound( const char *name ) +MAKE_HOOK(S_PrecacheSound, G::S_PrecacheSoundAddr, void*, const char* name) +{ + return nullptr; +} diff --git a/TextmodeTF2/src/SDK/Globals.h b/TextmodeTF2/src/SDK/Globals.h index ef95714..39d228d 100644 --- a/TextmodeTF2/src/SDK/Globals.h +++ b/TextmodeTF2/src/SDK/Globals.h @@ -18,4 +18,13 @@ namespace G inline uintptr_t Host_IsSecureServerAllowedAddr{}; inline uintptr_t Client_CreateEntityByNameAddr{}; inline uintptr_t Con_DebugLogAddr{}; + inline uintptr_t CParticleSystemMgr_DrawRenderCacheAddr{}; + inline uintptr_t CParticleCollection_SimulateAddr{}; + inline uintptr_t CStaticPropMgr_DrawStaticPropsAddr{}; + inline uintptr_t CStaticPropMgr_UnserializeStaticPropsAddr{}; + inline uintptr_t S_PrecacheSoundAddr{}; + inline uintptr_t CModelLoader_GetModelForNameAddr{}; + inline uintptr_t CModelRender_DrawModelExecuteAddr{}; + inline uintptr_t CDebugOverlay_AddBoxOverlayAddr{}; + inline uintptr_t CDebugOverlay_AddLineOverlayAddr{}; }; \ No newline at end of file diff --git a/TextmodeTF2/src/SDK/SDK.cpp b/TextmodeTF2/src/SDK/SDK.cpp index 9b756c9..38ef523 100644 --- a/TextmodeTF2/src/SDK/SDK.cpp +++ b/TextmodeTF2/src/SDK/SDK.cpp @@ -2,15 +2,35 @@ void SDK::Output(const char* cFunction, const char* cLog, bool bLogFile, int iMessageBox) { +#ifdef _DEBUG + if (!GetConsoleWindow()) + { + AllocConsole(); + FILE* pFile; + freopen_s(&pFile, "CONOUT$", "w", stdout); + } +#endif + if (cLog) { + std::string sLog = std::format("[{}] {}", cFunction, cLog); +#ifdef _DEBUG + printf("%s\n", sLog.c_str()); + fflush(stdout); +#endif + if (bLogFile) - OutputFile(TEXTMODE_LOG_FILE, std::format("[{}] {}\n", cFunction, cLog).c_str()); + OutputFile(TEXTMODE_LOG_FILE, (sLog + "\n").c_str()); if (iMessageBox != -1) MessageBox(nullptr, cLog, cFunction, iMessageBox); } else { +#ifdef _DEBUG + printf("%s\n", cFunction); + fflush(stdout); +#endif + if (bLogFile) OutputFile(TEXTMODE_LOG_FILE, std::format("{}\n", cFunction).c_str()); if (iMessageBox != -1) @@ -20,14 +40,36 @@ void SDK::Output(const char* cFunction, const char* cLog, bool bLogFile, int iMe void SDK::OutputFile(const char* cOutputFileName, const char* cMsg) { - if (G::AppdataPath.empty()) - return; + std::string sPath = G::AppdataPath.empty() ? G::CurrentPath + "\\" : G::AppdataPath; + if (sPath == "\\" || sPath.empty()) + { + char szPath[MAX_PATH]; + if (GetModuleFileNameA(NULL, szPath, MAX_PATH)) + { + std::string sModulePath(szPath); + sPath = sModulePath.substr(0, sModulePath.find_last_of("\\/")) + "\\"; + } + } + try { std::ofstream file; - file.open(G::AppdataPath + cOutputFileName, std::ios::app); - file << cMsg; - file.close(); + file.open(sPath + cOutputFileName, std::ios::app); + if (file.is_open()) + { + file << cMsg; + file.flush(); + file.close(); + } + + if (!file.is_open()) { + std::ofstream backupFile; + backupFile.open("C:\\TextmodeLog_Backup.log", std::ios::app); + if (backupFile.is_open()) { + backupFile << cMsg; + backupFile.close(); + } + } } catch (...) {} } @@ -38,7 +80,11 @@ bool SDK::BlacklistFile(const char* cFileName) ".ani", ".wav", ".mp3", ".vvd", ".vtx", ".vtf", ".vfe", ".cache", ".jpg", ".png", ".tga", ".dds", // Texture files we dont need in textmode ".phy", // Physics - ".dem" // Demo and log files + ".dem", // Demo and log files + ".vcd", // Scene files + ".ain", // AI node graph + ".lst", // Manifests + ".pcf" // Particle systems }; if (!cFileName || !std::strncmp(cFileName, "materials/console/", 18)) @@ -56,6 +102,10 @@ bool SDK::BlacklistFile(const char* cFileName) if (!std::strcmp(ext_p, ".bsp")) return false; + // NEVER block .nav files - navengine needs it obviosuly lol + if (!std::strcmp(ext_p, ".nav")) + return false; + // Block all particle effects during map load if (!std::strcmp(ext_p, ".pcf")) return true; @@ -76,6 +126,15 @@ bool SDK::BlacklistFile(const char* cFileName) if (std::strstr(cFileName, "ambient")) return true; + // Block models that aren't players or essential gameplay items + if (!std::strcmp(ext_p, ".mdl")) + { + if (std::strstr(cFileName, "player/") || std::strstr(cFileName, "buildables/") || std::strstr(cFileName, "weapons/") || std::strstr(cFileName, "empty.mdl") || std::strstr(cFileName, "error.mdl")) + return false; + + return true; + } + if (!std::strcmp(ext_p, ".vmt")) { // Only allow essential UI materials @@ -96,8 +155,6 @@ bool SDK::BlacklistFile(const char* cFileName) return false; if (!std::strncmp(cFileName, "sound/player/footsteps", 22)) return false; - if (!std::strcmp(ext_p, ".mdl")) - return false; if (!std::strncmp(cFileName, "/decal", 6)) return true; diff --git a/TextmodeTF2/src/Utils/Hooks/Hooks.cpp b/TextmodeTF2/src/Utils/Hooks/Hooks.cpp index 8a3799f..0ca5ee4 100644 --- a/TextmodeTF2/src/Utils/Hooks/Hooks.cpp +++ b/TextmodeTF2/src/Utils/Hooks/Hooks.cpp @@ -1,4 +1,5 @@ #include "Hooks.h" +#include "../../SDK/SDK.h" #include "../Assert/Assert.h" #include "../../Core/Core.h" @@ -19,7 +20,18 @@ bool CHooks::Initialize(const char* sName) } auto pHook = m_mHooks[sName]; + if (!pHook) + { + SDK::Output("Hooks", std::format("Failed to find hook: {}", sName).c_str()); + return false; + } + bool bFail{!reinterpret_cast(pHook->m_pInitFunc)()}; + if (bFail) + { + SDK::Output("Hooks", std::format("Failed to initialize hook (InitFunc): {}", sName).c_str()); + return false; + } bFail = MH_EnableHook(pHook->m_pTarget) != MH_OK; if (bFail) diff --git a/TextmodeTF2/src/Utils/Interfaces/Interfaces.cpp b/TextmodeTF2/src/Utils/Interfaces/Interfaces.cpp index 7428203..ff63b60 100644 --- a/TextmodeTF2/src/Utils/Interfaces/Interfaces.cpp +++ b/TextmodeTF2/src/Utils/Interfaces/Interfaces.cpp @@ -1,4 +1,5 @@ #include "Interfaces.h" +#include "../../SDK/SDK.h" #include "../Memory/Memory.h" #include "../../Core/Core.h" #include "../Assert/Assert.h" @@ -84,12 +85,22 @@ bool CInterfaces::Initialize() Interface->m_pszDLLName = SearchForDLL(Interface->m_pszDLLName); if (Interface->m_nOffset == -1) + { *Interface->m_pPtr = U::Memory.FindInterface(Interface->m_pszDLLName, Interface->m_pszVersion); + if (!*Interface->m_pPtr) + { + SDK::Output("Interfaces", std::format("Failed to find interface: {} in {}", Interface->m_pszVersion, Interface->m_pszDLLName).c_str()); + bFail = true; + continue; + } + SDK::Output("Interfaces", std::format("Successfully found interface: {} in {}", Interface->m_pszVersion, Interface->m_pszDLLName).c_str()); + } else { auto dwDest = U::Memory.FindSignature(Interface->m_pszDLLName, Interface->m_pszVersion); if (!dwDest) { + SDK::Output("Interfaces", std::format("Failed to find signature for interface: {} in {}", Interface->m_pszVersion, Interface->m_pszDLLName).c_str()); U::Core.AppendFailText(std::format("CInterfaces::Initialize() failed to find signature:\n {}\n {}", Interface->m_pszDLLName, Interface->m_pszVersion).c_str()); bFail = true; continue; @@ -100,19 +111,18 @@ bool CInterfaces::Initialize() for (int n = 0; n < Interface->m_nDereferenceCount; n++) { - if (Interface->m_pPtr) + if (*Interface->m_pPtr) *Interface->m_pPtr = *reinterpret_cast(*Interface->m_pPtr); } - } - if (!*Interface->m_pPtr) - { - U::Core.AppendFailText(std::format("CInterfaces::Initialize() failed to initialize:\n {}\n {}", Interface->m_pszDLLName, Interface->m_pszVersion).c_str()); - bFail = true; - continue; + if (!*Interface->m_pPtr) + { + SDK::Output("Interfaces", std::format("Failed to resolve interface address: {} in {}", Interface->m_pszVersion, Interface->m_pszDLLName).c_str()); + bFail = true; + continue; + } + SDK::Output("Interfaces", std::format("Successfully found interface (via signature): {} in {}", Interface->m_pszVersion, Interface->m_pszDLLName).c_str()); } - U::Core.AppendSuccessText("Interfaces", std::format("Successfully initialized: {}, {}", Interface->m_pszDLLName, Interface->m_pszVersion).c_str()); } - return !bFail; } \ No newline at end of file From e39958a38f9d4b8e91f6c6ac0b4e0a009542ceba Mon Sep 17 00:00:00 2001 From: mlemlody Date: Sun, 11 Jan 2026 20:49:44 +0100 Subject: [PATCH 2/6] this todo is uesless --- TextmodeTF2/src/Core/Core.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/TextmodeTF2/src/Core/Core.cpp b/TextmodeTF2/src/Core/Core.cpp index dada0ed..5a7f91f 100644 --- a/TextmodeTF2/src/Core/Core.cpp +++ b/TextmodeTF2/src/Core/Core.cpp @@ -8,8 +8,6 @@ #define LOAD_FAIL -1 #define CHECK(x, sFailMessage) if (x == LOAD_FAIL) {m_bUnload = true; SDK::Output("TextmodeTF2", sFailMessage); return;} -// TODO: null subsystems (Particle, Material, Model partially, Sound and etc.) - void CCore::AppendFailText(const char* sMessage, bool bCritical) { if (!m_bTimeout && !bCritical) From 51a7a97bffb796791ff9c6600f65a0c4de880813 Mon Sep 17 00:00:00 2001 From: mlemlody Date: Mon, 12 Jan 2026 00:13:53 +0100 Subject: [PATCH 3/6] update --- TextmodeTF2/TextmodeTF2.vcxproj | 3 + TextmodeTF2/TextmodeTF2.vcxproj.filters | 2 + TextmodeTF2/src/Core/Core.cpp | 30 ++++++++-- TextmodeTF2/src/Core/Core.h | 3 +- ...rticleSystemMgr_ReadParticleConfigFile.cpp | 10 ++++ .../src/Hooks/IBaseFileSystem_Hooks.cpp | 9 +++ .../Hooks/IMDLCache_ProcessDataIntoCache.cpp | 14 +++++ .../src/Hooks/IMaterialSystem_Hooks.cpp | 27 +++++++++ TextmodeTF2/src/SDK/Definitions/Interfaces.h | 5 +- .../SDK/Definitions/Interfaces/IMDLCache.h | 59 +++++++++++++++++++ TextmodeTF2/src/SDK/Globals.h | 4 ++ TextmodeTF2/src/SDK/SDK.cpp | 13 +++- 12 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 TextmodeTF2/src/Hooks/CParticleSystemMgr_ReadParticleConfigFile.cpp create mode 100644 TextmodeTF2/src/Hooks/IMDLCache_ProcessDataIntoCache.cpp create mode 100644 TextmodeTF2/src/SDK/Definitions/Interfaces/IMDLCache.h diff --git a/TextmodeTF2/TextmodeTF2.vcxproj b/TextmodeTF2/TextmodeTF2.vcxproj index a5e566f..9a3a74d 100644 --- a/TextmodeTF2/TextmodeTF2.vcxproj +++ b/TextmodeTF2/TextmodeTF2.vcxproj @@ -231,7 +231,9 @@ + + @@ -258,6 +260,7 @@ + diff --git a/TextmodeTF2/TextmodeTF2.vcxproj.filters b/TextmodeTF2/TextmodeTF2.vcxproj.filters index 41d360d..af24fa5 100644 --- a/TextmodeTF2/TextmodeTF2.vcxproj.filters +++ b/TextmodeTF2/TextmodeTF2.vcxproj.filters @@ -18,6 +18,7 @@ + @@ -46,6 +47,7 @@ + \ No newline at end of file diff --git a/TextmodeTF2/src/Core/Core.cpp b/TextmodeTF2/src/Core/Core.cpp index 5a7f91f..e9e2971 100644 --- a/TextmodeTF2/src/Core/Core.cpp +++ b/TextmodeTF2/src/Core/Core.cpp @@ -36,7 +36,7 @@ int CCore::LoadFilesystem() "IFileSystem_AsyncReadMultiple", "IFileSystem_OpenEx", "IFileSystem_ReadFileEx", "IFileSystem_AddFilesToFileCache", "IBaseFileSystem_Open", "IBaseFileSystem_Precache", - "IBaseFileSystem_ReadFile" + "IBaseFileSystem_ReadFile", "IBaseFileSystem_FileExists" }; for (auto cHook : vFilesystemHooks) @@ -146,7 +146,7 @@ int CCore::LoadMatSys() { "IMaterialSystem_CreateRenderTargetTexture", "IMaterialSystem_CreateNamedRenderTargetTextureEx", "IMaterialSystem_CreateNamedRenderTargetTexture", "IMaterialSystem_CreateNamedRenderTargetTextureEx2", - "IMaterialSystem_SwapBuffers" + "IMaterialSystem_SwapBuffers", "IMaterialSystem_FindMaterial", "IMaterialSystem_FindTexture" }; for (auto cHook : vMatSystemHooks) @@ -172,18 +172,35 @@ int CCore::LoadParticles() if (!G::CParticleCollection_SimulateAddr) G::CParticleCollection_SimulateAddr = U::Memory.FindSignature("client.dll", "48 8B C4 44 88 40 18 57 41 56 48 81 EC 08 01 00 00"); - if (G::CParticleSystemMgr_DrawRenderCacheAddr && G::CParticleCollection_SimulateAddr) + if (!G::CParticleSystemMgr_ReadParticleConfigFileAddr) + G::CParticleSystemMgr_ReadParticleConfigFileAddr = U::Memory.FindSignature("client.dll", "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 81 EC ?? ?? ?? ?? 80 3A 21 48 8D 7A 01"); + + if (G::CParticleSystemMgr_DrawRenderCacheAddr && G::CParticleCollection_SimulateAddr && G::CParticleSystemMgr_ReadParticleConfigFileAddr) { if (!U::Hooks.Initialize("CParticleSystemMgr_DrawRenderCache")) return LOAD_FAIL; if (!U::Hooks.Initialize("CParticleCollection_Simulate")) return LOAD_FAIL; - return m_bParticlesLoaded = true; + if (!U::Hooks.Initialize("CParticleSystemMgr_ReadParticleConfigFile")) + return LOAD_FAIL; + m_bParticlesLoaded = true; } return LOAD_WAIT; } +int CCore::LoadMDLCache() +{ + G::IMDLCache = reinterpret_cast(U::Memory.FindInterface("datacache.dll", "MDLCache004")); + if (!G::IMDLCache) + return LOAD_WAIT; + + if (!U::Hooks.Initialize("IMDLCache_ProcessDataIntoCache")) + return LOAD_FAIL; + + return m_bMDLCacheLoaded = true; +} + void CCore::Load() { G::CurrentPath = std::filesystem::current_path().string() + "\\TextmodeTF2"; @@ -233,8 +250,11 @@ void CCore::Load() 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") } - while (!m_bFilesystemLoaded || !m_bEngineLoaded || !m_bMatSysLoaded || !m_bClientLoaded || !m_bParticlesLoaded); + while (!m_bFilesystemLoaded || !m_bEngineLoaded || !m_bMatSysLoaded || !m_bClientLoaded || !m_bParticlesLoaded || !m_bMDLCacheLoaded); SDK::Output("TextmodeTF2", std::format("Loaded in {} seconds", SDK::PlatFloatTime()).c_str()); } diff --git a/TextmodeTF2/src/Core/Core.h b/TextmodeTF2/src/Core/Core.h index 215b3ba..7441cee 100644 --- a/TextmodeTF2/src/Core/Core.h +++ b/TextmodeTF2/src/Core/Core.h @@ -17,13 +17,14 @@ 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; + bool m_bFilesystemLoaded = false, m_bEngineLoaded = false, m_bMatSysLoaded = false, m_bClientLoaded = false, m_bParticlesLoaded = false, m_bMDLCacheLoaded = false; int LoadFilesystem(); int LoadEngine(); int LoadMatSys(); int LoadClient(); int LoadParticles(); + int LoadMDLCache(); std::stringstream ssFailStream; }; diff --git a/TextmodeTF2/src/Hooks/CParticleSystemMgr_ReadParticleConfigFile.cpp b/TextmodeTF2/src/Hooks/CParticleSystemMgr_ReadParticleConfigFile.cpp new file mode 100644 index 0000000..387703a --- /dev/null +++ b/TextmodeTF2/src/Hooks/CParticleSystemMgr_ReadParticleConfigFile.cpp @@ -0,0 +1,10 @@ +#include "../SDK/SDK.h" + +MAKE_HOOK(CParticleSystemMgr_ReadParticleConfigFile, G::CParticleSystemMgr_ReadParticleConfigFileAddr, bool, + void* rcx, const char* pFileName, bool bPrecache, bool bDecommitTempMemory) +{ + if (SDK::BlacklistFile(pFileName)) + return true; + + return CALL_ORIGINAL(rcx, pFileName, bPrecache, bDecommitTempMemory); +} diff --git a/TextmodeTF2/src/Hooks/IBaseFileSystem_Hooks.cpp b/TextmodeTF2/src/Hooks/IBaseFileSystem_Hooks.cpp index de68786..a25cab7 100644 --- a/TextmodeTF2/src/Hooks/IBaseFileSystem_Hooks.cpp +++ b/TextmodeTF2/src/Hooks/IBaseFileSystem_Hooks.cpp @@ -24,4 +24,13 @@ MAKE_HOOK(IBaseFileSystem_ReadFile, U::Memory.GetVFunc(reinterpret_cast(G return false; return CALL_ORIGINAL(rcx, pFileName, pPath, buf, nMaxBytes, nStartingByte, pfnAlloc); +} + +MAKE_HOOK(IBaseFileSystem_FileExists, U::Memory.GetVFunc(reinterpret_cast(G::IBaseFileSystemAddr), 10), bool, + void* rcx, const char* pFileName, const char* pPathID) +{ + if (SDK::BlacklistFile(pFileName)) + return false; + + return CALL_ORIGINAL(rcx, pFileName, pPathID); } \ No newline at end of file diff --git a/TextmodeTF2/src/Hooks/IMDLCache_ProcessDataIntoCache.cpp b/TextmodeTF2/src/Hooks/IMDLCache_ProcessDataIntoCache.cpp new file mode 100644 index 0000000..351f554 --- /dev/null +++ b/TextmodeTF2/src/Hooks/IMDLCache_ProcessDataIntoCache.cpp @@ -0,0 +1,14 @@ +#include "../SDK/SDK.h" + +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; + } + + 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 607949e..57c12a8 100644 --- a/TextmodeTF2/src/Hooks/IMaterialSystem_Hooks.cpp +++ b/TextmodeTF2/src/Hooks/IMaterialSystem_Hooks.cpp @@ -6,6 +6,33 @@ MAKE_HOOK(IMaterialSystem_SwapBuffers, U::Memory.GetVFunc(I::MaterialSystem, 40) return; } +MAKE_HOOK(IMaterialSystem_FindMaterial, U::Memory.GetVFunc(I::MaterialSystem, 71), IMaterial*, // 71 + void* rcx, char const* pMaterialName, const char* pTextureGroupName, bool complain, const char* pComplainPrefix) +{ + 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); +} + +MAKE_HOOK(IMaterialSystem_FindTexture, U::Memory.GetVFunc(I::MaterialSystem, 79), ITexture*, // 79 + void* rcx, char const* pTextureName, const char* pTextureGroupName, bool complain, int nAdditionalCreationFlags) +{ + if (SDK::BlacklistFile(pTextureName)) + { + return CALL_ORIGINAL(rcx, "error", pTextureGroupName, false, nAdditionalCreationFlags); + } + + return CALL_ORIGINAL(rcx, pTextureName, pTextureGroupName, complain, nAdditionalCreationFlags); +} + MAKE_HOOK(IMaterialSystem_CreateRenderTargetTexture, U::Memory.GetVFunc(I::MaterialSystem, 84), ITexture*, // 84 void* rcx, int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat format, MaterialRenderTargetDepth_t depth) { diff --git a/TextmodeTF2/src/SDK/Definitions/Interfaces.h b/TextmodeTF2/src/SDK/Definitions/Interfaces.h index fbc91ca..ed27963 100644 --- a/TextmodeTF2/src/SDK/Definitions/Interfaces.h +++ b/TextmodeTF2/src/SDK/Definitions/Interfaces.h @@ -1,4 +1,7 @@ #pragma once #include "../../Utils/Feature/Feature.h" -#include "Interfaces/IMaterialSystem.h" \ No newline at end of file +#include "Interfaces/IMaterialSystem.h" +#include "Interfaces/IMDLCache.h" + +MAKE_INTERFACE_VERSION(IMDLCache, MDLCache, "datacache.dll", "MDLCache004"); \ No newline at end of file diff --git a/TextmodeTF2/src/SDK/Definitions/Interfaces/IMDLCache.h b/TextmodeTF2/src/SDK/Definitions/Interfaces/IMDLCache.h new file mode 100644 index 0000000..7bea4e6 --- /dev/null +++ b/TextmodeTF2/src/SDK/Definitions/Interfaces/IMDLCache.h @@ -0,0 +1,59 @@ +#pragma once +#include "Interface.h" +#include "../Misc/IAppSystem.h" + +typedef unsigned short MDLHandle_t; + +enum MDLCacheDataType_t +{ + MDLCACHE_STUDIOHDR = 0, + MDLCACHE_STUDIOHWDATA, + MDLCACHE_VCOLLIDE, + MDLCACHE_ANIMBLOCK, + MDLCACHE_VIRTUALMODEL, + MDLCACHE_VERTEXES, + MDLCACHE_DECODEDANIMBLOCK, +}; + +class IMDLCacheNotify +{ +public: + virtual void OnDataLoaded(MDLCacheDataType_t type, MDLHandle_t handle) = 0; + virtual void OnDataUnloaded(MDLCacheDataType_t type, MDLHandle_t handle) = 0; +}; + +class IMDLCache : public IAppSystem +{ +public: + virtual void SetCacheNotify(IMDLCacheNotify* pNotify) = 0; + virtual MDLHandle_t FindMDL(const char* pMDLRelativePath) = 0; + virtual int AddRef(MDLHandle_t handle) = 0; + virtual int Release(MDLHandle_t handle) = 0; + virtual int GetRef(MDLHandle_t handle) = 0; + virtual void* GetStudioHdr(MDLHandle_t handle) = 0; + virtual void* GetHardwareData(MDLHandle_t handle) = 0; + virtual void* GetVCollide(MDLHandle_t handle) = 0; + virtual unsigned char* GetAnimBlock(MDLHandle_t handle, int nBlock) = 0; + 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 SetUserData(MDLHandle_t handle, void* pData) = 0; + virtual void* GetUserData(MDLHandle_t handle) = 0; + virtual bool IsErrorModel(MDLHandle_t handle) = 0; + virtual void Flush(int nFlushFlags = 0xFFFFFFFF) = 0; + virtual void Flush(MDLHandle_t handle, int nFlushFlags = 0xFFFFFFFF) = 0; + virtual const char* GetModelName(MDLHandle_t handle) = 0; + virtual void* GetVirtualModelFast(const void* pStudioHdr, MDLHandle_t handle) = 0; + virtual void BeginLock() = 0; + virtual void EndLock() = 0; + virtual int* GetFrameUnlockCounterPtrOLD() = 0; + virtual void FinishPendingLoads() = 0; + virtual void* GetVCollideEx(MDLHandle_t handle, bool synchronousLoad = true) = 0; + virtual bool GetVCollideSize(MDLHandle_t handle, int* pVCollideSize) = 0; + virtual bool GetAsyncLoad(MDLCacheDataType_t type) = 0; + 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; +}; diff --git a/TextmodeTF2/src/SDK/Globals.h b/TextmodeTF2/src/SDK/Globals.h index 39d228d..8d3750a 100644 --- a/TextmodeTF2/src/SDK/Globals.h +++ b/TextmodeTF2/src/SDK/Globals.h @@ -6,6 +6,8 @@ #define TEXTMODE_LOG_FILE "TextmodeLog.log" #define CONSOLE_LOG_FILE "Console.log" +class IMDLCache; + namespace G { inline std::string CurrentPath{}; @@ -27,4 +29,6 @@ namespace G inline uintptr_t CModelRender_DrawModelExecuteAddr{}; inline uintptr_t CDebugOverlay_AddBoxOverlayAddr{}; inline uintptr_t CDebugOverlay_AddLineOverlayAddr{}; + inline uintptr_t CParticleSystemMgr_ReadParticleConfigFileAddr{}; + inline IMDLCache* IMDLCache{}; }; \ No newline at end of file diff --git a/TextmodeTF2/src/SDK/SDK.cpp b/TextmodeTF2/src/SDK/SDK.cpp index 38ef523..2fc5c7e 100644 --- a/TextmodeTF2/src/SDK/SDK.cpp +++ b/TextmodeTF2/src/SDK/SDK.cpp @@ -78,7 +78,7 @@ bool SDK::BlacklistFile(const char* cFileName) { const static char* blacklist[] = { ".ani", ".wav", ".mp3", ".vvd", ".vtx", ".vtf", ".vfe", ".cache", - ".jpg", ".png", ".tga", ".dds", // Texture files we dont need in textmode + ".jpg", ".png", ".tga", ".dds", ".vmt", // Texture and material files ".phy", // Physics ".dem", // Demo and log files ".vcd", // Scene files @@ -87,9 +87,18 @@ bool SDK::BlacklistFile(const char* cFileName) ".pcf" // Particle systems }; - if (!cFileName || !std::strncmp(cFileName, "materials/console/", 18)) + if (!cFileName) return false; + if (!std::strncmp(cFileName, "materials/console/", 18)) + return false; + + if (!std::strncmp(cFileName, "debug/", 6)) + return false; + + if (!std::strncmp(cFileName, "sprites/", 8)) + return true; + std::size_t len = std::strlen(cFileName); if (len <= 3) return false; From b354e3c9e1b84acb283657f3e88c5802f682bff5 Mon Sep 17 00:00:00 2001 From: mlemlody Date: Tue, 13 Jan 2026 19:11:48 +0100 Subject: [PATCH 4/6] crashfix --- TextmodeTF2/src/BytePatches/BytePatches.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/TextmodeTF2/src/BytePatches/BytePatches.h b/TextmodeTF2/src/BytePatches/BytePatches.h index c4e8daf..05be3bd 100644 --- a/TextmodeTF2/src/BytePatches/BytePatches.h +++ b/TextmodeTF2/src/BytePatches/BytePatches.h @@ -131,6 +131,11 @@ class CBytePatches // CBaseHudChat::ChatPrintf BytePatch("client.dll", "4C 89 4C 24 ? 48 89 4C 24 ? 55 53", 0x0, "C3"), + }}, + {"datacache", + { + // CDataCacheSection::Unlock (sub_18000F280) + 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"), }} }; }; From 51870d402bfbaa2aaf52fea09cbbf38ce8361dd4 Mon Sep 17 00:00:00 2001 From: mlemlody Date: Wed, 14 Jan 2026 16:41:15 +0100 Subject: [PATCH 5/6] Update BytePatches.h --- TextmodeTF2/src/BytePatches/BytePatches.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/TextmodeTF2/src/BytePatches/BytePatches.h b/TextmodeTF2/src/BytePatches/BytePatches.h index 05be3bd..2459a92 100644 --- a/TextmodeTF2/src/BytePatches/BytePatches.h +++ b/TextmodeTF2/src/BytePatches/BytePatches.h @@ -43,33 +43,33 @@ class CBytePatches // evil cathook's plan b implementation - // Mod_LoadLighting (sub_180102C50) + // 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"), - // Sprite_LoadModel (sub_180105390) + // 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"), - // Mod_LoadWorldlights (sub_1801025E0) + // 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"), - // Mod_LoadTexinfo (sub_180103E30) + // Mod_LoadTexinfo // forces mat_loadtextures 0 logic to skip material loading BytePatch("engine.dll", "0F 84 ? ? ? ? 48 63 7E 44", 0x0, "90 E9"), }}, {"materialsystem", { - // CMaterialSystem::Init (sub_180017050) + // 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"), - // CMaterialSystem::BeginFrame (sub_180015630) + // CMaterialSystem::BeginFrame // bye bye frame rendering! BytePatch("materialsystem.dll", "48 8B 0D ? ? ? ? 48 8B 01 48 FF A0 ? ? ? ? CC", 0x0, "C3"), - // CMaterialSystem::FindMaterial (sub_180017310) + // 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"), }}, @@ -134,7 +134,7 @@ class CBytePatches }}, {"datacache", { - // CDataCacheSection::Unlock (sub_18000F280) + // 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"), }} }; From 9e6fcf06f832796a302abbb2215be591c53738d6 Mon Sep 17 00:00:00 2001 From: mlemlody Date: Thu, 15 Jan 2026 15:46:38 +0100 Subject: [PATCH 6/6] Update BytePatches.h --- TextmodeTF2/src/BytePatches/BytePatches.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/TextmodeTF2/src/BytePatches/BytePatches.h b/TextmodeTF2/src/BytePatches/BytePatches.h index 2459a92..ad9b49e 100644 --- a/TextmodeTF2/src/BytePatches/BytePatches.h +++ b/TextmodeTF2/src/BytePatches/BytePatches.h @@ -131,6 +131,12 @@ class CBytePatches // CBaseHudChat::ChatPrintf BytePatch("client.dll", "4C 89 4C 24 ? 48 89 4C 24 ? 55 53", 0x0, "C3"), + + // Fixes crash (CEconItemView::GetItemDefinitionIndex) + BytePatch("client.dll", "48 8B 41 08 48 85 C0 75 0A 48 8B 01 8B 80 BC 00 00 00 C3 8B 40 20 C3", 0x0, "48 8B 41 08 48 85 C0 75 0F 48 8B 01 48 85 C0 74 0B 8B 80 BC 00 00 00 C3 8B 40 20 C3 31 C0 C3"), + + // 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"), }}, {"datacache", {