diff --git a/TextmodeTF2/TextmodeTF2.vcxproj b/TextmodeTF2/TextmodeTF2.vcxproj
index 507fd80..9a3a74d 100644
--- a/TextmodeTF2/TextmodeTF2.vcxproj
+++ b/TextmodeTF2/TextmodeTF2.vcxproj
@@ -1,4 +1,4 @@
-
+
@@ -226,11 +226,22 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -249,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/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..ad9b49e 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
+ // 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
+ // 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
+ // 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
+ // forces mat_loadtextures 0 logic to skip material loading
+ BytePatch("engine.dll", "0F 84 ? ? ? ? 48 63 7E 44", 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"),
+
+ // CMaterialSystem::BeginFrame
+ // bye bye frame rendering!
+ BytePatch("materialsystem.dll", "48 8B 0D ? ? ? ? 48 8B 01 48 FF A0 ? ? ? ? CC", 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",
{
@@ -99,6 +131,17 @@ 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",
+ {
+ // 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"),
}}
};
};
diff --git a/TextmodeTF2/src/Core/Core.cpp b/TextmodeTF2/src/Core/Core.cpp
index 81e04c2..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)
@@ -93,12 +93,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;
@@ -115,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)
@@ -133,9 +164,47 @@ 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_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;
+ 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";
+ SDK::Output("Core", "Initializing logging...");
char* cBotID = nullptr;
if (_dupenv_s(&cBotID, nullptr, "BOTID") == 0 && cBotID)
{
@@ -178,8 +247,14 @@ 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")
+
+ int iMDLCache = m_bMDLCacheLoaded ? 1 : LoadMDLCache();
+ CHECK(iMDLCache, "Failed to load MDL cache")
}
- while (!m_bFilesystemLoaded || !m_bEngineLoaded || !m_bMatSysLoaded || !m_bClientLoaded);
+ 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 14aaeb9..7441cee 100644
--- a/TextmodeTF2/src/Core/Core.h
+++ b/TextmodeTF2/src/Core/Core.h
@@ -17,12 +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;
+ 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/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/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/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/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/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/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 ef95714..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{};
@@ -18,4 +20,15 @@ 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{};
+ 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 9b756c9..2fc5c7e 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 (...) {}
}
@@ -36,14 +78,27 @@ 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
+ ".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))
+ 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;
@@ -56,6 +111,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 +135,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 +164,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