diff --git a/docs/cvars.md b/docs/cvars.md index 02672cfd..ccc4d58a 100644 --- a/docs/cvars.md +++ b/docs/cvars.md @@ -423,8 +423,8 @@ |sar_portalcolor_mp2_1|255 179 31|Portal color for P-Body (orange)'s left portal.| |sar_portalcolor_mp2_2|57 2 2|Portal color for P-Body (orange)'s right portal.| |sar_portalcolor_rainbow|0|Rainbow portals!| -|sar_portalcolor_sp_1|64 160 255|Portal color for Chell's left portal.| -|sar_portalcolor_sp_2|255 160 32|Portal color for Chell's right portal.| +|sar_portalcolor_sp_1|64 160 255|Portal color for Chell's left portal. r_portal_fastpath 0 required.| +|sar_portalcolor_sp_2|255 160 32|Portal color for Chell's right portal. r_portal_fastpath 0 required.| |sar_portalgun_hud|0|Enables the portalgun HUD.| |sar_portalgun_hud_x|5|The x position of the portalgun HUD.| |sar_portalgun_hud_y|5|The y position of the portalgun HUD.| diff --git a/src/Modules/Client.cpp b/src/Modules/Client.cpp index e60f6176..ad93566e 100644 --- a/src/Modules/Client.cpp +++ b/src/Modules/Client.cpp @@ -11,9 +11,9 @@ #include "Features/FovChanger.hpp" #include "Features/GroundFramesCounter.hpp" #include "Features/Hud/InputHud.hpp" +#include "Features/Hud/RhythmGame.hpp" #include "Features/Hud/ScrollSpeed.hpp" #include "Features/Hud/StrafeHud.hpp" -#include "Features/Hud/RhythmGame.hpp" #include "Features/Hud/StrafeQuality.hpp" #include "Features/NetMessage.hpp" #include "Features/OverlayRender.hpp" @@ -84,8 +84,8 @@ Variable sar_patch_minor_angle_decay("sar_patch_minor_angle_decay", "0", "Patche Variable sar_unlocked_chapters("sar_unlocked_chapters", "-1", "Max unlocked chapter.\n"); Variable sar_portalcolor_enable("sar_portalcolor_enable", "0", "Enable custom portal colors.\n"); -Variable sar_portalcolor_sp_1("sar_portalcolor_sp_1", "64 160 255", "Portal color for Chell's left portal.\n"); -Variable sar_portalcolor_sp_2("sar_portalcolor_sp_2", "255 160 32", "Portal color for Chell's right portal.\n"); +Variable sar_portalcolor_sp_1("sar_portalcolor_sp_1", "64 160 255", "Portal color for Chell's left portal. r_portal_fastpath 0 required.\n"); +Variable sar_portalcolor_sp_2("sar_portalcolor_sp_2", "255 160 32", "Portal color for Chell's right portal. r_portal_fastpath 0 required.\n"); Variable sar_portalcolor_mp1_1("sar_portalcolor_mp1_1", "31 127 210", "Portal color for Atlas (blue)'s left portal.\n"); Variable sar_portalcolor_mp1_2("sar_portalcolor_mp1_2", "19 0 210", "Portal color for Atlas (blue)'s right portal.\n"); Variable sar_portalcolor_mp2_1("sar_portalcolor_mp2_1", "255 179 31", "Portal color for P-Body (orange)'s left portal.\n"); @@ -124,6 +124,7 @@ REDECL(Client::OnCommand); REDECL(Client::ApplyMouse_Mid); REDECL(Client::ApplyMouse_Mid_Continue); #endif +REDECL(Client::DrawPortal); REDECL(Client::GetChapterProgress); @@ -330,12 +331,44 @@ DETOUR_COMMAND(Client::openleaderboard) { } } +Memory::Patch *g_drawPortalPatch; +Memory::Patch *g_drawPortalGhostPatch; +// C_Prop_Portal::DrawPortal +extern Hook g_DrawPortalHook; +DETOUR(Client::DrawPortal, void *pRenderContext) { + if (sar_portalcolor_enable.GetBool()) { + g_drawPortalPatch->Execute(); + } else { + g_drawPortalPatch->Restore(); + } + g_DrawPortalHook.Disable(); + auto ret = Client::DrawPortal(thisptr, pRenderContext); + g_DrawPortalHook.Enable(); + return ret; +} +Hook g_DrawPortalHook(&Client::DrawPortal_Hook); + +static void (*g_DrawPortalGhost)(void *pRenderContext); + +// C_Prop_Portal::DrawPortalGhostLocations +extern Hook g_DrawPortalGhostHook; +static void DrawPortalGhost_Hook(void *pRenderContext) { + if (sar_portalcolor_enable.GetBool()) { + g_drawPortalGhostPatch->Execute(); + } else { + g_drawPortalGhostPatch->Restore(); + } + g_DrawPortalGhostHook.Disable(); + g_DrawPortalGhost(pRenderContext); + g_DrawPortalGhostHook.Enable(); + return; +} +Hook g_DrawPortalGhostHook(&DrawPortalGhost_Hook); + + static SourceColor (*UTIL_Portal_Color)(int iPortal, int iTeamNumber); extern Hook UTIL_Portal_Color_Hook; static SourceColor UTIL_Portal_Color_Detour(int iPortal, int iTeamNumber) { - // FIXME: SP portal rendering does not use this but rather the - // texture's color itself. This does however work on the color - // of the SP *crosshair* and particles. UTIL_Portal_Color_Hook.Disable(); SourceColor ret = UTIL_Portal_Color(iPortal, iTeamNumber); UTIL_Portal_Color_Hook.Enable(); @@ -992,13 +1025,45 @@ bool Client::Init() { #ifdef _WIN32 auto ApplyMouse_Mid_addr = (uintptr_t)(Client::ApplyMouse) + Offsets::ApplyMouse_Mid; - g_ApplyMouseMidHook.SetFunc(ApplyMouse_Mid_addr); - g_ApplyMouseMidHook.Disable(); + g_ApplyMouseMidHook.SetFunc(ApplyMouse_Mid_addr, false); Client::ApplyMouse_Mid_Continue = ApplyMouse_Mid_addr + 0x5; #endif MatrixBuildRotationAboutAxis = (decltype(MatrixBuildRotationAboutAxis))Memory::Scan(client->Name(), Offsets::MatrixBuildRotationAboutAxis); - MatrixBuildRotationAboutAxisHook.SetFunc(MatrixBuildRotationAboutAxis); - MatrixBuildRotationAboutAxisHook.Disable(); // only during ApplyMouse + MatrixBuildRotationAboutAxisHook.SetFunc(MatrixBuildRotationAboutAxis, false); // only during ApplyMouse + + auto drawPortalSpBranch = Memory::Scan(client->Name(), Offsets::DrawPortalSpBranch); + auto drawPortalGhostSpBranch = Memory::Scan(client->Name(), Offsets::DrawPortalGhostSpBranch); + + Client::DrawPortal = (decltype(Client::DrawPortal))Memory::Scan(client->Name(), Offsets::DrawPortal); + g_DrawPortalGhost = (decltype(g_DrawPortalGhost))Memory::Scan(client->Name(), Offsets::DrawPortalGhost); + + g_DrawPortalHook.SetFunc(Client::DrawPortal); + g_DrawPortalGhostHook.SetFunc(g_DrawPortalGhost); + + g_drawPortalPatch = new Memory::Patch(); + g_drawPortalGhostPatch = new Memory::Patch(); + + unsigned char drawPortalGhostByte = 0x80; + if (drawPortalSpBranch && drawPortalGhostSpBranch) { +#ifndef _WIN32 + unsigned char drawPortalBytes[5]; + + *(int32_t *)(drawPortalBytes + 1) = *(int32_t *)(drawPortalSpBranch + 2) + Offsets::DrawPortalSpBranchOff; + drawPortalBytes[0] = 0x81; + + g_drawPortalPatch->Execute(drawPortalSpBranch + 1, drawPortalBytes, 5); + g_drawPortalGhostPatch->Execute(drawPortalGhostSpBranch + 1, &drawPortalGhostByte, 1); + +#else + unsigned char drawPortalBytes[2]; + + drawPortalBytes[0] = 0xEB; + drawPortalBytes[1] = Offsets::DrawPortalSpBranchOff; + + g_drawPortalPatch->Execute(drawPortalSpBranch, drawPortalBytes, 2); + g_drawPortalGhostPatch->Execute(drawPortalGhostSpBranch + 1, &drawPortalGhostByte, 1); +#endif + } in_forceuser = Variable("in_forceuser"); if (!!in_forceuser && this->g_Input) { @@ -1057,8 +1122,8 @@ bool Client::Init() { g_AddShadowToReceiverHook.SetFunc(Client::AddShadowToReceiver); - UTIL_Portal_Color = (decltype (UTIL_Portal_Color))Memory::Scan(client->Name(), Offsets::UTIL_Portal_Color); - UTIL_Portal_Color_Particles = (decltype (UTIL_Portal_Color_Particles))Memory::Scan(client->Name(), Offsets::UTIL_Portal_Color_Particles); + UTIL_Portal_Color = (decltype(UTIL_Portal_Color))Memory::Scan(client->Name(), Offsets::UTIL_Portal_Color); + UTIL_Portal_Color_Particles = (decltype(UTIL_Portal_Color_Particles))Memory::Scan(client->Name(), Offsets::UTIL_Portal_Color_Particles); UTIL_Portal_Color_Hook.SetFunc(UTIL_Portal_Color); UTIL_Portal_Color_Particles_Hook.SetFunc(UTIL_Portal_Color_Particles); diff --git a/src/Modules/Client.hpp b/src/Modules/Client.hpp index c40838a3..4effe3bf 100644 --- a/src/Modules/Client.hpp +++ b/src/Modules/Client.hpp @@ -167,6 +167,9 @@ class Client : public Module { DECL_DETOUR_MID_MH(ApplyMouse_Mid); #endif + // C_Prop_Portal::DrawPortal + DECL_DETOUR(DrawPortal, void *pRenderContext); + bool Init() override; void Shutdown() override; const char *Name() override { diff --git a/src/Offsets/INFRA 6905.hpp b/src/Offsets/INFRA 6905.hpp index 315b1e78..138203a0 100644 --- a/src/Offsets/INFRA 6905.hpp +++ b/src/Offsets/INFRA 6905.hpp @@ -95,6 +95,7 @@ SIGSCAN_WINDOWS(SND_RecordBuffer, "55 8B EC 80 3D ? ? ? ? 00 56") // Client SIGSCAN_WINDOWS(DrawTranslucentRenderables, "55 8B EC 81 EC 80 00 00 00 53 56 8B F1") +SIGSCAN_WINDOWS(DrawPortalGhost, "") SIGSCAN_WINDOWS(DrawOpaqueRenderables, "55 8B EC 83 EC 54 A1 ? ? ? ? 83 7D ? 00") SIGSCAN_WINDOWS(GetHudSig, "55 8B EC 8B 45 ? 83 F8 FF 75 ? 8B 0D ? ? ? ? 8B 01 8B 90 ? ? ? ? FF D2 69 C0 84 00 00 00") // usage of FindElement -> probably previous function call SIGSCAN_WINDOWS(FindElementSig, "55 8B EC 53 8B 5D ? 56 57 8B F1 33 FF") // "[%d] Could not find Hud Element: %s\n" xref diff --git a/src/Offsets/Portal 2 5723.hpp b/src/Offsets/Portal 2 5723.hpp index 04b33bc6..15c538af 100644 --- a/src/Offsets/Portal 2 5723.hpp +++ b/src/Offsets/Portal 2 5723.hpp @@ -19,5 +19,13 @@ OFFSET_LINUX(snd_linear_count, 33) OFFSET_LINUX(snd_p, 72) OFFSET_LINUX(snd_vol, 80) +// Pathmatch SIGSCAN_LINUX(PathMatch, "55 89 E5 57 56 53 83 EC ? 0F B6 45 ? 80 3D") + +// Client +SIGSCAN_LINUX(DrawPortal, "55 89 E5 83 EC 58 A1 ? ? ? ? 89 5D ? 89 75 ? 8B 5D ? 89 7D ? 8B 75 ? 8B 10") +SIGSCAN_LINUX(DrawPortalSpBranch, "0F 85 ? ? ? ? 0F B6 83 ? ? ? ? 8B 3C 85 ? ? ? ? A1 ? ? ? ? 89 04 24 E8 ? ? ? ? 84 C0 74") +OFFSET_LINUX(DrawPortalSpBranchOff, 0x15) +SIGSCAN_LINUX(DrawPortalGhost, "55 89 E5 57 56 53 83 EC 5C A1 ? ? ? ? 8B 40") +SIGSCAN_LINUX(DrawPortalGhostSpBranch, "0F 84 ? ? ? ? FF 90 ? ? ? ? 80 BB ? ? ? ? 01") SIGSCAN_LINUX(GetChapterProgress, "55 89 E5 57 56 53 83 EC 2C 8B 7D 08 E8 ? ? ? ? 8B 10 C7") diff --git a/src/Offsets/Portal 2 8151.hpp b/src/Offsets/Portal 2 8151.hpp index 7bbe5af8..007b16cb 100644 --- a/src/Offsets/Portal 2 8151.hpp +++ b/src/Offsets/Portal 2 8151.hpp @@ -54,6 +54,11 @@ SIGSCAN_LINUX(SND_RecordBuffer, "55 89 E5 57 56 53 83 EC 3C 65 A1 ? ? ? ? 89 45 // Client SIGSCAN_LINUX(MatrixBuildRotationAboutAxis, "55 89 E5 56 53 8D 45 ? 8D 55 ? 83 EC 20") SIGSCAN_LINUX(DrawTranslucentRenderables, "55 89 E5 57 56 53 81 EC DC 00 00 00 8B 45 08 8B 5D 0C 89 C7 89 45 84 8B 45 10 89 85 4C FF FF FF") +SIGSCAN_LINUX(DrawPortal, "55 89 E5 57 56 53 83 EC 3C A1 ? ? ? ? 8B 5D ? 8B 10 89 04 24 FF 52 ? A8 02") +SIGSCAN_LINUX(DrawPortalSpBranch, "0F 85 ? ? ? ? 0F B6 83 ? ? ? ? 8B 34 85") +OFFSET_LINUX(DrawPortalSpBranchOff, 0x15) +SIGSCAN_LINUX(DrawPortalGhost, "A1 ? ? ? ? 8B 40 ? 85 C0 74 ? 55 89 E5 57 56 53 83 EC 4C") +SIGSCAN_LINUX(DrawPortalGhostSpBranch, "0F 84 ? ? ? ? 8B 03 89 1C 24 FF 90 ? ? ? ? 80 BB ? ? ? ? 01") SIGSCAN_LINUX(DrawOpaqueRenderables, "55 89 E5 57 56 53 81 EC 8C 00 00 00 8B 45 0C 8B 5D 08 89 45 8C 8B 45 14 89 45 90 65 A1 14 00 00 00") SIGSCAN_LINUX(AddShadowToReceiver, "55 89 E5 57 56 53 83 EC ? 8B 45 ? 8B 4D ? 8B 7D ? 89 45 ? 0F B7 C0") SIGSCAN_LINUX(UTIL_Portal_Color, "55 89 E5 56 53 83 EC 10 8B 75 ? 8B 5D ? 85 F6 0F 84") diff --git a/src/Offsets/Portal 2 8491.hpp b/src/Offsets/Portal 2 8491.hpp index 592fcdb1..c4dfa134 100644 --- a/src/Offsets/Portal 2 8491.hpp +++ b/src/Offsets/Portal 2 8491.hpp @@ -394,6 +394,15 @@ SIGSCAN_DEFAULT(MatrixBuildRotationAboutAxis, "55 8B EC 51 F3 0F 10 45 ? 0F 5A C "56 66 0F EF C0 53 83 EC 14 8B 5C 24 ? 8D 44 24") SIGSCAN_DEFAULT(DrawTranslucentRenderables, "55 8B EC 81 EC 80 00 00 00 53 56 8B F1 8B 0D ? ? ? ? 8B 01 8B 90 C4 01 00 00 57 89 75 F0 FF D2 8B F8", "55 89 E5 57 56 53 81 EC B8 00 00 00 8B 45 10 8B 5D 0C 89 85 60 FF FF FF 88 45 A7 A1 ? ? ? ?") +SIGSCAN_DEFAULT(DrawPortal, "55 8B EC 83 EC 14 53 8B D9 8B 0D ? ? ? ? 8B 01", + "55 57 56 53 83 EC 2C A1 ? ? ? ? 8B 5C 24 ? 8B 74 24 ? 8B 10") // "$PortalColorGradientLight" xref[0] -> C_Prop_Portal::DrawPortal +SIGSCAN_DEFAULT(DrawPortalSpBranch, "8B 15 ? ? ? ? 33 C0 32 C9", + "0F 85 ? ? ? ? 0F B6 83 ? ? ? ? 8B 2C 85") +OFFSET_DEFAULT(DrawPortalSpBranchOff, -14, 0x19) +SIGSCAN_DEFAULT(DrawPortalGhost, "55 8B EC A1 ? ? ? ? 83 EC 24 83 78 ? ? 0F 84 1E 02 00 00 A1 ? ? ? ?", + "A1 ? ? ? ? 8B 40 ? 85 C0 0F 84 ? ? ? ? 55 57") // "Portal Ghosts" xref[1] -> next function call has sig (int *) -> C_Prop_Portal::DrawPortalGhostLocations +SIGSCAN_DEFAULT(DrawPortalGhostSpBranch, "0F 84 ? ? ? ? 8B 90 ? ? ? ? FF D2 50 33 C0 38 86 ? ? ? ? 8D 4D ? 0F 95 C0", + "0F 84 ? ? ? ? 8B 03 83 EC 0C 53 FF 90 ? ? ? ? 83 C4 10 80 BB ? ? ? ? 01") SIGSCAN_DEFAULT(DrawOpaqueRenderables, "55 8B EC 83 EC 54 83 7D 0C 00 A1 ? ? ? ? 53 56 0F 9F 45 EC 83 78 30 00 57 8B F1 0F 84 BA 03 00 00", "55 89 E5 57 56 53 83 EC 7C A1 ? ? ? ? 8B 5D 08 89 45 90 85 C0 0F 85 34 04 00 00 A1 ? ? ? ? 8B 40 30 85 C0") SIGSCAN_DEFAULT(MsgPreSkipToNextLevel, "57 8B F9 E8 ? ? ? ? 8B C8 E8 ? ? ? ? 0B C2", @@ -403,9 +412,9 @@ SIGSCAN_DEFAULT(CalcViewModelLag, "53 8B DC 83 EC 08 83 E4 F0 83 C4 04 55 8B 6B SIGSCAN_DEFAULT(AddShadowToReceiver, "55 8B EC 51 53 56 57 0F B7 7D 08", "55 89 E5 57 56 53 83 EC 44 8B 45 0C 8B 5D 08 8B 55 14 8B 75 10") SIGSCAN_DEFAULT(UTIL_Portal_Color, "55 8B EC 56 8B 75 ? 85 F6 0F 84 ? ? ? ? 0F 8E", - "56 53 83 EC 04 8B 44 24 ? 8B 74 24 ? 85 C0 74 ? 8D 58") + "56 53 83 EC 04 8B 44 24 ? 8B 74 24 ? 85 C0 74 ? 8D 58") SIGSCAN_DEFAULT(UTIL_Portal_Color_Particles, "55 8B EC 51 8B 0D ? ? ? ? 8B 01 8B 90 ? ? ? ? FF D2 84 C0", - "53 83 EC 14 A1 ? ? ? ? 8B 5C 24 ? 8B 10 50 FF 92 ? ? ? ? 83 C4 10 84 C0 75") + "53 83 EC 14 A1 ? ? ? ? 8B 5C 24 ? 8B 10 50 FF 92 ? ? ? ? 83 C4 10 84 C0 75") SIGSCAN_DEFAULT(GetNumChapters, "55 8B EC 80 7D 08 00 57 74 0C", "55 89 E5 56 80 7D") SIGSCAN_DEFAULT(CPortalLeaderboardPanel_OnThink, "55 8B EC A1 ? ? ? ? 81 EC ? ? ? ? 53 56 32 DB", diff --git a/src/Utils/Memory.cpp b/src/Utils/Memory.cpp index 12e0c549..afc8ddcd 100644 --- a/src/Utils/Memory.cpp +++ b/src/Utils/Memory.cpp @@ -231,19 +231,49 @@ std::vector> Memory::MultiScan(const char *moduleName, co return results; } -#ifdef _WIN32 Memory::Patch::~Patch() { if (this->original) { this->Restore(); - delete this->original; + delete[] this->original; this->original = nullptr; } + if (this->patch) { + delete[] this->patch; + this->patch = nullptr; + } + this->isPatched = false; } +bool Memory::Patch::Execute() { + if (this->isPatched) return true; // already executed + unsigned char *tmpPatch = new unsigned char[this->size]; + // We create another patch, because this->patch is gonna be deleted + memcpy(tmpPatch, this->patch, this->size); + auto ret = this->Execute(this->location, tmpPatch, this->size); + delete[] tmpPatch; + return ret; +} + bool Memory::Patch::Execute(uintptr_t location, unsigned char *bytes, size_t size) { + if (this->isPatched) return true; // already executed this->location = location; this->size = size; + if (this->original) { + delete[] this->original; + this->original = nullptr; + } this->original = new unsigned char[this->size]; + if (!bytes) { + return false; + } + if (this->patch) { + delete[] this->patch; + this->patch = nullptr; + } + this->patch = new unsigned char[this->size]; + memcpy(this->patch, bytes, size); + +#ifdef _WIN32 for (size_t i = 0; i < this->size; ++i) { if (!ReadProcessMemory(GetCurrentProcess(), reinterpret_cast(this->location + i), &this->original[i], 1, 0)) { return false; @@ -255,17 +285,38 @@ bool Memory::Patch::Execute(uintptr_t location, unsigned char *bytes, size_t siz return false; } } +#else + Memory::UnProtect(reinterpret_cast(this->location), this->size); + for (size_t i = 0; i < this->size; ++i) { + this->original[i] = *(uint8_t *)(this->location + i); + *(uint8_t *)(this->location + i) = bytes[i]; + } +#endif + this->isPatched = true; return true; } bool Memory::Patch::Restore() { - if (this->location && this->original) { - for (size_t i = 0; i < this->size; ++i) { - if (!WriteProcessMemory(GetCurrentProcess(), reinterpret_cast(this->location + i), &this->original[i], 1, 0)) { - return false; - } + if (!this->location || !this->original) { + return false; + } + if (!this->isPatched) return true; // already restored +#ifdef _WIN32 + for (size_t i = 0; i < this->size; ++i) { + if (!WriteProcessMemory(GetCurrentProcess(), reinterpret_cast(this->location + i), &this->original[i], 1, 0)) { + return false; } - return true; } - return false; -} +#else + // Should be already unprotected, but just in case + Memory::UnProtect(reinterpret_cast(this->location), this->size); + for (size_t i = 0; i < this->size; ++i) { + *(uint8_t *)(this->location + i) = this->original[i]; + } #endif + this->isPatched = false; + return true; +} + +bool Memory::Patch::IsPatched() { + return this->isPatched; +} diff --git a/src/Utils/Memory.hpp b/src/Utils/Memory.hpp index b950d60c..b4c48471 100644 --- a/src/Utils/Memory.hpp +++ b/src/Utils/Memory.hpp @@ -33,23 +33,25 @@ namespace Memory { uintptr_t Scan(const char *moduleName, const char *pattern, int offset = 0); std::vector MultiScan(const char *moduleName, const char *pattern, int offset = 0); -#ifdef _WIN32 class Patch { private: uintptr_t location; unsigned char *original; + unsigned char *patch; size_t size; + bool isPatched; public: ~Patch(); + bool Execute(); bool Execute(uintptr_t location, unsigned char *bytes, size_t size); template bool Execute(uintptr_t location, unsigned char (&bytes)[size]) { return Execute(location, bytes, size); } bool Restore(); + bool IsPatched(); }; -#endif struct Pattern { const char *signature;