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