diff --git a/README.md b/README.md index 12090495..2713726a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/NeKzor/SourceAutoRecord.svg?branch=master)](https://travis-ci.org/NeKzor/SourceAutoRecord) +![Build Status](https://github.com/NeKzor/SourceAutoRecord/workflows/CI/badge.svg) [![Build Version](https://img.shields.io/badge/version-v1.11-brightgreen.svg)](https://github.com/NeKzor/SourceAutoRecord/projects/3) [![Release Status](https://img.shields.io/github/release/NeKzor/SourceAutoRecord/all.svg)](https://github.com/NeKzor/SourceAutoRecord/releases) diff --git a/SourceAutoRecord.sln b/SourceAutoRecord.sln index 40905ac7..b42e50e4 100644 --- a/SourceAutoRecord.sln +++ b/SourceAutoRecord.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2010 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28407.52 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SourceAutoRecord", "src\SourceAutoRecord.vcxproj", "{3F6459A9-566E-4CAC-A412-C03FF51D67E9}" EndProject @@ -10,7 +10,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .clang-format = .clang-format .gitattributes = .gitattributes .gitignore = .gitignore - .travis.yml = .travis.yml _config.yml = _config.yml copy.bat = copy.bat cvars.js = cvars.js @@ -40,6 +39,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "images", "images", "{B82DAA doc\images\unable_to_load_plugin.png = doc\images\unable_to_load_plugin.png EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{B5E886E6-FC59-47F9-9964-13A49C0C8E5A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{B8C7B3B0-4D30-4D3C-A7DC-9EF33EDBAF22}" + ProjectSection(SolutionItems) = preProject + .github\workflows\CD.yml = .github\workflows\CD.yml + .github\workflows\CI.yml = .github\workflows\CI.yml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -52,8 +59,8 @@ Global GlobalSection(ProjectConfigurationPlatforms) = postSolution {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Debug|Any CPU.ActiveCfg = Debug|Win32 {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Debug|x64.ActiveCfg = Debug|Win32 - {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Debug|x86.ActiveCfg = Release|Win32 - {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Debug|x86.Build.0 = Release|Win32 + {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Debug|x86.ActiveCfg = Debug|Win32 + {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Debug|x86.Build.0 = Debug|Win32 {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Release|Any CPU.ActiveCfg = Release|Win32 {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Release|x64.ActiveCfg = Release|Win32 {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Release|x86.ActiveCfg = Release|Win32 @@ -65,6 +72,8 @@ Global GlobalSection(NestedProjects) = preSolution {2234E52A-D21C-4984-B830-0D1EBC6842C5} = {4990948C-3306-40BA-9EAD-594A5520043F} {B82DAA33-1051-496B-A05A-58BB70E8BC02} = {2234E52A-D21C-4984-B830-0D1EBC6842C5} + {B5E886E6-FC59-47F9-9964-13A49C0C8E5A} = {4990948C-3306-40BA-9EAD-594A5520043F} + {B8C7B3B0-4D30-4D3C-A7DC-9EF33EDBAF22} = {B5E886E6-FC59-47F9-9964-13A49C0C8E5A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FE1A6506-7258-47FF-839A-FF441AAA310C} diff --git a/SourceAutoRecordv16.sln b/SourceAutoRecordv16.sln deleted file mode 100644 index b42e50e4..00000000 --- a/SourceAutoRecordv16.sln +++ /dev/null @@ -1,81 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28407.52 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SourceAutoRecord", "src\SourceAutoRecord.vcxproj", "{3F6459A9-566E-4CAC-A412-C03FF51D67E9}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4990948C-3306-40BA-9EAD-594A5520043F}" - ProjectSection(SolutionItems) = preProject - .clang-format = .clang-format - .gitattributes = .gitattributes - .gitignore = .gitignore - _config.yml = _config.yml - copy.bat = copy.bat - cvars.js = cvars.js - makefile = makefile - README.md = README.md - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{2234E52A-D21C-4984-B830-0D1EBC6842C5}" - ProjectSection(SolutionItems) = preProject - doc\contributing.md = doc\contributing.md - doc\cvars.md = doc\cvars.md - doc\issue.md = doc\issue.md - doc\mapping.md = doc\mapping.md - doc\maps.md = doc\maps.md - doc\standard.md = doc\standard.md - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "images", "images", "{B82DAA33-1051-496B-A05A-58BB70E8BC02}" - ProjectSection(SolutionItems) = preProject - doc\images\cp1.png = doc\images\cp1.png - doc\images\cpstart.png = doc\images\cpstart.png - doc\images\failed_to_load.png = doc\images\failed_to_load.png - doc\images\feature_request.png = doc\images\feature_request.png - doc\images\game_crashed.png = doc\images\game_crashed.png - doc\images\screenie.png = doc\images\screenie.png - doc\images\start.png = doc\images\start.png - doc\images\unable_to_load_plugin.png = doc\images\unable_to_load_plugin.png - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{B5E886E6-FC59-47F9-9964-13A49C0C8E5A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{B8C7B3B0-4D30-4D3C-A7DC-9EF33EDBAF22}" - ProjectSection(SolutionItems) = preProject - .github\workflows\CD.yml = .github\workflows\CD.yml - .github\workflows\CI.yml = .github\workflows\CI.yml - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Debug|x64.ActiveCfg = Debug|Win32 - {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Debug|x86.ActiveCfg = Debug|Win32 - {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Debug|x86.Build.0 = Debug|Win32 - {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Release|Any CPU.ActiveCfg = Release|Win32 - {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Release|x64.ActiveCfg = Release|Win32 - {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Release|x86.ActiveCfg = Release|Win32 - {3F6459A9-566E-4CAC-A412-C03FF51D67E9}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {2234E52A-D21C-4984-B830-0D1EBC6842C5} = {4990948C-3306-40BA-9EAD-594A5520043F} - {B82DAA33-1051-496B-A05A-58BB70E8BC02} = {2234E52A-D21C-4984-B830-0D1EBC6842C5} - {B5E886E6-FC59-47F9-9964-13A49C0C8E5A} = {4990948C-3306-40BA-9EAD-594A5520043F} - {B8C7B3B0-4D30-4D3C-A7DC-9EF33EDBAF22} = {B5E886E6-FC59-47F9-9964-13A49C0C8E5A} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {FE1A6506-7258-47FF-839A-FF441AAA310C} - EndGlobalSection -EndGlobal diff --git a/_config.yml b/_config.yml index 05f5a5f9..3e6778e7 100644 --- a/_config.yml +++ b/_config.yml @@ -2,5 +2,4 @@ include: - doc/contributing.md exclude: - src - - lib - .github diff --git a/doc/contributing.md b/doc/contributing.md index 111942dc..5f340fc7 100644 --- a/doc/contributing.md +++ b/doc/contributing.md @@ -7,10 +7,11 @@ - [Linux](#linux) - [Pull Requests](#pull-requests) - [Coding Style](#coding-style) -- [Coding](#coding) +- [API](#api) - [Interfaces](#interfaces) - [Offsets](#offsets) - [Hooking](#hooking) + - [Command Hooks](#command-hooks) - [Features](#features) - [Memory Utils](#memory-utils) - [Reading Pointer Paths](#reading-pointer-paths) @@ -25,7 +26,7 @@ - [Buttons](#buttons) - [HUD](#hud) - [Elements](#elements) - - [Separate](#separate) + - [Separate](#separate) - [Game Support](#game-support) - [Versions](#versions) - [Unique Console Commands](#unique-console-commands) @@ -38,8 +39,8 @@ ### Windows -- Visual Studio 2017 or 2019 -- MSVC Toolset v141 +- Visual Studio 2019 +- MSVC Toolset v142 - Configure SDK version in `src/SourceAutoRecord.vcxproj` or `src/SourceAutoRecord16.vcxproj` - Configure paths in `copy.bat` @@ -61,7 +62,7 @@ ### Quick Tutorial with git - Fork this repository on GitHub -- git clone https://github.com//SourceAutoRecord +- git clone https://github.com/\/SourceAutoRecord - git remote add upstream https://github.com/NeKzor/SourceAutoRecord - git fetch remotes/upstream/master - git checkout -b feature/something remotes/upstream/master @@ -94,21 +95,74 @@ A `.clang-format` file is included. I'd highly recommend using an extension: Note: You'll sometimes see a mix with Valve's coding style. -## Coding +## API SAR was designed to be able to load for multiple Source Engine games on Windows and Linux. +### Modules + +Modules represent the game engine. They are used to initialize all game states and hooks. By default a module will not enable hooked functions automatically unless `isHookable` is set to true. + +```cpp +// Modules/Engine.hpp + +Engine() + : Module(MODULE("engine")) // Macro will resolve .dll/.so extension +{ + // Only required when calling Interface::Hookable + this->isHookable = true; +} +``` + +```cpp +// Modules/Engine.cpp + +void Engine::Init() +{ + // Hook, game specific init logic + // Should throw exception if an error occurs +} + +void Engine::Shutdown() +{ + // Destroy stuff +} +``` + ### Interfaces -Engine interfaces can easily be obtained and hooked: +The interface class can be used to wrap a game object. They are used to walk through vtables to get specific engine functions but also for intercepting function calls (see [hooking](#hooking)). Engine interfaces can easily be obtained too. SAR will resolve the interface version automatically: +Note: Only static objects should be hooked with this. + +```cpp +// Wrap pointer +auto wrapped = Interface::CreateNew(this, someObjectPointer); + +// Find interface in current module +this->g_ClientDLL = Interface::CreateNew(this, "VClient0"); // VClient001 +``` + +In order to call the `Interface::Hook(_Hook hook, int offset)` method of interfaces, the module needs to be hookable (see [Modules](#modules)). ```cpp -this->g_ClientDLL = Interface::Create(this->Name(), "VClient0"); +this->g_ClientDLL = Interface::Hookable(this, "VClient0"); ``` -SAR will resolve the interface version automatically. Use `VClient0` instead of `VClient001` etc. +The static `Temp` method can be useful if a temporary instance should be created in cases where only the functions are needed. + +```cpp +Interface::Temp(this, "VClient0", [this](const Inteface* g_ClientDLL) { + this->SomeMethod = g_ClientDLL->Original<_SomeMethod>(Offsets::SomeMethod); +}); +``` -Note: Modules implement `Module::Name` which returns their module name. For example: `client.so` for Linux and `client.dll` for Windows. There's also the `MODULE` macro that helps you with that. +Note: These methods will throw an exception on error. SAR will automatically catch them on load and return an error message. Hookable interfaces will be acitvated as the last initialization step of the plugin. + +In the end when a module unloads all its interfaces should be deleted wich can be done with `Destroy`. + +```cpp +Interface::Destroy(this->someInterface); +``` ### Offsets @@ -149,28 +203,44 @@ Read [Game Support](#game-support) for initialization. Functions will be hooked through virtual method tables (VMT). SAR provides useful macros for declaration: ```cpp -// Client.hpp -DECL_DETOUR(CreateMove, float flInputSampleTime, CUserCmd* cmd) - // Client.cpp -REDECL(Client::CreateMove); -// int __cdecl Client::CreateMove_Hook(void* thisptr, float flInputSampleTime, CUserCmd* cmd) -DETOUR(Client::CreateMove, float flInputSampleTime, CUserCmd* cmd) +// int __cdecl CreateMove_Hook(void* thisptr, float flInputSampleTime, CUserCmd* cmd) +DETOUR(CreateMove, float flInputSampleTime, CUserCmd* cmd) { // Always call/return original function/value unless you know what you're doing - return Client::CreateMove(thisptr, flInputSampleTime, cmd); + return CreateMove(thisptr, flInputSampleTime, cmd); } // Somewhere in Client::Init -this->g_ClientDLL->Hook(Client::HudUpdate_Hook, Client::HudUpdate, Offsets::HudUpdate); +this->g_ClientDLL->Hook(&hkHudUpdate, Offsets::HudUpdate); ``` Calling conventions will automatically be resolved using the `__rescall` macro. On Linux it will be `__cdecl` and on Windows `__thiscall`. Hooks on Windows will be declared as `__fastcall` with unused `edx` register. Use `DETOUR_T` for custom return types and `DETOUR_STD` for `__stdcall`. +#### Command Hooks + +```cpp +// Engine.cpp + +// "gameui_activate" +DETOUR_COMMAND(gameui_activate) +{ + if (sar_disable_steam_pause.GetBool() && engine->overlayActivated) { + return; + } + + // Call original + gameui_activate_callback(args); +} + +// Engine::Init +gameui_activate_hook.Register(this); +``` + ### Features -Simple example for adding a new SAR feature in OOP style. +Every custom game state and code logic should be written as a features. They would then we be called by modules or commands. ```cpp // src/Features/MyFeature.hpp @@ -187,7 +257,9 @@ public: }; extern MyFeature* myFeature; +``` +```cpp // src/Features/MyFeature.cpp #include "MyFeature.hpp" @@ -196,7 +268,6 @@ MyFeature* myFeature; MyFeature::MyFeature() : state(0) { - this->hasLoaded = true; } void MyFeature::ChangeState(int newState) { @@ -206,13 +277,15 @@ int MyFeature::GetState() { return this->state; } +``` +```cpp // src/Features.hpp #include "Features/MyFeature.hpp" // src/SAR.cpp -// SAR::Load -this->features->AddFeature(&myFeature); +// SAR::Init +this->features->AddFeature<>(&myFeature); ``` ### Memory Utils @@ -250,7 +323,7 @@ Memory::CloseModuleHandle(tier0); #### Access Virtual Function ```cpp -auto IsCommand = Memory::VMT(cmd, Offsets::IsCommand)); +auto IsCommand = Memory::VMT(cmd, Offsets::IsCommand); ``` #### Signature-Scanning aka AOB-Scan @@ -263,17 +336,23 @@ uintptr_t firstResult = Memory::Scan(MODULE("engine"), "55 8B EC 0F 57 C0 81 EC std::vector allResults = Memory::MultiScan(engine->Name(), TRACE_SHUTDOWN_PATTERN, TRACE_SHUTDOWN_OFFSET1); // Multiple patterns with different offsets +// Note: This is not a pointer path PATTERN(DATAMAP_PATTERN1, "B8 ? ? ? ? C7 05", 11, 1); PATTERN(DATAMAP_PATTERN2, "C7 05 ? ? ? ? ? ? ? ? B8", 6, 11); PATTERNS(DATAMAP_PATTERNS, &DATAMAP_PATTERN1, &DATAMAP_PATTERN2); -auto result = Memory::MultiScan(moduleName, &DATAMAP_PATTERNS); +auto results = Memory::MultiScan(moduleName, &DATAMAP_PATTERNS); + +for (auto const& result : results) { + auto res1 = Memory::Deref(result[0]); // 11, 6 + auto res2 = Memory::Deref(result[1]); // 1, 11 +} ``` #### Relative to Absolute Address -Only use this in tests. +Only use this in tests. Disabled by default for release builds. ```cpp auto funcAddress = Memory::Absolute(MODULE("engine"), 0xdeadbeef); @@ -284,19 +363,28 @@ auto funcAddress = Memory::Absolute(MODULE("engine"), 0xdeadbeef); #### Variables ```cpp -// Boolean +// Simple on/off Variable sar_simple_mode("sar_simple_mode", "0", "Useful help description.\n"); -// Float + +// Number, game specific for Portal and Portal2 Variable sar_mode("sar_mode", "0", 0 + "Useful help description.\n", + SourceGame_Portal | SourceGame_Portal2); + +// Number range [0, 2] +Variable sar_mode("sar_mode", "0", 0, 2 "Useful help description.\n"); -// String + +// Specific flags Variable sar_text("sar_text", "a string", - "Useful help description.\n", 0); + "Useful help description.\n", + SourceGame_Unknown, // Available for every game + 0); // Sets flags to interpret this as a string // From the engine auto sv_cheats = Variable("sv_cheats"); -if (sv_cheats.GetBool()) { +if (!!sv_cheats && sv_cheats.GetBool()) { // Stop cheating sv_cheats.SetValue(0); } @@ -306,17 +394,23 @@ Note: Keep a static version of a variable if it can be accessed more than once. #### Commands -Commands should always return a useful message if something went wrong. - ```cpp CON_COMMAND(sar_hello, "Useful help description.\n") { + // Always print a useful message for the user if not used correctly if (args.ArgC() != 2) { return console->Print("Please enter a string!\n"); } console->Print("Hello %s!\n", args[1]); } + +// Limit a command to specfic games +CON_COMMAND_U(sar_unique_command, + "Useful help description.\n", + SourceGame_Portal | SourceGame_Portal2) +{ +} ``` #### Autocompletion @@ -328,18 +422,18 @@ CON_COMMAND(sar_hello, "Useful help description.\n") // Last argument is type of std::vector. It is required to wrap it with () CON_COMMAND_COMPLETION(sar_force_fov, "Description.\n", ({ "0", "50", "60", "70", "80", "90", "100", "110", "120", "130", "140" })) { - // Command callback + // Command callback } // Use this macro in order to call some initialization logic DECL_COMMAND_COMPLETION(sar_workshop) { - // Init some stuff + // Init some stuff if (workshop->maps.empty()) { workshop->Update(); } - // Basic filtering logic + // Basic filtering logic for (auto& map : workshop->maps) { if (items.size() == COMMAND_COMPLETION_MAXITEMS) { break; @@ -359,7 +453,7 @@ DECL_COMMAND_COMPLETION(sar_workshop) CON_COMMAND_F_COMPLETION(sar_workshop, "Description.\n", 0, sar_workshop_CompletionFunc) { - // Command callback + // Command callback } ``` @@ -373,39 +467,47 @@ HUD elements can be declared with just a few lines of code. All elements are gro #include "Features/Hud/Hud.hpp" // Called if: sar_hud_frame 1 -HUD_ELEMENT(frame, "0", "Default example.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT(frame, "0", + "Default example.\n", + HudType_InGame | HudType_Paused) { ctx->DrawElement("frame: %i", session->currentFrame); } // Called if: sar_hud_some_mode > 0 -HUD_ELEMENT_MODE(some_mode, "0", 0, 5, "Mode example.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT_MODE(some_mode, "0", 0, 5, + "Mode example.\n", + HudType_InGame | HudType_Paused) { - if (mode == 4) { - ctx->DrawElement("mode: 4"); - } else { - ctx->DrawElement("mode: 1-3 or 5"); - } + if (mode == 4) { + ctx->DrawElement("mode: 4"); + } else { + ctx->DrawElement("mode: 1-3 or 5"); + } } // Called if: sar_hud_some_text[0] != '\0' (not empty) -HUD_ELEMENT_STRING(some_text, "", 0, 5, "Text example.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT_STRING(some_text, "", 0, 5, + "Text example.\n", + HudType_InGame | HudType_Paused) { ctx->DrawElement("mode: %s", text); } // Splitscreen support needs a 2 at the end of the macro -HUD_ELEMENT2(splitscreen, "0", "Slot example.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT2(splitscreen, "0", + "Slot example.\n", + HudType_InGame | HudType_Paused) { - // Do something with slot - auto slot = ctx->slot; + // Do something with slot + auto slot = ctx->slot; } // Limit an element for a specific game HUD_ELEMENT3(game_version, "0", "Game specific example.\n", - HudType_InGame | HudType_Paused, // Where to draw - false, // no splitscreens - SourceGame_Portal) // Portal only + HudType_InGame | HudType_Paused, // Where to draw + false, // no splitscreens + SourceGame_Portal) // Portal only { } ``` @@ -415,12 +517,12 @@ Last step is to add the element name to the ordered list. It is used for autocom ``` // Features/Hud/Hud.cpp std::vector elementOrder = { - // ... - "frame", - "some_mode", - "some_text", - "splitscreen", - "game_version" + // ... + "frame", + "some_mode", + "some_text", + "splitscreen", + "game_version" }; ``` @@ -460,25 +562,36 @@ extern Variable sar_my_hud_font_index; #include "Variable.hpp" -Variable sar_my_hud("sar_sr_hud", "0", 0, "Draws my HUD.\n"); -Variable sar_my_hud_x("sar_sr_hud_x", "0", 0, "X offset of my HUD.\n"); -Variable sar_my_hud_y("sar_sr_hud_y", "100", 0, "Y offset of my HUD.\n"); -Variable sar_my_hud_font_color("sar_sr_hud_font_color", "255 255 255 255", "RGBA font color of my HUD.\n", 0); -Variable sar_my_hud_font_index("sar_sr_hud_font_index", "70", 0, "Font index of my HUD.\n"); +Variable sar_sr_hud("sar_sr_hud", "0", 0, + "Draws speedrun timer.\n", + SourceGame_SupportsS3); +Variable sar_sr_hud_x("sar_sr_hud_x", "0", 0, + "X offset of speedrun timer HUD.\n", + SourceGame_SupportsS3); +Variable sar_sr_hud_y("sar_sr_hud_y", "100", 0, + "Y offset of speedrun timer HUD.\n", + SourceGame_SupportsS3); +Variable sar_sr_hud_font_color("sar_sr_hud_font_color", "255 255 255 255", + "RGBA font color of speedrun timer HUD.\n", + SourceGame_SupportsS3, + 0); +Variable sar_sr_hud_font_index("sar_sr_hud_font_index", "70", 0, + "Font index of speedrun timer HUD.\n", + SourceGame_SupportsS3); MyHud myHud; MyHud::MyHud() : Hud(HudType_InGame, // Only when session is running (no-pauses) - false, // Do not draw for splitscreen (default) - SourceGame_Portal2Engine) // Support specific game verison (default is for every game) + false, // Do not draw for splitscreen (default) + SourceGame_Portal2Engine) // Support specific game verison (default is for every game) { } // Implement a more complex drawing logic if needed bool MyHud::ShouldDraw() { - // Calling the base function will resolve the HUD type condition + // Calling the base function will resolve the HUD type condition return sar_my_hud.GetBool() && Hud::ShouldDraw(); } @@ -500,7 +613,7 @@ void MyHud::Paint(int slot) // See Feature/Hud/InputHud.cpp bool MyHud::GetCurrentSize(int& xSize, int& ySize) { - // Calc size and return value if hud is active + // Calc size and return value if hud is active return false; } ``` @@ -508,6 +621,7 @@ bool MyHud::GetCurrentSize(int& xSize, int& ySize) #### Buttons Portal 2 Engine only. + ```cpp #define IN_AUTOSTRAFE (1 << 31) // Make sure to use a unique flag diff --git a/lib/minhook/LICENSE.txt b/lib/minhook/LICENSE.txt deleted file mode 100644 index 74dea272..00000000 --- a/lib/minhook/LICENSE.txt +++ /dev/null @@ -1,81 +0,0 @@ -MinHook - The Minimalistic API Hooking Library for x64/x86 -Copyright (C) 2009-2017 Tsuda Kageyu. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER -OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -================================================================================ -Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov. -================================================================================ -Hacker Disassembler Engine 32 C -Copyright (c) 2008-2009, Vyacheslav Patkov. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -------------------------------------------------------------------------------- -Hacker Disassembler Engine 64 C -Copyright (c) 2008-2009, Vyacheslav Patkov. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/minhook/MinHook.h b/lib/minhook/MinHook.h deleted file mode 100644 index 23244b8e..00000000 --- a/lib/minhook/MinHook.h +++ /dev/null @@ -1,186 +0,0 @@ -/* -* MinHook - The Minimalistic API Hooking Library for x64/x86 -* Copyright (C) 2009-2017 Tsuda Kageyu. -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER -* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#pragma once - -#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) -#error MinHook supports only x86 and x64 systems. -#endif - -#include - -// MinHook Error Codes. -typedef enum MH_STATUS -{ - // Unknown error. Should not be returned. - MH_UNKNOWN = -1, - - // Successful. - MH_OK = 0, - - // MinHook is already initialized. - MH_ERROR_ALREADY_INITIALIZED, - - // MinHook is not initialized yet, or already uninitialized. - MH_ERROR_NOT_INITIALIZED, - - // The hook for the specified target function is already created. - MH_ERROR_ALREADY_CREATED, - - // The hook for the specified target function is not created yet. - MH_ERROR_NOT_CREATED, - - // The hook for the specified target function is already enabled. - MH_ERROR_ENABLED, - - // The hook for the specified target function is not enabled yet, or already - // disabled. - MH_ERROR_DISABLED, - - // The specified pointer is invalid. It points the address of non-allocated - // and/or non-executable region. - MH_ERROR_NOT_EXECUTABLE, - - // The specified target function cannot be hooked. - MH_ERROR_UNSUPPORTED_FUNCTION, - - // Failed to allocate memory. - MH_ERROR_MEMORY_ALLOC, - - // Failed to change the memory protection. - MH_ERROR_MEMORY_PROTECT, - - // The specified module is not loaded. - MH_ERROR_MODULE_NOT_FOUND, - - // The specified function is not found. - MH_ERROR_FUNCTION_NOT_FOUND -} -MH_STATUS; - -// Can be passed as a parameter to MH_EnableHook, MH_DisableHook, -// MH_QueueEnableHook or MH_QueueDisableHook. -#define MH_ALL_HOOKS NULL - -#ifdef __cplusplus -extern "C" { -#endif - - // Initialize the MinHook library. You must call this function EXACTLY ONCE - // at the beginning of your program. - MH_STATUS WINAPI MH_Initialize(VOID); - - // Uninitialize the MinHook library. You must call this function EXACTLY - // ONCE at the end of your program. - MH_STATUS WINAPI MH_Uninitialize(VOID); - - // Creates a Hook for the specified target function, in disabled state. - // Parameters: - // pTarget [in] A pointer to the target function, which will be - // overridden by the detour function. - // pDetour [in] A pointer to the detour function, which will override - // the target function. - // ppOriginal [out] A pointer to the trampoline function, which will be - // used to call the original target function. - // This parameter can be NULL. - MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); - - // Creates a Hook for the specified API function, in disabled state. - // Parameters: - // pszModule [in] A pointer to the loaded module name which contains the - // target function. - // pszTarget [in] A pointer to the target function name, which will be - // overridden by the detour function. - // pDetour [in] A pointer to the detour function, which will override - // the target function. - // ppOriginal [out] A pointer to the trampoline function, which will be - // used to call the original target function. - // This parameter can be NULL. - MH_STATUS WINAPI MH_CreateHookApi( - LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); - - // Creates a Hook for the specified API function, in disabled state. - // Parameters: - // pszModule [in] A pointer to the loaded module name which contains the - // target function. - // pszTarget [in] A pointer to the target function name, which will be - // overridden by the detour function. - // pDetour [in] A pointer to the detour function, which will override - // the target function. - // ppOriginal [out] A pointer to the trampoline function, which will be - // used to call the original target function. - // This parameter can be NULL. - // ppTarget [out] A pointer to the target function, which will be used - // with other functions. - // This parameter can be NULL. - MH_STATUS WINAPI MH_CreateHookApiEx( - LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); - - // Removes an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); - - // Enables an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // enabled in one go. - MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); - - // Disables an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // disabled in one go. - MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); - - // Queues to enable an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // queued to be enabled. - MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); - - // Queues to disable an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // queued to be disabled. - MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); - - // Applies all queued changes in one go. - MH_STATUS WINAPI MH_ApplyQueued(VOID); - - // Translates the MH_STATUS to its name as a string. - const char * WINAPI MH_StatusToString(MH_STATUS status); - -#ifdef __cplusplus -} -#endif - diff --git a/lib/minhook/buffer.c b/lib/minhook/buffer.c deleted file mode 100644 index 8f9fbcea..00000000 --- a/lib/minhook/buffer.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "buffer.h" - -// Size of each memory block. (= page size of VirtualAlloc) -#define MEMORY_BLOCK_SIZE 0x1000 - -// Max range for seeking a memory block. (= 1024MB) -#define MAX_MEMORY_RANGE 0x40000000 - -// Memory protection flags to check the executable address. -#define PAGE_EXECUTE_FLAGS \ - (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) - -// Memory slot. -typedef struct _MEMORY_SLOT -{ - union - { - struct _MEMORY_SLOT *pNext; - UINT8 buffer[MEMORY_SLOT_SIZE]; - }; -} MEMORY_SLOT, *PMEMORY_SLOT; - -// Memory block info. Placed at the head of each block. -typedef struct _MEMORY_BLOCK -{ - struct _MEMORY_BLOCK *pNext; - PMEMORY_SLOT pFree; // First element of the free slot list. - UINT usedCount; -} MEMORY_BLOCK, *PMEMORY_BLOCK; - -//------------------------------------------------------------------------- -// Global Variables: -//------------------------------------------------------------------------- - -// First element of the memory block list. -PMEMORY_BLOCK g_pMemoryBlocks; - -//------------------------------------------------------------------------- -VOID InitializeBuffer(VOID) -{ - // Nothing to do for now. -} - -//------------------------------------------------------------------------- -VOID UninitializeBuffer(VOID) -{ - PMEMORY_BLOCK pBlock = g_pMemoryBlocks; - g_pMemoryBlocks = NULL; - - while (pBlock) - { - PMEMORY_BLOCK pNext = pBlock->pNext; - VirtualFree(pBlock, 0, MEM_RELEASE); - pBlock = pNext; - } -} - -//------------------------------------------------------------------------- -#if defined(_M_X64) || defined(__x86_64__) -static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity) -{ - ULONG_PTR tryAddr = (ULONG_PTR)pAddress; - - // Round down to the allocation granularity. - tryAddr -= tryAddr % dwAllocationGranularity; - - // Start from the previous allocation granularity multiply. - tryAddr -= dwAllocationGranularity; - - while (tryAddr >= (ULONG_PTR)pMinAddr) - { - MEMORY_BASIC_INFORMATION mbi; - if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) - break; - - if (mbi.State == MEM_FREE) - return (LPVOID)tryAddr; - - if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity) - break; - - tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity; - } - - return NULL; -} -#endif - -//------------------------------------------------------------------------- -#if defined(_M_X64) || defined(__x86_64__) -static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity) -{ - ULONG_PTR tryAddr = (ULONG_PTR)pAddress; - - // Round down to the allocation granularity. - tryAddr -= tryAddr % dwAllocationGranularity; - - // Start from the next allocation granularity multiply. - tryAddr += dwAllocationGranularity; - - while (tryAddr <= (ULONG_PTR)pMaxAddr) - { - MEMORY_BASIC_INFORMATION mbi; - if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) - break; - - if (mbi.State == MEM_FREE) - return (LPVOID)tryAddr; - - tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize; - - // Round up to the next allocation granularity. - tryAddr += dwAllocationGranularity - 1; - tryAddr -= tryAddr % dwAllocationGranularity; - } - - return NULL; -} -#endif - -//------------------------------------------------------------------------- -static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin) -{ - PMEMORY_BLOCK pBlock; -#if defined(_M_X64) || defined(__x86_64__) - ULONG_PTR minAddr; - ULONG_PTR maxAddr; - - SYSTEM_INFO si; - GetSystemInfo(&si); - minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress; - maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress; - - // pOrigin ± 512MB - if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE) - minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE; - - if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE) - maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE; - - // Make room for MEMORY_BLOCK_SIZE bytes. - maxAddr -= MEMORY_BLOCK_SIZE - 1; -#endif - - // Look the registered blocks for a reachable one. - for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext) - { -#if defined(_M_X64) || defined(__x86_64__) - // Ignore the blocks too far. - if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr) - continue; -#endif - // The block has at least one unused slot. - if (pBlock->pFree != NULL) - return pBlock; - } - -#if defined(_M_X64) || defined(__x86_64__) - // Alloc a new block above if not found. - { - LPVOID pAlloc = pOrigin; - while ((ULONG_PTR)pAlloc >= minAddr) - { - pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity); - if (pAlloc == NULL) - break; - - pBlock = (PMEMORY_BLOCK)VirtualAlloc( - pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (pBlock != NULL) - break; - } - } - - // Alloc a new block below if not found. - if (pBlock == NULL) - { - LPVOID pAlloc = pOrigin; - while ((ULONG_PTR)pAlloc <= maxAddr) - { - pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity); - if (pAlloc == NULL) - break; - - pBlock = (PMEMORY_BLOCK)VirtualAlloc( - pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (pBlock != NULL) - break; - } - } -#else - // In x86 mode, a memory block can be placed anywhere. - pBlock = (PMEMORY_BLOCK)VirtualAlloc( - NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); -#endif - - if (pBlock != NULL) - { - // Build a linked list of all the slots. - PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1; - pBlock->pFree = NULL; - pBlock->usedCount = 0; - do - { - pSlot->pNext = pBlock->pFree; - pBlock->pFree = pSlot; - pSlot++; - } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE); - - pBlock->pNext = g_pMemoryBlocks; - g_pMemoryBlocks = pBlock; - } - - return pBlock; -} - -//------------------------------------------------------------------------- -LPVOID AllocateBuffer(LPVOID pOrigin) -{ - PMEMORY_SLOT pSlot; - PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin); - if (pBlock == NULL) - return NULL; - - // Remove an unused slot from the list. - pSlot = pBlock->pFree; - pBlock->pFree = pSlot->pNext; - pBlock->usedCount++; -#ifdef _DEBUG - // Fill the slot with INT3 for debugging. - memset(pSlot, 0xCC, sizeof(MEMORY_SLOT)); -#endif - return pSlot; -} - -//------------------------------------------------------------------------- -VOID FreeBuffer(LPVOID pBuffer) -{ - PMEMORY_BLOCK pBlock = g_pMemoryBlocks; - PMEMORY_BLOCK pPrev = NULL; - ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE; - - while (pBlock != NULL) - { - if ((ULONG_PTR)pBlock == pTargetBlock) - { - PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer; -#ifdef _DEBUG - // Clear the released slot for debugging. - memset(pSlot, 0x00, sizeof(*pSlot)); -#endif - // Restore the released slot to the list. - pSlot->pNext = pBlock->pFree; - pBlock->pFree = pSlot; - pBlock->usedCount--; - - // Free if unused. - if (pBlock->usedCount == 0) - { - if (pPrev) - pPrev->pNext = pBlock->pNext; - else - g_pMemoryBlocks = pBlock->pNext; - - VirtualFree(pBlock, 0, MEM_RELEASE); - } - - break; - } - - pPrev = pBlock; - pBlock = pBlock->pNext; - } -} - -//------------------------------------------------------------------------- -BOOL IsExecutableAddress(LPVOID pAddress) -{ - MEMORY_BASIC_INFORMATION mi; - VirtualQuery(pAddress, &mi, sizeof(mi)); - - return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS)); -} diff --git a/lib/minhook/buffer.h b/lib/minhook/buffer.h deleted file mode 100644 index 204d551b..00000000 --- a/lib/minhook/buffer.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -// Size of each memory slot. -#if defined(_M_X64) || defined(__x86_64__) - #define MEMORY_SLOT_SIZE 64 -#else - #define MEMORY_SLOT_SIZE 32 -#endif - -VOID InitializeBuffer(VOID); -VOID UninitializeBuffer(VOID); -LPVOID AllocateBuffer(LPVOID pOrigin); -VOID FreeBuffer(LPVOID pBuffer); -BOOL IsExecutableAddress(LPVOID pAddress); diff --git a/lib/minhook/hde/hde32.c b/lib/minhook/hde/hde32.c deleted file mode 100644 index 08fa25bd..00000000 --- a/lib/minhook/hde/hde32.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Hacker Disassembler Engine 32 C - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - */ - -#if defined(_M_IX86) || defined(__i386__) - -#include "hde32.h" -#include "table32.h" - -unsigned int hde32_disasm(const void *code, hde32s *hs) -{ - uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; - uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0; - - // Avoid using memset to reduce the footprint. -#ifndef _MSC_VER - memset((LPBYTE)hs, 0, sizeof(hde32s)); -#else - __stosb((LPBYTE)hs, 0, sizeof(hde32s)); -#endif - - for (x = 16; x; x--) - switch (c = *p++) { - case 0xf3: - hs->p_rep = c; - pref |= PRE_F3; - break; - case 0xf2: - hs->p_rep = c; - pref |= PRE_F2; - break; - case 0xf0: - hs->p_lock = c; - pref |= PRE_LOCK; - break; - case 0x26: case 0x2e: case 0x36: - case 0x3e: case 0x64: case 0x65: - hs->p_seg = c; - pref |= PRE_SEG; - break; - case 0x66: - hs->p_66 = c; - pref |= PRE_66; - break; - case 0x67: - hs->p_67 = c; - pref |= PRE_67; - break; - default: - goto pref_done; - } - pref_done: - - hs->flags = (uint32_t)pref << 23; - - if (!pref) - pref |= PRE_NONE; - - if ((hs->opcode = c) == 0x0f) { - hs->opcode2 = c = *p++; - ht += DELTA_OPCODES; - } else if (c >= 0xa0 && c <= 0xa3) { - if (pref & PRE_67) - pref |= PRE_66; - else - pref &= ~PRE_66; - } - - opcode = c; - cflags = ht[ht[opcode / 4] + (opcode % 4)]; - - if (cflags == C_ERROR) { - hs->flags |= F_ERROR | F_ERROR_OPCODE; - cflags = 0; - if ((opcode & -3) == 0x24) - cflags++; - } - - x = 0; - if (cflags & C_GROUP) { - uint16_t t; - t = *(uint16_t *)(ht + (cflags & 0x7f)); - cflags = (uint8_t)t; - x = (uint8_t)(t >> 8); - } - - if (hs->opcode2) { - ht = hde32_table + DELTA_PREFIXES; - if (ht[ht[opcode / 4] + (opcode % 4)] & pref) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - } - - if (cflags & C_MODRM) { - hs->flags |= F_MODRM; - hs->modrm = c = *p++; - hs->modrm_mod = m_mod = c >> 6; - hs->modrm_rm = m_rm = c & 7; - hs->modrm_reg = m_reg = (c & 0x3f) >> 3; - - if (x && ((x << m_reg) & 0x80)) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - - if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { - uint8_t t = opcode - 0xd9; - if (m_mod == 3) { - ht = hde32_table + DELTA_FPU_MODRM + t*8; - t = ht[m_reg] << m_rm; - } else { - ht = hde32_table + DELTA_FPU_REG; - t = ht[t] << m_reg; - } - if (t & 0x80) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - } - - if (pref & PRE_LOCK) { - if (m_mod == 3) { - hs->flags |= F_ERROR | F_ERROR_LOCK; - } else { - uint8_t *table_end, op = opcode; - if (hs->opcode2) { - ht = hde32_table + DELTA_OP2_LOCK_OK; - table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; - } else { - ht = hde32_table + DELTA_OP_LOCK_OK; - table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; - op &= -2; - } - for (; ht != table_end; ht++) - if (*ht++ == op) { - if (!((*ht << m_reg) & 0x80)) - goto no_lock_error; - else - break; - } - hs->flags |= F_ERROR | F_ERROR_LOCK; - no_lock_error: - ; - } - } - - if (hs->opcode2) { - switch (opcode) { - case 0x20: case 0x22: - m_mod = 3; - if (m_reg > 4 || m_reg == 1) - goto error_operand; - else - goto no_error_operand; - case 0x21: case 0x23: - m_mod = 3; - if (m_reg == 4 || m_reg == 5) - goto error_operand; - else - goto no_error_operand; - } - } else { - switch (opcode) { - case 0x8c: - if (m_reg > 5) - goto error_operand; - else - goto no_error_operand; - case 0x8e: - if (m_reg == 1 || m_reg > 5) - goto error_operand; - else - goto no_error_operand; - } - } - - if (m_mod == 3) { - uint8_t *table_end; - if (hs->opcode2) { - ht = hde32_table + DELTA_OP2_ONLY_MEM; - table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM; - } else { - ht = hde32_table + DELTA_OP_ONLY_MEM; - table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; - } - for (; ht != table_end; ht += 2) - if (*ht++ == opcode) { - if (*ht++ & pref && !((*ht << m_reg) & 0x80)) - goto error_operand; - else - break; - } - goto no_error_operand; - } else if (hs->opcode2) { - switch (opcode) { - case 0x50: case 0xd7: case 0xf7: - if (pref & (PRE_NONE | PRE_66)) - goto error_operand; - break; - case 0xd6: - if (pref & (PRE_F2 | PRE_F3)) - goto error_operand; - break; - case 0xc5: - goto error_operand; - } - goto no_error_operand; - } else - goto no_error_operand; - - error_operand: - hs->flags |= F_ERROR | F_ERROR_OPERAND; - no_error_operand: - - c = *p++; - if (m_reg <= 1) { - if (opcode == 0xf6) - cflags |= C_IMM8; - else if (opcode == 0xf7) - cflags |= C_IMM_P66; - } - - switch (m_mod) { - case 0: - if (pref & PRE_67) { - if (m_rm == 6) - disp_size = 2; - } else - if (m_rm == 5) - disp_size = 4; - break; - case 1: - disp_size = 1; - break; - case 2: - disp_size = 2; - if (!(pref & PRE_67)) - disp_size <<= 1; - } - - if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) { - hs->flags |= F_SIB; - p++; - hs->sib = c; - hs->sib_scale = c >> 6; - hs->sib_index = (c & 0x3f) >> 3; - if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) - disp_size = 4; - } - - p--; - switch (disp_size) { - case 1: - hs->flags |= F_DISP8; - hs->disp.disp8 = *p; - break; - case 2: - hs->flags |= F_DISP16; - hs->disp.disp16 = *(uint16_t *)p; - break; - case 4: - hs->flags |= F_DISP32; - hs->disp.disp32 = *(uint32_t *)p; - } - p += disp_size; - } else if (pref & PRE_LOCK) - hs->flags |= F_ERROR | F_ERROR_LOCK; - - if (cflags & C_IMM_P66) { - if (cflags & C_REL32) { - if (pref & PRE_66) { - hs->flags |= F_IMM16 | F_RELATIVE; - hs->imm.imm16 = *(uint16_t *)p; - p += 2; - goto disasm_done; - } - goto rel32_ok; - } - if (pref & PRE_66) { - hs->flags |= F_IMM16; - hs->imm.imm16 = *(uint16_t *)p; - p += 2; - } else { - hs->flags |= F_IMM32; - hs->imm.imm32 = *(uint32_t *)p; - p += 4; - } - } - - if (cflags & C_IMM16) { - if (hs->flags & F_IMM32) { - hs->flags |= F_IMM16; - hs->disp.disp16 = *(uint16_t *)p; - } else if (hs->flags & F_IMM16) { - hs->flags |= F_2IMM16; - hs->disp.disp16 = *(uint16_t *)p; - } else { - hs->flags |= F_IMM16; - hs->imm.imm16 = *(uint16_t *)p; - } - p += 2; - } - if (cflags & C_IMM8) { - hs->flags |= F_IMM8; - hs->imm.imm8 = *p++; - } - - if (cflags & C_REL32) { - rel32_ok: - hs->flags |= F_IMM32 | F_RELATIVE; - hs->imm.imm32 = *(uint32_t *)p; - p += 4; - } else if (cflags & C_REL8) { - hs->flags |= F_IMM8 | F_RELATIVE; - hs->imm.imm8 = *p++; - } - - disasm_done: - - if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { - hs->flags |= F_ERROR | F_ERROR_LENGTH; - hs->len = 15; - } - - return (unsigned int)hs->len; -} - -#endif // defined(_M_IX86) || defined(__i386__) diff --git a/lib/minhook/hde/hde32.h b/lib/minhook/hde/hde32.h deleted file mode 100644 index 1112450d..00000000 --- a/lib/minhook/hde/hde32.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Hacker Disassembler Engine 32 - * Copyright (c) 2006-2009, Vyacheslav Patkov. - * All rights reserved. - * - * hde32.h: C/C++ header file - * - */ - -#ifndef _HDE32_H_ -#define _HDE32_H_ - -/* stdint.h - C99 standard header - * http://en.wikipedia.org/wiki/stdint.h - * - * if your compiler doesn't contain "stdint.h" header (for - * example, Microsoft Visual C++), you can download file: - * http://www.azillionmonkeys.com/qed/pstdint.h - * and change next line to: - * #include "pstdint.h" - */ -#include "pstdint.h" - -#define F_MODRM 0x00000001 -#define F_SIB 0x00000002 -#define F_IMM8 0x00000004 -#define F_IMM16 0x00000008 -#define F_IMM32 0x00000010 -#define F_DISP8 0x00000020 -#define F_DISP16 0x00000040 -#define F_DISP32 0x00000080 -#define F_RELATIVE 0x00000100 -#define F_2IMM16 0x00000800 -#define F_ERROR 0x00001000 -#define F_ERROR_OPCODE 0x00002000 -#define F_ERROR_LENGTH 0x00004000 -#define F_ERROR_LOCK 0x00008000 -#define F_ERROR_OPERAND 0x00010000 -#define F_PREFIX_REPNZ 0x01000000 -#define F_PREFIX_REPX 0x02000000 -#define F_PREFIX_REP 0x03000000 -#define F_PREFIX_66 0x04000000 -#define F_PREFIX_67 0x08000000 -#define F_PREFIX_LOCK 0x10000000 -#define F_PREFIX_SEG 0x20000000 -#define F_PREFIX_ANY 0x3f000000 - -#define PREFIX_SEGMENT_CS 0x2e -#define PREFIX_SEGMENT_SS 0x36 -#define PREFIX_SEGMENT_DS 0x3e -#define PREFIX_SEGMENT_ES 0x26 -#define PREFIX_SEGMENT_FS 0x64 -#define PREFIX_SEGMENT_GS 0x65 -#define PREFIX_LOCK 0xf0 -#define PREFIX_REPNZ 0xf2 -#define PREFIX_REPX 0xf3 -#define PREFIX_OPERAND_SIZE 0x66 -#define PREFIX_ADDRESS_SIZE 0x67 - -#pragma pack(push,1) - -typedef struct { - uint8_t len; - uint8_t p_rep; - uint8_t p_lock; - uint8_t p_seg; - uint8_t p_66; - uint8_t p_67; - uint8_t opcode; - uint8_t opcode2; - uint8_t modrm; - uint8_t modrm_mod; - uint8_t modrm_reg; - uint8_t modrm_rm; - uint8_t sib; - uint8_t sib_scale; - uint8_t sib_index; - uint8_t sib_base; - union { - uint8_t imm8; - uint16_t imm16; - uint32_t imm32; - } imm; - union { - uint8_t disp8; - uint16_t disp16; - uint32_t disp32; - } disp; - uint32_t flags; -} hde32s; - -#pragma pack(pop) - -#ifdef __cplusplus -extern "C" { -#endif - -/* __cdecl */ -unsigned int hde32_disasm(const void *code, hde32s *hs); - -#ifdef __cplusplus -} -#endif - -#endif /* _HDE32_H_ */ diff --git a/lib/minhook/hde/hde64.c b/lib/minhook/hde/hde64.c deleted file mode 100644 index c23e2fc6..00000000 --- a/lib/minhook/hde/hde64.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Hacker Disassembler Engine 64 C - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - */ - -#if defined(_M_X64) || defined(__x86_64__) - -#include "hde64.h" -#include "table64.h" - -unsigned int hde64_disasm(const void *code, hde64s *hs) -{ - uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; - uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; - uint8_t op64 = 0; - - // Avoid using memset to reduce the footprint. -#ifndef _MSC_VER - memset((LPBYTE)hs, 0, sizeof(hde64s)); -#else - __stosb((LPBYTE)hs, 0, sizeof(hde64s)); -#endif - - for (x = 16; x; x--) - switch (c = *p++) { - case 0xf3: - hs->p_rep = c; - pref |= PRE_F3; - break; - case 0xf2: - hs->p_rep = c; - pref |= PRE_F2; - break; - case 0xf0: - hs->p_lock = c; - pref |= PRE_LOCK; - break; - case 0x26: case 0x2e: case 0x36: - case 0x3e: case 0x64: case 0x65: - hs->p_seg = c; - pref |= PRE_SEG; - break; - case 0x66: - hs->p_66 = c; - pref |= PRE_66; - break; - case 0x67: - hs->p_67 = c; - pref |= PRE_67; - break; - default: - goto pref_done; - } - pref_done: - - hs->flags = (uint32_t)pref << 23; - - if (!pref) - pref |= PRE_NONE; - - if ((c & 0xf0) == 0x40) { - hs->flags |= F_PREFIX_REX; - if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) - op64++; - hs->rex_r = (c & 7) >> 2; - hs->rex_x = (c & 3) >> 1; - hs->rex_b = c & 1; - if (((c = *p++) & 0xf0) == 0x40) { - opcode = c; - goto error_opcode; - } - } - - if ((hs->opcode = c) == 0x0f) { - hs->opcode2 = c = *p++; - ht += DELTA_OPCODES; - } else if (c >= 0xa0 && c <= 0xa3) { - op64++; - if (pref & PRE_67) - pref |= PRE_66; - else - pref &= ~PRE_66; - } - - opcode = c; - cflags = ht[ht[opcode / 4] + (opcode % 4)]; - - if (cflags == C_ERROR) { - error_opcode: - hs->flags |= F_ERROR | F_ERROR_OPCODE; - cflags = 0; - if ((opcode & -3) == 0x24) - cflags++; - } - - x = 0; - if (cflags & C_GROUP) { - uint16_t t; - t = *(uint16_t *)(ht + (cflags & 0x7f)); - cflags = (uint8_t)t; - x = (uint8_t)(t >> 8); - } - - if (hs->opcode2) { - ht = hde64_table + DELTA_PREFIXES; - if (ht[ht[opcode / 4] + (opcode % 4)] & pref) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - } - - if (cflags & C_MODRM) { - hs->flags |= F_MODRM; - hs->modrm = c = *p++; - hs->modrm_mod = m_mod = c >> 6; - hs->modrm_rm = m_rm = c & 7; - hs->modrm_reg = m_reg = (c & 0x3f) >> 3; - - if (x && ((x << m_reg) & 0x80)) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - - if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { - uint8_t t = opcode - 0xd9; - if (m_mod == 3) { - ht = hde64_table + DELTA_FPU_MODRM + t*8; - t = ht[m_reg] << m_rm; - } else { - ht = hde64_table + DELTA_FPU_REG; - t = ht[t] << m_reg; - } - if (t & 0x80) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - } - - if (pref & PRE_LOCK) { - if (m_mod == 3) { - hs->flags |= F_ERROR | F_ERROR_LOCK; - } else { - uint8_t *table_end, op = opcode; - if (hs->opcode2) { - ht = hde64_table + DELTA_OP2_LOCK_OK; - table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; - } else { - ht = hde64_table + DELTA_OP_LOCK_OK; - table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; - op &= -2; - } - for (; ht != table_end; ht++) - if (*ht++ == op) { - if (!((*ht << m_reg) & 0x80)) - goto no_lock_error; - else - break; - } - hs->flags |= F_ERROR | F_ERROR_LOCK; - no_lock_error: - ; - } - } - - if (hs->opcode2) { - switch (opcode) { - case 0x20: case 0x22: - m_mod = 3; - if (m_reg > 4 || m_reg == 1) - goto error_operand; - else - goto no_error_operand; - case 0x21: case 0x23: - m_mod = 3; - if (m_reg == 4 || m_reg == 5) - goto error_operand; - else - goto no_error_operand; - } - } else { - switch (opcode) { - case 0x8c: - if (m_reg > 5) - goto error_operand; - else - goto no_error_operand; - case 0x8e: - if (m_reg == 1 || m_reg > 5) - goto error_operand; - else - goto no_error_operand; - } - } - - if (m_mod == 3) { - uint8_t *table_end; - if (hs->opcode2) { - ht = hde64_table + DELTA_OP2_ONLY_MEM; - table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; - } else { - ht = hde64_table + DELTA_OP_ONLY_MEM; - table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; - } - for (; ht != table_end; ht += 2) - if (*ht++ == opcode) { - if (*ht++ & pref && !((*ht << m_reg) & 0x80)) - goto error_operand; - else - break; - } - goto no_error_operand; - } else if (hs->opcode2) { - switch (opcode) { - case 0x50: case 0xd7: case 0xf7: - if (pref & (PRE_NONE | PRE_66)) - goto error_operand; - break; - case 0xd6: - if (pref & (PRE_F2 | PRE_F3)) - goto error_operand; - break; - case 0xc5: - goto error_operand; - } - goto no_error_operand; - } else - goto no_error_operand; - - error_operand: - hs->flags |= F_ERROR | F_ERROR_OPERAND; - no_error_operand: - - c = *p++; - if (m_reg <= 1) { - if (opcode == 0xf6) - cflags |= C_IMM8; - else if (opcode == 0xf7) - cflags |= C_IMM_P66; - } - - switch (m_mod) { - case 0: - if (pref & PRE_67) { - if (m_rm == 6) - disp_size = 2; - } else - if (m_rm == 5) - disp_size = 4; - break; - case 1: - disp_size = 1; - break; - case 2: - disp_size = 2; - if (!(pref & PRE_67)) - disp_size <<= 1; - } - - if (m_mod != 3 && m_rm == 4) { - hs->flags |= F_SIB; - p++; - hs->sib = c; - hs->sib_scale = c >> 6; - hs->sib_index = (c & 0x3f) >> 3; - if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) - disp_size = 4; - } - - p--; - switch (disp_size) { - case 1: - hs->flags |= F_DISP8; - hs->disp.disp8 = *p; - break; - case 2: - hs->flags |= F_DISP16; - hs->disp.disp16 = *(uint16_t *)p; - break; - case 4: - hs->flags |= F_DISP32; - hs->disp.disp32 = *(uint32_t *)p; - } - p += disp_size; - } else if (pref & PRE_LOCK) - hs->flags |= F_ERROR | F_ERROR_LOCK; - - if (cflags & C_IMM_P66) { - if (cflags & C_REL32) { - if (pref & PRE_66) { - hs->flags |= F_IMM16 | F_RELATIVE; - hs->imm.imm16 = *(uint16_t *)p; - p += 2; - goto disasm_done; - } - goto rel32_ok; - } - if (op64) { - hs->flags |= F_IMM64; - hs->imm.imm64 = *(uint64_t *)p; - p += 8; - } else if (!(pref & PRE_66)) { - hs->flags |= F_IMM32; - hs->imm.imm32 = *(uint32_t *)p; - p += 4; - } else - goto imm16_ok; - } - - - if (cflags & C_IMM16) { - imm16_ok: - hs->flags |= F_IMM16; - hs->imm.imm16 = *(uint16_t *)p; - p += 2; - } - if (cflags & C_IMM8) { - hs->flags |= F_IMM8; - hs->imm.imm8 = *p++; - } - - if (cflags & C_REL32) { - rel32_ok: - hs->flags |= F_IMM32 | F_RELATIVE; - hs->imm.imm32 = *(uint32_t *)p; - p += 4; - } else if (cflags & C_REL8) { - hs->flags |= F_IMM8 | F_RELATIVE; - hs->imm.imm8 = *p++; - } - - disasm_done: - - if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { - hs->flags |= F_ERROR | F_ERROR_LENGTH; - hs->len = 15; - } - - return (unsigned int)hs->len; -} - -#endif // defined(_M_X64) || defined(__x86_64__) diff --git a/lib/minhook/hde/hde64.h b/lib/minhook/hde/hde64.h deleted file mode 100644 index ecbf4df9..00000000 --- a/lib/minhook/hde/hde64.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Hacker Disassembler Engine 64 - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - * hde64.h: C/C++ header file - * - */ - -#ifndef _HDE64_H_ -#define _HDE64_H_ - -/* stdint.h - C99 standard header - * http://en.wikipedia.org/wiki/stdint.h - * - * if your compiler doesn't contain "stdint.h" header (for - * example, Microsoft Visual C++), you can download file: - * http://www.azillionmonkeys.com/qed/pstdint.h - * and change next line to: - * #include "pstdint.h" - */ -#include "pstdint.h" - -#define F_MODRM 0x00000001 -#define F_SIB 0x00000002 -#define F_IMM8 0x00000004 -#define F_IMM16 0x00000008 -#define F_IMM32 0x00000010 -#define F_IMM64 0x00000020 -#define F_DISP8 0x00000040 -#define F_DISP16 0x00000080 -#define F_DISP32 0x00000100 -#define F_RELATIVE 0x00000200 -#define F_ERROR 0x00001000 -#define F_ERROR_OPCODE 0x00002000 -#define F_ERROR_LENGTH 0x00004000 -#define F_ERROR_LOCK 0x00008000 -#define F_ERROR_OPERAND 0x00010000 -#define F_PREFIX_REPNZ 0x01000000 -#define F_PREFIX_REPX 0x02000000 -#define F_PREFIX_REP 0x03000000 -#define F_PREFIX_66 0x04000000 -#define F_PREFIX_67 0x08000000 -#define F_PREFIX_LOCK 0x10000000 -#define F_PREFIX_SEG 0x20000000 -#define F_PREFIX_REX 0x40000000 -#define F_PREFIX_ANY 0x7f000000 - -#define PREFIX_SEGMENT_CS 0x2e -#define PREFIX_SEGMENT_SS 0x36 -#define PREFIX_SEGMENT_DS 0x3e -#define PREFIX_SEGMENT_ES 0x26 -#define PREFIX_SEGMENT_FS 0x64 -#define PREFIX_SEGMENT_GS 0x65 -#define PREFIX_LOCK 0xf0 -#define PREFIX_REPNZ 0xf2 -#define PREFIX_REPX 0xf3 -#define PREFIX_OPERAND_SIZE 0x66 -#define PREFIX_ADDRESS_SIZE 0x67 - -#pragma pack(push,1) - -typedef struct { - uint8_t len; - uint8_t p_rep; - uint8_t p_lock; - uint8_t p_seg; - uint8_t p_66; - uint8_t p_67; - uint8_t rex; - uint8_t rex_w; - uint8_t rex_r; - uint8_t rex_x; - uint8_t rex_b; - uint8_t opcode; - uint8_t opcode2; - uint8_t modrm; - uint8_t modrm_mod; - uint8_t modrm_reg; - uint8_t modrm_rm; - uint8_t sib; - uint8_t sib_scale; - uint8_t sib_index; - uint8_t sib_base; - union { - uint8_t imm8; - uint16_t imm16; - uint32_t imm32; - uint64_t imm64; - } imm; - union { - uint8_t disp8; - uint16_t disp16; - uint32_t disp32; - } disp; - uint32_t flags; -} hde64s; - -#pragma pack(pop) - -#ifdef __cplusplus -extern "C" { -#endif - -/* __cdecl */ -unsigned int hde64_disasm(const void *code, hde64s *hs); - -#ifdef __cplusplus -} -#endif - -#endif /* _HDE64_H_ */ diff --git a/lib/minhook/hde/pstdint.h b/lib/minhook/hde/pstdint.h deleted file mode 100644 index 84d82a01..00000000 --- a/lib/minhook/hde/pstdint.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include - -// Integer types for HDE. -typedef INT8 int8_t; -typedef INT16 int16_t; -typedef INT32 int32_t; -typedef INT64 int64_t; -typedef UINT8 uint8_t; -typedef UINT16 uint16_t; -typedef UINT32 uint32_t; -typedef UINT64 uint64_t; diff --git a/lib/minhook/hde/table32.h b/lib/minhook/hde/table32.h deleted file mode 100644 index 7b3e12e3..00000000 --- a/lib/minhook/hde/table32.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Hacker Disassembler Engine 32 C - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - */ - -#define C_NONE 0x00 -#define C_MODRM 0x01 -#define C_IMM8 0x02 -#define C_IMM16 0x04 -#define C_IMM_P66 0x10 -#define C_REL8 0x20 -#define C_REL32 0x40 -#define C_GROUP 0x80 -#define C_ERROR 0xff - -#define PRE_ANY 0x00 -#define PRE_NONE 0x01 -#define PRE_F2 0x02 -#define PRE_F3 0x04 -#define PRE_66 0x08 -#define PRE_67 0x10 -#define PRE_LOCK 0x20 -#define PRE_SEG 0x40 -#define PRE_ALL 0xff - -#define DELTA_OPCODES 0x4a -#define DELTA_FPU_REG 0xf1 -#define DELTA_FPU_MODRM 0xf8 -#define DELTA_PREFIXES 0x130 -#define DELTA_OP_LOCK_OK 0x1a1 -#define DELTA_OP2_LOCK_OK 0x1b9 -#define DELTA_OP_ONLY_MEM 0x1cb -#define DELTA_OP2_ONLY_MEM 0x1da - -unsigned char hde32_table[] = { - 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3, - 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f, - 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3, - 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa, - 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90, - 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d, - 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59, - 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, - 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0, - 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01, - 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11, - 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8, - 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca, - 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff, - 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03, - 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00, - 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00, - 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f, - 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a, - 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, - 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a, - 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06, - 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06, - 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, - 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08, - 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01, - 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba, - 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00, - 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00, - 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07, - 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf, - 0xe7,0x08,0x00,0xf0,0x02,0x00 -}; diff --git a/lib/minhook/hde/table64.h b/lib/minhook/hde/table64.h deleted file mode 100644 index 01d4541f..00000000 --- a/lib/minhook/hde/table64.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Hacker Disassembler Engine 64 C - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - */ - -#define C_NONE 0x00 -#define C_MODRM 0x01 -#define C_IMM8 0x02 -#define C_IMM16 0x04 -#define C_IMM_P66 0x10 -#define C_REL8 0x20 -#define C_REL32 0x40 -#define C_GROUP 0x80 -#define C_ERROR 0xff - -#define PRE_ANY 0x00 -#define PRE_NONE 0x01 -#define PRE_F2 0x02 -#define PRE_F3 0x04 -#define PRE_66 0x08 -#define PRE_67 0x10 -#define PRE_LOCK 0x20 -#define PRE_SEG 0x40 -#define PRE_ALL 0xff - -#define DELTA_OPCODES 0x4a -#define DELTA_FPU_REG 0xfd -#define DELTA_FPU_MODRM 0x104 -#define DELTA_PREFIXES 0x13c -#define DELTA_OP_LOCK_OK 0x1ae -#define DELTA_OP2_LOCK_OK 0x1c6 -#define DELTA_OP_ONLY_MEM 0x1d8 -#define DELTA_OP2_ONLY_MEM 0x1e7 - -unsigned char hde64_table[] = { - 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, - 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, - 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, - 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, - 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, - 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, - 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, - 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, - 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, - 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, - 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, - 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, - 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, - 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, - 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, - 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, - 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, - 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, - 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, - 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, - 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, - 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, - 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, - 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, - 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, - 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, - 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, - 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, - 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, - 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, - 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, - 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, - 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, - 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, - 0x00,0xf0,0x02,0x00 -}; diff --git a/lib/minhook/hook.c b/lib/minhook/hook.c deleted file mode 100644 index 793c1765..00000000 --- a/lib/minhook/hook.c +++ /dev/null @@ -1,889 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include - -#include "MinHook.h" -#include "buffer.h" -#include "trampoline.h" - -#ifndef ARRAYSIZE - #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) -#endif - -// Initial capacity of the HOOK_ENTRY buffer. -#define INITIAL_HOOK_CAPACITY 32 - -// Initial capacity of the thread IDs buffer. -#define INITIAL_THREAD_CAPACITY 128 - -// Special hook position values. -#define INVALID_HOOK_POS UINT_MAX -#define ALL_HOOKS_POS UINT_MAX - -// Freeze() action argument defines. -#define ACTION_DISABLE 0 -#define ACTION_ENABLE 1 -#define ACTION_APPLY_QUEUED 2 - -// Thread access rights for suspending/resuming threads. -#define THREAD_ACCESS \ - (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT) - -// Hook information. -typedef struct _HOOK_ENTRY -{ - LPVOID pTarget; // Address of the target function. - LPVOID pDetour; // Address of the detour or relay function. - LPVOID pTrampoline; // Address of the trampoline function. - UINT8 backup[8]; // Original prologue of the target function. - - UINT8 patchAbove : 1; // Uses the hot patch area. - UINT8 isEnabled : 1; // Enabled. - UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled. - - UINT nIP : 4; // Count of the instruction boundaries. - UINT8 oldIPs[8]; // Instruction boundaries of the target function. - UINT8 newIPs[8]; // Instruction boundaries of the trampoline function. -} HOOK_ENTRY, *PHOOK_ENTRY; - -// Suspended threads for Freeze()/Unfreeze(). -typedef struct _FROZEN_THREADS -{ - LPDWORD pItems; // Data heap - UINT capacity; // Size of allocated data heap, items - UINT size; // Actual number of data items -} FROZEN_THREADS, *PFROZEN_THREADS; - -//------------------------------------------------------------------------- -// Global Variables: -//------------------------------------------------------------------------- - -// Spin lock flag for EnterSpinLock()/LeaveSpinLock(). -volatile LONG g_isLocked = FALSE; - -// Private heap handle. If not NULL, this library is initialized. -HANDLE g_hHeap = NULL; - -// Hook entries. -struct -{ - PHOOK_ENTRY pItems; // Data heap - UINT capacity; // Size of allocated data heap, items - UINT size; // Actual number of data items -} g_hooks; - -//------------------------------------------------------------------------- -// Returns INVALID_HOOK_POS if not found. -static UINT FindHookEntry(LPVOID pTarget) -{ - UINT i; - for (i = 0; i < g_hooks.size; ++i) - { - if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget) - return i; - } - - return INVALID_HOOK_POS; -} - -//------------------------------------------------------------------------- -static PHOOK_ENTRY AddHookEntry() -{ - if (g_hooks.pItems == NULL) - { - g_hooks.capacity = INITIAL_HOOK_CAPACITY; - g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc( - g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY)); - if (g_hooks.pItems == NULL) - return NULL; - } - else if (g_hooks.size >= g_hooks.capacity) - { - PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( - g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY)); - if (p == NULL) - return NULL; - - g_hooks.capacity *= 2; - g_hooks.pItems = p; - } - - return &g_hooks.pItems[g_hooks.size++]; -} - -//------------------------------------------------------------------------- -static void DeleteHookEntry(UINT pos) -{ - if (pos < g_hooks.size - 1) - g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1]; - - g_hooks.size--; - - if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size) - { - PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( - g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY)); - if (p == NULL) - return; - - g_hooks.capacity /= 2; - g_hooks.pItems = p; - } -} - -//------------------------------------------------------------------------- -static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip) -{ - UINT i; - - if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL))) - return (DWORD_PTR)pHook->pTarget; - - for (i = 0; i < pHook->nIP; ++i) - { - if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i])) - return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]; - } - -#if defined(_M_X64) || defined(__x86_64__) - // Check relay function. - if (ip == (DWORD_PTR)pHook->pDetour) - return (DWORD_PTR)pHook->pTarget; -#endif - - return 0; -} - -//------------------------------------------------------------------------- -static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip) -{ - UINT i; - for (i = 0; i < pHook->nIP; ++i) - { - if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i])) - return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]; - } - - return 0; -} - -//------------------------------------------------------------------------- -static void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action) -{ - // If the thread suspended in the overwritten area, - // move IP to the proper address. - - CONTEXT c; -#if defined(_M_X64) || defined(__x86_64__) - DWORD64 *pIP = &c.Rip; -#else - DWORD *pIP = &c.Eip; -#endif - UINT count; - - c.ContextFlags = CONTEXT_CONTROL; - if (!GetThreadContext(hThread, &c)) - return; - - if (pos == ALL_HOOKS_POS) - { - pos = 0; - count = g_hooks.size; - } - else - { - count = pos + 1; - } - - for (; pos < count; ++pos) - { - PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; - BOOL enable; - DWORD_PTR ip; - - switch (action) - { - case ACTION_DISABLE: - enable = FALSE; - break; - - case ACTION_ENABLE: - enable = TRUE; - break; - - default: // ACTION_APPLY_QUEUED - enable = pHook->queueEnable; - break; - } - if (pHook->isEnabled == enable) - continue; - - if (enable) - ip = FindNewIP(pHook, *pIP); - else - ip = FindOldIP(pHook, *pIP); - - if (ip != 0) - { - *pIP = ip; - SetThreadContext(hThread, &c); - } - } -} - -//------------------------------------------------------------------------- -static VOID EnumerateThreads(PFROZEN_THREADS pThreads) -{ - HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - if (hSnapshot != INVALID_HANDLE_VALUE) - { - THREADENTRY32 te; - te.dwSize = sizeof(THREADENTRY32); - if (Thread32First(hSnapshot, &te)) - { - do - { - if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD)) - && te.th32OwnerProcessID == GetCurrentProcessId() - && te.th32ThreadID != GetCurrentThreadId()) - { - if (pThreads->pItems == NULL) - { - pThreads->capacity = INITIAL_THREAD_CAPACITY; - pThreads->pItems - = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD)); - if (pThreads->pItems == NULL) - break; - } - else if (pThreads->size >= pThreads->capacity) - { - LPDWORD p = (LPDWORD)HeapReAlloc( - g_hHeap, 0, pThreads->pItems, (pThreads->capacity * 2) * sizeof(DWORD)); - if (p == NULL) - break; - - pThreads->capacity *= 2; - pThreads->pItems = p; - } - pThreads->pItems[pThreads->size++] = te.th32ThreadID; - } - - te.dwSize = sizeof(THREADENTRY32); - } while (Thread32Next(hSnapshot, &te)); - } - CloseHandle(hSnapshot); - } -} - -//------------------------------------------------------------------------- -static VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action) -{ - pThreads->pItems = NULL; - pThreads->capacity = 0; - pThreads->size = 0; - EnumerateThreads(pThreads); - - if (pThreads->pItems != NULL) - { - UINT i; - for (i = 0; i < pThreads->size; ++i) - { - HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); - if (hThread != NULL) - { - SuspendThread(hThread); - ProcessThreadIPs(hThread, pos, action); - CloseHandle(hThread); - } - } - } -} - -//------------------------------------------------------------------------- -static VOID Unfreeze(PFROZEN_THREADS pThreads) -{ - if (pThreads->pItems != NULL) - { - UINT i; - for (i = 0; i < pThreads->size; ++i) - { - HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); - if (hThread != NULL) - { - ResumeThread(hThread); - CloseHandle(hThread); - } - } - - HeapFree(g_hHeap, 0, pThreads->pItems); - } -} - -//------------------------------------------------------------------------- -static MH_STATUS EnableHookLL(UINT pos, BOOL enable) -{ - PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; - DWORD oldProtect; - SIZE_T patchSize = sizeof(JMP_REL); - LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget; - - if (pHook->patchAbove) - { - pPatchTarget -= sizeof(JMP_REL); - patchSize += sizeof(JMP_REL_SHORT); - } - - if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) - return MH_ERROR_MEMORY_PROTECT; - - if (enable) - { - PJMP_REL pJmp = (PJMP_REL)pPatchTarget; - pJmp->opcode = 0xE9; - pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL))); - - if (pHook->patchAbove) - { - PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget; - pShortJmp->opcode = 0xEB; - pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL))); - } - } - else - { - if (pHook->patchAbove) - memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); - else - memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL)); - } - - VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect); - - // Just-in-case measure. - FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize); - - pHook->isEnabled = enable; - pHook->queueEnable = enable; - - return MH_OK; -} - -//------------------------------------------------------------------------- -static MH_STATUS EnableAllHooksLL(BOOL enable) -{ - MH_STATUS status = MH_OK; - UINT i, first = INVALID_HOOK_POS; - - for (i = 0; i < g_hooks.size; ++i) - { - if (g_hooks.pItems[i].isEnabled != enable) - { - first = i; - break; - } - } - - if (first != INVALID_HOOK_POS) - { - FROZEN_THREADS threads; - Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE); - - for (i = first; i < g_hooks.size; ++i) - { - if (g_hooks.pItems[i].isEnabled != enable) - { - status = EnableHookLL(i, enable); - if (status != MH_OK) - break; - } - } - - Unfreeze(&threads); - } - - return status; -} - -//------------------------------------------------------------------------- -static VOID EnterSpinLock(VOID) -{ - SIZE_T spinCount = 0; - - // Wait until the flag is FALSE. - while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE) - { - // No need to generate a memory barrier here, since InterlockedCompareExchange() - // generates a full memory barrier itself. - - // Prevent the loop from being too busy. - if (spinCount < 32) - Sleep(0); - else - Sleep(1); - - spinCount++; - } -} - -//------------------------------------------------------------------------- -static VOID LeaveSpinLock(VOID) -{ - // No need to generate a memory barrier here, since InterlockedExchange() - // generates a full memory barrier itself. - - InterlockedExchange(&g_isLocked, FALSE); -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_Initialize(VOID) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap == NULL) - { - g_hHeap = HeapCreate(0, 0, 0); - if (g_hHeap != NULL) - { - // Initialize the internal function buffer. - InitializeBuffer(); - } - else - { - status = MH_ERROR_MEMORY_ALLOC; - } - } - else - { - status = MH_ERROR_ALREADY_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_Uninitialize(VOID) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - status = EnableAllHooksLL(FALSE); - if (status == MH_OK) - { - // Free the internal function buffer. - - // HeapFree is actually not required, but some tools detect a false - // memory leak without HeapFree. - - UninitializeBuffer(); - - HeapFree(g_hHeap, 0, g_hooks.pItems); - HeapDestroy(g_hHeap); - - g_hHeap = NULL; - - g_hooks.pItems = NULL; - g_hooks.capacity = 0; - g_hooks.size = 0; - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour)) - { - UINT pos = FindHookEntry(pTarget); - if (pos == INVALID_HOOK_POS) - { - LPVOID pBuffer = AllocateBuffer(pTarget); - if (pBuffer != NULL) - { - TRAMPOLINE ct; - - ct.pTarget = pTarget; - ct.pDetour = pDetour; - ct.pTrampoline = pBuffer; - if (CreateTrampolineFunction(&ct)) - { - PHOOK_ENTRY pHook = AddHookEntry(); - if (pHook != NULL) - { - pHook->pTarget = ct.pTarget; -#if defined(_M_X64) || defined(__x86_64__) - pHook->pDetour = ct.pRelay; -#else - pHook->pDetour = ct.pDetour; -#endif - pHook->pTrampoline = ct.pTrampoline; - pHook->patchAbove = ct.patchAbove; - pHook->isEnabled = FALSE; - pHook->queueEnable = FALSE; - pHook->nIP = ct.nIP; - memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs)); - memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs)); - - // Back up the target function. - - if (ct.patchAbove) - { - memcpy( - pHook->backup, - (LPBYTE)pTarget - sizeof(JMP_REL), - sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); - } - else - { - memcpy(pHook->backup, pTarget, sizeof(JMP_REL)); - } - - if (ppOriginal != NULL) - *ppOriginal = pHook->pTrampoline; - } - else - { - status = MH_ERROR_MEMORY_ALLOC; - } - } - else - { - status = MH_ERROR_UNSUPPORTED_FUNCTION; - } - - if (status != MH_OK) - { - FreeBuffer(pBuffer); - } - } - else - { - status = MH_ERROR_MEMORY_ALLOC; - } - } - else - { - status = MH_ERROR_ALREADY_CREATED; - } - } - else - { - status = MH_ERROR_NOT_EXECUTABLE; - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - UINT pos = FindHookEntry(pTarget); - if (pos != INVALID_HOOK_POS) - { - if (g_hooks.pItems[pos].isEnabled) - { - FROZEN_THREADS threads; - Freeze(&threads, pos, ACTION_DISABLE); - - status = EnableHookLL(pos, FALSE); - - Unfreeze(&threads); - } - - if (status == MH_OK) - { - FreeBuffer(g_hooks.pItems[pos].pTrampoline); - DeleteHookEntry(pos); - } - } - else - { - status = MH_ERROR_NOT_CREATED; - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - if (pTarget == MH_ALL_HOOKS) - { - status = EnableAllHooksLL(enable); - } - else - { - FROZEN_THREADS threads; - UINT pos = FindHookEntry(pTarget); - if (pos != INVALID_HOOK_POS) - { - if (g_hooks.pItems[pos].isEnabled != enable) - { - Freeze(&threads, pos, ACTION_ENABLE); - - status = EnableHookLL(pos, enable); - - Unfreeze(&threads); - } - else - { - status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED; - } - } - else - { - status = MH_ERROR_NOT_CREATED; - } - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget) -{ - return EnableHook(pTarget, TRUE); -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget) -{ - return EnableHook(pTarget, FALSE); -} - -//------------------------------------------------------------------------- -static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - if (pTarget == MH_ALL_HOOKS) - { - UINT i; - for (i = 0; i < g_hooks.size; ++i) - g_hooks.pItems[i].queueEnable = queueEnable; - } - else - { - UINT pos = FindHookEntry(pTarget); - if (pos != INVALID_HOOK_POS) - { - g_hooks.pItems[pos].queueEnable = queueEnable; - } - else - { - status = MH_ERROR_NOT_CREATED; - } - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget) -{ - return QueueHook(pTarget, TRUE); -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget) -{ - return QueueHook(pTarget, FALSE); -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_ApplyQueued(VOID) -{ - MH_STATUS status = MH_OK; - UINT i, first = INVALID_HOOK_POS; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - for (i = 0; i < g_hooks.size; ++i) - { - if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable) - { - first = i; - break; - } - } - - if (first != INVALID_HOOK_POS) - { - FROZEN_THREADS threads; - Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED); - - for (i = first; i < g_hooks.size; ++i) - { - PHOOK_ENTRY pHook = &g_hooks.pItems[i]; - if (pHook->isEnabled != pHook->queueEnable) - { - status = EnableHookLL(i, pHook->queueEnable); - if (status != MH_OK) - break; - } - } - - Unfreeze(&threads); - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_CreateHookApiEx( - LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, - LPVOID *ppOriginal, LPVOID *ppTarget) -{ - HMODULE hModule; - LPVOID pTarget; - - hModule = GetModuleHandleW(pszModule); - if (hModule == NULL) - return MH_ERROR_MODULE_NOT_FOUND; - - pTarget = (LPVOID)GetProcAddress(hModule, pszProcName); - if (pTarget == NULL) - return MH_ERROR_FUNCTION_NOT_FOUND; - - if(ppTarget != NULL) - *ppTarget = pTarget; - - return MH_CreateHook(pTarget, pDetour, ppOriginal); -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_CreateHookApi( - LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal) -{ - return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL); -} - -//------------------------------------------------------------------------- -const char * WINAPI MH_StatusToString(MH_STATUS status) -{ -#define MH_ST2STR(x) \ - case x: \ - return #x; - - switch (status) { - MH_ST2STR(MH_UNKNOWN) - MH_ST2STR(MH_OK) - MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED) - MH_ST2STR(MH_ERROR_NOT_INITIALIZED) - MH_ST2STR(MH_ERROR_ALREADY_CREATED) - MH_ST2STR(MH_ERROR_NOT_CREATED) - MH_ST2STR(MH_ERROR_ENABLED) - MH_ST2STR(MH_ERROR_DISABLED) - MH_ST2STR(MH_ERROR_NOT_EXECUTABLE) - MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION) - MH_ST2STR(MH_ERROR_MEMORY_ALLOC) - MH_ST2STR(MH_ERROR_MEMORY_PROTECT) - MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND) - MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND) - } - -#undef MH_ST2STR - - return "(unknown)"; -} diff --git a/lib/minhook/trampoline.c b/lib/minhook/trampoline.c deleted file mode 100644 index ac37f0f1..00000000 --- a/lib/minhook/trampoline.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#ifndef ARRAYSIZE - #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) -#endif - -#if defined(_M_X64) || defined(__x86_64__) - #include "./hde/hde64.h" - typedef hde64s HDE; - #define HDE_DISASM(code, hs) hde64_disasm(code, hs) -#else - #include "./hde/hde32.h" - typedef hde32s HDE; - #define HDE_DISASM(code, hs) hde32_disasm(code, hs) -#endif - -#include "trampoline.h" -#include "buffer.h" - -// Maximum size of a trampoline function. -#if defined(_M_X64) || defined(__x86_64__) - #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS)) -#else - #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE -#endif - -//------------------------------------------------------------------------- -static BOOL IsCodePadding(LPBYTE pInst, UINT size) -{ - UINT i; - - if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC) - return FALSE; - - for (i = 1; i < size; ++i) - { - if (pInst[i] != pInst[0]) - return FALSE; - } - return TRUE; -} - -//------------------------------------------------------------------------- -BOOL CreateTrampolineFunction(PTRAMPOLINE ct) -{ -#if defined(_M_X64) || defined(__x86_64__) - CALL_ABS call = { - 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8] - 0xEB, 0x08, // EB 08: JMP +10 - 0x0000000000000000ULL // Absolute destination address - }; - JMP_ABS jmp = { - 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] - 0x0000000000000000ULL // Absolute destination address - }; - JCC_ABS jcc = { - 0x70, 0x0E, // 7* 0E: J** +16 - 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] - 0x0000000000000000ULL // Absolute destination address - }; -#else - CALL_REL call = { - 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx - 0x00000000 // Relative destination address - }; - JMP_REL jmp = { - 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx - 0x00000000 // Relative destination address - }; - JCC_REL jcc = { - 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx - 0x00000000 // Relative destination address - }; -#endif - - UINT8 oldPos = 0; - UINT8 newPos = 0; - ULONG_PTR jmpDest = 0; // Destination address of an internal jump. - BOOL finished = FALSE; // Is the function completed? -#if defined(_M_X64) || defined(__x86_64__) - UINT8 instBuf[16]; -#endif - - ct->patchAbove = FALSE; - ct->nIP = 0; - - do - { - HDE hs; - UINT copySize; - LPVOID pCopySrc; - ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos; - ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos; - - copySize = HDE_DISASM((LPVOID)pOldInst, &hs); - if (hs.flags & F_ERROR) - return FALSE; - - pCopySrc = (LPVOID)pOldInst; - if (oldPos >= sizeof(JMP_REL)) - { - // The trampoline function is long enough. - // Complete the function with the jump to the target function. -#if defined(_M_X64) || defined(__x86_64__) - jmp.address = pOldInst; -#else - jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp))); -#endif - pCopySrc = &jmp; - copySize = sizeof(jmp); - - finished = TRUE; - } -#if defined(_M_X64) || defined(__x86_64__) - else if ((hs.modrm & 0xC7) == 0x05) - { - // Instructions using RIP relative addressing. (ModR/M = 00???101B) - - // Modify the RIP relative address. - PUINT32 pRelAddr; - - // Avoid using memcpy to reduce the footprint. -#ifndef _MSC_VER - memcpy(instBuf, (LPBYTE)pOldInst, copySize); -#else - __movsb(instBuf, (LPBYTE)pOldInst, copySize); -#endif - pCopySrc = instBuf; - - // Relative address is stored at (instruction length - immediate value length - 4). - pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4); - *pRelAddr - = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len)); - - // Complete the function if JMP (FF /4). - if (hs.opcode == 0xFF && hs.modrm_reg == 4) - finished = TRUE; - } -#endif - else if (hs.opcode == 0xE8) - { - // Direct relative CALL - ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32; -#if defined(_M_X64) || defined(__x86_64__) - call.address = dest; -#else - call.operand = (UINT32)(dest - (pNewInst + sizeof(call))); -#endif - pCopySrc = &call; - copySize = sizeof(call); - } - else if ((hs.opcode & 0xFD) == 0xE9) - { - // Direct relative JMP (EB or E9) - ULONG_PTR dest = pOldInst + hs.len; - - if (hs.opcode == 0xEB) // isShort jmp - dest += (INT8)hs.imm.imm8; - else - dest += (INT32)hs.imm.imm32; - - // Simply copy an internal jump. - if ((ULONG_PTR)ct->pTarget <= dest - && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) - { - if (jmpDest < dest) - jmpDest = dest; - } - else - { -#if defined(_M_X64) || defined(__x86_64__) - jmp.address = dest; -#else - jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp))); -#endif - pCopySrc = &jmp; - copySize = sizeof(jmp); - - // Exit the function If it is not in the branch - finished = (pOldInst >= jmpDest); - } - } - else if ((hs.opcode & 0xF0) == 0x70 - || (hs.opcode & 0xFC) == 0xE0 - || (hs.opcode2 & 0xF0) == 0x80) - { - // Direct relative Jcc - ULONG_PTR dest = pOldInst + hs.len; - - if ((hs.opcode & 0xF0) == 0x70 // Jcc - || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ - dest += (INT8)hs.imm.imm8; - else - dest += (INT32)hs.imm.imm32; - - // Simply copy an internal jump. - if ((ULONG_PTR)ct->pTarget <= dest - && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) - { - if (jmpDest < dest) - jmpDest = dest; - } - else if ((hs.opcode & 0xFC) == 0xE0) - { - // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported. - return FALSE; - } - else - { - UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F); -#if defined(_M_X64) || defined(__x86_64__) - // Invert the condition in x64 mode to simplify the conditional jump logic. - jcc.opcode = 0x71 ^ cond; - jcc.address = dest; -#else - jcc.opcode1 = 0x80 | cond; - jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc))); -#endif - pCopySrc = &jcc; - copySize = sizeof(jcc); - } - } - else if ((hs.opcode & 0xFE) == 0xC2) - { - // RET (C2 or C3) - - // Complete the function if not in a branch. - finished = (pOldInst >= jmpDest); - } - - // Can't alter the instruction length in a branch. - if (pOldInst < jmpDest && copySize != hs.len) - return FALSE; - - // Trampoline function is too large. - if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE) - return FALSE; - - // Trampoline function has too many instructions. - if (ct->nIP >= ARRAYSIZE(ct->oldIPs)) - return FALSE; - - ct->oldIPs[ct->nIP] = oldPos; - ct->newIPs[ct->nIP] = newPos; - ct->nIP++; - - // Avoid using memcpy to reduce the footprint. -#ifndef _MSC_VER - memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); -#else - __movsb((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); -#endif - newPos += copySize; - oldPos += hs.len; - } - while (!finished); - - // Is there enough place for a long jump? - if (oldPos < sizeof(JMP_REL) - && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos)) - { - // Is there enough place for a short jump? - if (oldPos < sizeof(JMP_REL_SHORT) - && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos)) - { - return FALSE; - } - - // Can we place the long jump above the function? - if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL))) - return FALSE; - - if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL))) - return FALSE; - - ct->patchAbove = TRUE; - } - -#if defined(_M_X64) || defined(__x86_64__) - // Create a relay function. - jmp.address = (ULONG_PTR)ct->pDetour; - - ct->pRelay = (LPBYTE)ct->pTrampoline + newPos; - memcpy(ct->pRelay, &jmp, sizeof(jmp)); -#endif - - return TRUE; -} diff --git a/lib/minhook/trampoline.h b/lib/minhook/trampoline.h deleted file mode 100644 index bdffdac0..00000000 --- a/lib/minhook/trampoline.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#pragma pack(push, 1) - -// Structs for writing x86/x64 instructions. - -// 8-bit relative jump. -typedef struct _JMP_REL_SHORT -{ - UINT8 opcode; // EB xx: JMP +2+xx - UINT8 operand; -} JMP_REL_SHORT, *PJMP_REL_SHORT; - -// 32-bit direct relative jump/call. -typedef struct _JMP_REL -{ - UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx - UINT32 operand; // Relative destination address -} JMP_REL, *PJMP_REL, CALL_REL; - -// 64-bit indirect absolute jump. -typedef struct _JMP_ABS -{ - UINT8 opcode0; // FF25 00000000: JMP [+6] - UINT8 opcode1; - UINT32 dummy; - UINT64 address; // Absolute destination address -} JMP_ABS, *PJMP_ABS; - -// 64-bit indirect absolute call. -typedef struct _CALL_ABS -{ - UINT8 opcode0; // FF15 00000002: CALL [+6] - UINT8 opcode1; - UINT32 dummy0; - UINT8 dummy1; // EB 08: JMP +10 - UINT8 dummy2; - UINT64 address; // Absolute destination address -} CALL_ABS; - -// 32-bit direct relative conditional jumps. -typedef struct _JCC_REL -{ - UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx - UINT8 opcode1; - UINT32 operand; // Relative destination address -} JCC_REL; - -// 64bit indirect absolute conditional jumps that x64 lacks. -typedef struct _JCC_ABS -{ - UINT8 opcode; // 7* 0E: J** +16 - UINT8 dummy0; - UINT8 dummy1; // FF25 00000000: JMP [+6] - UINT8 dummy2; - UINT32 dummy3; - UINT64 address; // Absolute destination address -} JCC_ABS; - -#pragma pack(pop) - -typedef struct _TRAMPOLINE -{ - LPVOID pTarget; // [In] Address of the target function. - LPVOID pDetour; // [In] Address of the detour function. - LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function. - -#if defined(_M_X64) || defined(__x86_64__) - LPVOID pRelay; // [Out] Address of the relay function. -#endif - BOOL patchAbove; // [Out] Should use the hot patch area? - UINT nIP; // [Out] Number of the instruction boundaries. - UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function. - UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function. -} TRAMPOLINE, *PTRAMPOLINE; - -BOOL CreateTrampolineFunction(PTRAMPOLINE ct); diff --git a/makefile b/makefile index 5e56ec68..cdbb25c9 100644 --- a/makefile +++ b/makefile @@ -20,7 +20,7 @@ SRCS+=$(wildcard $(SDIR)Utils/*.cpp) OBJS=$(patsubst $(SDIR)%.cpp, $(ODIR)%.o, $(SRCS)) CC=g++ -STFU=-Wno-unused-function -Wno-unused-variable -Wno-parentheses -Wno-unknown-pragmas +STFU=-Wno-unused-function -Wno-unused-variable -Wno-parentheses -Wno-unknown-pragmas -Wno-register CFLAGS=-std=c++17 -m32 -fPIC -static-libstdc++ -shared -Wall -s $(STFU) -I$(SDIR) #CFLAGS+=-D _DEBUG EXPORT=cp -fu diff --git a/src/Cheats.cpp b/src/Cheats.cpp index b0c01012..1bcccfaa 100644 --- a/src/Cheats.cpp +++ b/src/Cheats.cpp @@ -3,20 +3,6 @@ #include #include "Features/Cvars.hpp" -#include "Features/Hud/Hud.hpp" -#include "Features/Hud/InspectionHud.hpp" -#include "Features/Hud/SpeedrunHud.hpp" -#include "Features/Imitator.hpp" -#include "Features/Listener.hpp" -#include "Features/ReplaySystem/ReplayPlayer.hpp" -#include "Features/ReplaySystem/ReplayProvider.hpp" -#include "Features/Routing/EntityInspector.hpp" -#include "Features/Speedrun/SpeedrunTimer.hpp" -#include "Features/Tas/AutoStrafer.hpp" -#include "Features/Tas/CommandQueuer.hpp" -#include "Features/Tas/TasTools.hpp" -#include "Features/Timer/Timer.hpp" -#include "Features/WorkshopList.hpp" #include "Modules/Client.hpp" #include "Modules/Console.hpp" @@ -26,17 +12,31 @@ #include "Game.hpp" #include "Offsets.hpp" -Variable sar_autorecord("sar_autorecord", "0", "Enables automatic demo recording.\n"); -Variable sar_autojump("sar_autojump", "0", "Enables automatic jumping on the server.\n"); -Variable sar_jumpboost("sar_jumpboost", "0", 0, "Enables special game movement on the server.\n" - "0 = Default,\n" - "1 = Orange Box Engine,\n" - "2 = Pre-OBE.\n"); -Variable sar_aircontrol("sar_aircontrol", "0", 0, "Enables more air-control on the server.\n"); -Variable sar_duckjump("sar_duckjump", "0", "Allows duck-jumping even when fully crouched, similar to prevent_crouch_jump.\n"); -Variable sar_disable_challenge_stats_hud("sar_disable_challenge_stats_hud", "0", "Disables opening the challenge mode stats HUD.\n"); -Variable sar_disable_steam_pause("sar_disable_steam_pause", "0", "Prevents pauses from steam overlay.\n"); -Variable sar_disable_no_focus_sleep("sar_disable_no_focus_sleep", "0", "Does not yield the CPU when game is not focused.\n"); +Variable sar_autorecord("sar_autorecord", "0", + "Enables automatic demo recording.\n"); +Variable sar_autojump("sar_autojump", "0", + "Enables automatic jumping on the server.\n"); +Variable sar_jumpboost("sar_jumpboost", "0", 0, + "Enables special game movement on the server.\n" + "0 = Default,\n" + "1 = Orange Box Engine,\n" + "2 = Pre-OBE.\n", + SourceGame_Portal2Engine); +Variable sar_aircontrol("sar_aircontrol", "0", 0, + "Enables more air-control on the server.\n", + SourceGame_Portal2Engine); +Variable sar_duckjump("sar_duckjump", "0", + "Allows duck-jumping even when fully crouched, similar to prevent_crouch_jump.\n", + SourceGame_Portal2Engine); +Variable sar_disable_challenge_stats_hud("sar_disable_challenge_stats_hud", "0", + "Disables opening the challenge mode stats HUD.\n", + SourceGame_Portal2); +Variable sar_disable_steam_pause("sar_disable_steam_pause", "0", + "Prevents pauses from steam overlay.\n", + SourceGame_Portal2Game); +Variable sar_disable_no_focus_sleep("sar_disable_no_focus_sleep", "0", + "Does not yield the CPU when game is not focused.\n", + SourceGame_Portal2Engine); Variable sv_laser_cube_autoaim; Variable ui_loadingscreen_transition_time; @@ -48,10 +48,10 @@ Variable hide_gun_when_holding; void IN_BhopDown(const CCommand& args) { client->KeyDown(client->in_jump, (args.ArgC() > 1) ? args[1] : nullptr); } void IN_BhopUp(const CCommand& args) { client->KeyUp(client->in_jump, (args.ArgC() > 1) ? args[1] : nullptr); } -Command startbhop("+bhop", IN_BhopDown, "Client sends a key-down event for the in_jump state.\n"); -Command endbhop("-bhop", IN_BhopUp, "Client sends a key-up event for the in_jump state.\n"); +Command startbhop("+bhop", IN_BhopDown, "Client sends a key-down event for the in_jump state.\n", SourceGame_TheStanleyParable); +Command endbhop("-bhop", IN_BhopUp, "Client sends a key-up event for the in_jump state.\n", SourceGame_TheStanleyParable); -CON_COMMAND(sar_anti_anti_cheat, "Sets sv_cheats to 1.\n") +CON_COMMAND_U(sar_anti_anti_cheat, "Sets sv_cheats to 1.\n", SourceGame_TheStanleyParable) { sv_cheats.ThisPtr()->m_nValue = 1; } @@ -61,14 +61,6 @@ DECLARE_AUTOCOMPLETION_FUNCTION(map, "maps", bsp); DECLARE_AUTOCOMPLETION_FUNCTION(changelevel, "maps", bsp); DECLARE_AUTOCOMPLETION_FUNCTION(changelevel2, "maps", bsp); -// P2 only -CON_COMMAND(sar_togglewait, "Enables or disables \"wait\" for the command buffer.\n") -{ - auto state = !*engine->m_bWaitEnabled; - *engine->m_bWaitEnabled = *engine->m_bWaitEnabled2 = state; - console->Print("%s wait!\n", (state) ? "Enabled" : "Disabled"); -} - // P2, INFRA and HL2 only #ifdef _WIN32 #define TRACE_SHUTDOWN_PATTERN "6A 00 68 ? ? ? ? E8 ? ? ? ? E8 ? ? ? ? " @@ -79,13 +71,13 @@ CON_COMMAND(sar_togglewait, "Enables or disables \"wait\" for the command buffer #define TRACE_SHUTDOWN_OFFSET1 11 #define TRACE_SHUTDOWN_OFFSET2 10 #endif -CON_COMMAND(sar_delete_alias_cmds, "Deletes all alias commands.\n") +CON_COMMAND_U(sar_delete_alias_cmds, "Deletes all alias commands.\n", SourceGame_Portal2Game | SourceGame_HalfLife2Engine) { using _Cmd_Shutdown = int (*)(); static _Cmd_Shutdown Cmd_Shutdown = nullptr; if (!Cmd_Shutdown) { - auto result = Memory::MultiScan(engine->Name(), TRACE_SHUTDOWN_PATTERN, TRACE_SHUTDOWN_OFFSET1); + auto result = Memory::MultiScan(engine->filename, TRACE_SHUTDOWN_PATTERN, TRACE_SHUTDOWN_OFFSET1); if (!result.empty()) { for (auto const& addr : result) { if (!std::strcmp(*reinterpret_cast(addr), "Cmd_Shutdown()")) { @@ -117,62 +109,11 @@ void Cheats::Init() Command::ActivateAutoCompleteFile("changelevel2", changelevel2_CompletionFunc); } - auto s3 = SourceGame_Portal2Game | SourceGame_Portal; - - sar_jumpboost.UniqueFor(SourceGame_Portal2Engine); - sar_aircontrol.UniqueFor(SourceGame_Portal2Engine); - //sar_hud_portals.UniqueFor(SourceGame_Portal2Game | SourceGame_Portal); - sar_disable_challenge_stats_hud.UniqueFor(SourceGame_Portal2); - sar_disable_steam_pause.UniqueFor(SourceGame_Portal2Game); - sar_debug_listener.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag); - sar_sr_hud.UniqueFor(s3); - sar_sr_hud_x.UniqueFor(s3); - sar_sr_hud_y.UniqueFor(s3); - sar_sr_hud_font_color.UniqueFor(s3); - sar_sr_hud_font_index.UniqueFor(s3); - sar_speedrun_autostart.UniqueFor(s3); - sar_speedrun_autostop.UniqueFor(s3); - sar_speedrun_standard.UniqueFor(s3); - sar_duckjump.UniqueFor(SourceGame_Portal2Engine); - sar_replay_viewmode.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag); - sar_mimic.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag); - sar_tas_ss_forceuser.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag); - //sar_hud_pause_timer.UniqueFor(s3); - sar_speedrun_time_pauses.UniqueFor(s3); - sar_speedrun_smartsplit.UniqueFor(s3); - sar_disable_no_focus_sleep.UniqueFor(SourceGame_Portal2Engine); - - startbhop.UniqueFor(SourceGame_TheStanleyParable); - endbhop.UniqueFor(SourceGame_TheStanleyParable); - sar_anti_anti_cheat.UniqueFor(SourceGame_TheStanleyParable); - sar_workshop.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag); - sar_workshop_update.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag); - sar_workshop_list.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag); - sar_speedrun_result.UniqueFor(s3); - sar_speedrun_export.UniqueFor(s3); - sar_speedrun_export_pb.UniqueFor(s3); - sar_speedrun_import.UniqueFor(s3); - sar_speedrun_category.UniqueFor(s3); - sar_speedrun_offset.UniqueFor(s3); - sar_speedrun_start.UniqueFor(s3); - sar_speedrun_stop.UniqueFor(s3); - sar_speedrun_split.UniqueFor(s3); - sar_speedrun_pause.UniqueFor(s3); - sar_speedrun_resume.UniqueFor(s3); - sar_speedrun_reset.UniqueFor(s3); - sar_togglewait.UniqueFor(SourceGame_Portal2Game | SourceGame_INFRA); - sar_tas_ss.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag); - sar_delete_alias_cmds.UniqueFor(SourceGame_Portal2Game | SourceGame_HalfLife2Engine); - sar_tas_strafe.UniqueFor(SourceGame_Portal2Engine); - sar_tas_strafe_vectorial.UniqueFor(SourceGame_Portal2Engine); - startautostrafe.UniqueFor(SourceGame_Portal2Engine); - endautostrafe.UniqueFor(SourceGame_Portal2Engine); - sar_dump_events.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag); - - cvars->Unlock(); - - Variable::RegisterAll(); - Command::RegisterAll(); + if (cvars) { + cvars->Unlock(); + } + + CommandBase::RegisterAll(); } void Cheats::Shutdown() { @@ -182,8 +123,9 @@ void Cheats::Shutdown() Command::DectivateAutoCompleteFile("changelevel2"); } - cvars->Lock(); + if (cvars) { + cvars->Lock(); + } - Variable::UnregisterAll(); - Command::UnregisterAll(); + CommandBase::UnregisterAll(); } diff --git a/src/Cheats.hpp b/src/Cheats.hpp index 85fe40b5..da35a35e 100644 --- a/src/Cheats.hpp +++ b/src/Cheats.hpp @@ -26,8 +26,3 @@ extern Variable hide_gun_when_holding; extern Command startbhop; extern Command endbhop; extern Command sar_anti_anti_cheat; -extern Command sar_togglewait; - -extern DECL_DECLARE_AUTOCOMPLETION_FUNCTION(map); -extern DECL_DECLARE_AUTOCOMPLETION_FUNCTION(changelevel); -extern DECL_DECLARE_AUTOCOMPLETION_FUNCTION(changelevel2); diff --git a/src/Command.cpp b/src/Command.cpp index f8904a22..610e2e81 100644 --- a/src/Command.cpp +++ b/src/Command.cpp @@ -1,49 +1,70 @@ #include "Command.hpp" #include +#include +#include "Modules/Console.hpp" +#include "Modules/Module.hpp" #include "Modules/Tier1.hpp" #include "Game.hpp" #include "SAR.hpp" -std::vector& Command::GetList() +std::vector& CommandBase::GetList() { - static std::vector list; + static std::vector list; return list; } -Command::Command() +CommandBase::CommandBase(int version) : ptr(nullptr) - , version(SourceGame_Unknown) + , version(version) , isRegistered(false) , isReference(false) { } -Command::~Command() +CommandBase::~CommandBase() { if (!this->isReference) { - SAFE_DELETE(this->ptr) + sdelete(this->ptr) } } -Command::Command(const char* name) +int CommandBase::RegisterAll() { - this->ptr = reinterpret_cast(tier1->FindCommandBase(tier1->g_pCVar->ThisPtr(), name)); - this->isReference = true; + auto result = 0; + for (const auto& command : CommandBase::GetList()) { + if (command->version != SourceGame_Unknown && !sar.game->Is(command->version)) { + continue; + } + command->Register(); + ++result; + } + return result; } -Command::Command(const char* pName, _CommandCallback callback, const char* pHelpString, int flags, _CommandCompletionCallback completionFunc) +void CommandBase::UnregisterAll() { - this->ptr = new ConCommand(pName, callback, pHelpString, flags, completionFunc); - - Command::GetList().push_back(this); + for (const auto& command : CommandBase::GetList()) { + command->Unregister(); + } } -ConCommand* Command::ThisPtr() + +Command::Command(const char* name) + : CommandBase(SourceGame_Unknown) { - return this->ptr; + this->ptr = tier1->FindCommandBase(tier1->g_pCVar->ThisPtr(), name); + if (!this->ptr) { + throw std::runtime_error("command " + std::string(name) + " not found"); + } + + this->isReference = true; } -void Command::UniqueFor(int version) +Command::Command(const char* pName, _CommandCallback callback, const char* pHelpString, int version, int flags, + _CommandCompletionCallback completionFunc) + : CommandBase(version) { - this->version = version; + this->ptr = new ConCommand(pName, callback, pHelpString, flags, completionFunc); + + CommandBase::GetList().push_back(this); } void Command::Register() { @@ -61,74 +82,69 @@ void Command::Unregister() } this->isRegistered = false; } -bool Command::operator!() -{ - return this->ptr == nullptr; -} -int Command::RegisterAll() +bool Command::ActivateAutoCompleteFile(const char* name, _CommandCompletionCallback callback) { - auto result = 0; - for (const auto& command : Command::GetList()) { - if (command->version != SourceGame_Unknown && !sar.game->Is(command->version)) { - continue; - } - command->Register(); - ++result; + auto cc = Command(name); + if (!!cc) { + auto ptr = cc.ThisPtr(); + ptr->m_bHasCompletionCallback = true; + ptr->m_fnCompletionCallback = callback; + return true; } - return result; + return false; } -void Command::UnregisterAll() +bool Command::DectivateAutoCompleteFile(const char* name) { - for (const auto& command : Command::GetList()) { - command->Unregister(); + auto cc = Command(name); + if (!!cc) { + auto ptr = cc.ThisPtr(); + ptr->m_bHasCompletionCallback = false; + ptr->m_fnCompletionCallback = nullptr; + return true; } + return false; } -Command* Command::Find(const char* name) + +CommandHook::CommandHook(const char* target, _CommandCallback* original, _CommandCallback detour) + : target(target) + , original(original) + , detour(detour) + , isRegistered(false) + , isHooked(false) { - for (const auto& command : Command::GetList()) { - if (!std::strcmp(command->ThisPtr()->m_pszName, name)) { - return command; - } - } - return nullptr; } - -bool Command::Hook(const char* name, _CommandCallback detour, _CommandCallback& original) +void CommandHook::Register(Module* mod) { - auto cc = Command(name); - if (!!cc) { - original = cc.ThisPtr()->m_fnCommandCallback; - cc.ThisPtr()->m_fnCommandCallback = detour; - return true; + if (!this->isRegistered) { + mod->cmdHooks.push_back(this); + } else { + console->Warning("CommandHook %s already registered!\n", this->target); } - return false; } -bool Command::Unhook(const char* name, _CommandCallback original) +void CommandHook::Unregister() { - auto cc = Command(name); - if (!!cc && original) { - cc.ThisPtr()->m_fnCommandCallback = original; - return true; + if (this->isRegistered) { + this->isRegistered = false; + } else { + console->Warning("CommandHook %s already unregistered!\n", this->target); } - return false; } -bool Command::ActivateAutoCompleteFile(const char* name, _CommandCompletionCallback callback) +void CommandHook::Hook() { - auto cc = Command(name); - if (!!cc) { - cc.ThisPtr()->m_bHasCompletionCallback = true; - cc.ThisPtr()->m_fnCompletionCallback = callback; - return true; + auto cmd = Command(this->target); + if (!!cmd) { + *this->original = cmd.ThisPtr()->m_fnCommandCallback; + cmd.ThisPtr()->m_fnCommandCallback = this->detour; + } else { + console->Warning("CommandHook failed to find command %s!\n", this->target); } - return false; } -bool Command::DectivateAutoCompleteFile(const char* name) +void CommandHook::Unhook() { - auto cc = Command(name); - if (!!cc) { - cc.ThisPtr()->m_bHasCompletionCallback = false; - cc.ThisPtr()->m_fnCompletionCallback = nullptr; - return true; + auto cmd = Command(this->target); + if (!!cmd) { + cmd.ThisPtr()->m_fnCommandCallback = *this->original; + } else { + console->Warning("CommandHook failed to find command %s!\n", this->target); } - return false; } diff --git a/src/Command.hpp b/src/Command.hpp index 21e7225e..2a4bca37 100644 --- a/src/Command.hpp +++ b/src/Command.hpp @@ -4,11 +4,13 @@ #include #include +#include "Modules/Module.hpp" + #include "Game.hpp" -class Command { -private: - ConCommand* ptr; +class CommandBase { +protected: + ConCommandBase* ptr; public: int version; @@ -16,46 +18,86 @@ class Command { bool isReference; public: - static std::vector& GetList(); + static std::vector& GetList(); public: - Command(); - ~Command(); - Command(const char* name); - Command(const char* pName, _CommandCallback callback, const char* pHelpString, int flags = 0, - _CommandCompletionCallback completionFunc = nullptr); + CommandBase(int version); + ~CommandBase(); - ConCommand* ThisPtr(); + virtual bool IsCommand() = 0; + virtual void Register() = 0; + virtual void Unregister() = 0; - void UniqueFor(int version); - void Register(); - void Unregister(); + inline ConCommandBase* ThisPtr() { return this->ptr; } - bool operator!(); + inline bool operator!() { return this->ptr == nullptr; } static int RegisterAll(); static void UnregisterAll(); - static Command* Find(const char* name); +}; + +class Command : public CommandBase { +public: + Command(const char* name); + Command(const char* pName, _CommandCallback callback, const char* pHelpString, int version = SourceGame_Unknown, + int flags = 0, _CommandCompletionCallback completionFunc = nullptr); + + bool IsCommand() override { return true; } + void Register() override; + void Unregister() override; + + inline ConCommand* ThisPtr() { return reinterpret_cast(this->ptr); } - static bool Hook(const char* name, _CommandCallback detour, _CommandCallback& original); - static bool Unhook(const char* name, _CommandCallback original); static bool ActivateAutoCompleteFile(const char* name, _CommandCompletionCallback callback); static bool DectivateAutoCompleteFile(const char* name); }; +class CommandHook { +public: + const char* target; + _CommandCallback* original; + _CommandCallback detour; + +private: + bool isRegistered; + bool isHooked; + +public: + CommandHook(const char* target, _CommandCallback* original, _CommandCallback detour); + void Register(Module* mod); + void Unregister(); + void Hook(); + void Unhook(); +}; + #define CON_COMMAND(name, description) \ void name##_callback(const CCommand& args); \ Command name = Command(#name, name##_callback, description); \ void name##_callback(const CCommand& args) -#define CON_COMMAND_F(name, description, flags) \ - void name##_callback(const CCommand& args); \ - Command name = Command(#name, name##_callback, description, flags); \ +#define CON_COMMAND_F(name, description, flags) \ + void name##_callback(const CCommand& args); \ + Command name = Command(#name, name##_callback, description, SourceGame_Unknown, flags); \ void name##_callback(const CCommand& args) -#define CON_COMMAND_F_COMPLETION(name, description, flags, completion) \ - void name##_callback(const CCommand& args); \ - Command name = Command(#name, name##_callback, description, flags, completion); \ +#define CON_COMMAND_F_COMPLETION(name, description, flags, completion) \ + void name##_callback(const CCommand& args); \ + Command name = Command(#name, name##_callback, description, SourceGame_Unknown, flags, completion); \ + void name##_callback(const CCommand& args) + +#define CON_COMMAND_U(name, description, version) \ + void name##_callback(const CCommand& args); \ + Command name = Command(#name, name##_callback, description, version); \ + void name##_callback(const CCommand& args) + +#define CON_COMMAND_FU(name, description, flags, version) \ + void name##_callback(const CCommand& args); \ + Command name = Command(#name, name##_callback, description, version, flags); \ + void name##_callback(const CCommand& args) + +#define CON_COMMAND_FU_COMPLETION(name, description, flags, completion, version) \ + void name##_callback(const CCommand& args); \ + Command name = Command(#name, name##_callback, description, version, flags, completion); \ void name##_callback(const CCommand& args) #define DECL_DECLARE_AUTOCOMPLETION_FUNCTION(command) \ @@ -76,11 +118,9 @@ class Command { DECLARE_AUTOCOMPLETION_FUNCTION(name, subdirectory, extension) \ CON_COMMAND_F_COMPLETION(name, description, flags, AUTOCOMPLETION_FUNCTION(name)) -#define DECL_DETOUR_COMMAND(name) \ - static _CommandCallback name##_callback; \ - static void name##_callback_hook(const CCommand& args) -#define DETOUR_COMMAND(name) \ - void name##_callback_hook(const CCommand& args) +#define CON_COMMAND_AUTOCOMPLETEFILE_U(name, description, flags, subdirectory, extension, version) \ + DECLARE_AUTOCOMPLETION_FUNCTION(name, subdirectory, extension) \ + CON_COMMAND_FU_COMPLETION(name, description, flags, AUTOCOMPLETION_FUNCTION(name), version) #define DECL_COMMAND_COMPLETION(command) \ DECL_DECLARE_AUTOCOMPLETION_FUNCTION(command) \ @@ -133,3 +173,9 @@ class Command { #define CON_COMMAND_COMPLETION(name, description, completion) \ DECL_AUTO_COMMAND_COMPLETION(name, completion) \ CON_COMMAND_F_COMPLETION(name, description, 0, name##_CompletionFunc) + +#define DETOUR_COMMAND(name) \ + _CommandCallback name##_callback; \ + void name##_callback_detour(const CCommand& args); \ + CommandHook name##_hook(#name, &name##_callback, name##_callback_detour); \ + void name##_callback_detour(const CCommand& args) diff --git a/src/Features/ClassDumper.cpp b/src/Features/ClassDumper.cpp index c5f02b4a..16f5f8f4 100644 --- a/src/Features/ClassDumper.cpp +++ b/src/Features/ClassDumper.cpp @@ -15,6 +15,7 @@ #include "Modules/Engine.hpp" #include "Modules/Server.hpp" +#include "Utils/Platform.hpp" #include "Utils/SDK.hpp" #include "SAR.hpp" @@ -26,7 +27,6 @@ ClassDumper::ClassDumper() , serverClassesFile("server_classes.json") , clientClassesFile("client_classes.json") { - this->hasLoaded = true; } void ClassDumper::Dump(bool dumpServer) { @@ -54,7 +54,7 @@ void ClassDumper::Dump(bool dumpServer) } } - file.seekp(-1, std::ios_base::_Seekcur); + file.seekp(-1, SEEK_DIR_CUR); file << "]}"; file.close(); @@ -105,7 +105,7 @@ void ClassDumper::DumpSendTable(std::ofstream& file, SendTable* table) } if (table->m_nProps != 0) { - file.seekp(-1, std::ios_base::_Seekcur); + file.seekp(-1, SEEK_DIR_CUR); } file << "]}"; } @@ -146,7 +146,7 @@ void ClassDumper::DumpRecvTable(std::ofstream& file, RecvTable* table) } if (table->m_nProps != 0) { - file.seekp(-1, std::ios_base::_Seekcur); + file.seekp(-1, SEEK_DIR_CUR); } file << "]}"; } diff --git a/src/Features/Config.cpp b/src/Features/Config.cpp index 7548e5a4..9bbcd7c3 100644 --- a/src/Features/Config.cpp +++ b/src/Features/Config.cpp @@ -23,7 +23,6 @@ Config* config; Config::Config() : filePath("/cfg/_sar_cvars.cfg") { - this->hasLoaded = true; } bool Config::Save() { diff --git a/src/Features/Cvars.cpp b/src/Features/Cvars.cpp index af5e97e0..1f2f6120 100644 --- a/src/Features/Cvars.cpp +++ b/src/Features/Cvars.cpp @@ -21,7 +21,6 @@ Cvars* cvars; Cvars::Cvars() : locked(true) { - this->hasLoaded = true; } int Cvars::Dump(std::ofstream& file) { @@ -77,15 +76,9 @@ int Cvars::DumpDoc(std::ofstream& file) }; auto count = 0; - for (const auto& var : Variable::GetList()) { - if (var && !var->isReference) { - InternalDump(var->ThisPtr(), Game::VersionToString(var->version), false); - ++count; - } - } - for (const auto& com : Command::GetList()) { - if (com && !com->isReference) { - InternalDump(com->ThisPtr(), Game::VersionToString(com->version), true); + for (const auto& cmd : CommandBase::GetList()) { + if (cmd && !cmd->isReference) { + InternalDump(cmd->ThisPtr(), Game::VersionToString(cmd->version), false); ++count; } } @@ -95,32 +88,35 @@ int Cvars::DumpDoc(std::ofstream& file) void Cvars::ListAll() { console->Msg("Commands:\n"); - for (auto& command : Command::GetList()) { - if (!!command && command->isRegistered) { - auto ptr = command->ThisPtr(); + + for (auto& cmd : CommandBase::GetList()) { + if (!!cmd && cmd->IsCommand() && cmd->isRegistered) { + auto ptr = cmd->ThisPtr(); + console->Print("\n%s\n", ptr->m_pszName); console->Msg("%s", ptr->m_pszHelpString); } } - console->Msg("\nVariables:\n"); - for (auto& variable : Variable::GetList()) { - if (!variable) { - continue; - } - auto ptr = variable->ThisPtr(); - if (variable->isRegistered) { - console->Print("\n%s ", ptr->m_pszName); - if (ptr->m_bHasMin) { - console->Print("\n"); - } else { - console->Print("\n"); - } - console->Msg("%s", ptr->m_pszHelpString); - } else if (variable->isReference) { - console->Print("\n%s (unlocked)\n", ptr->m_pszName); - if (std::strlen(ptr->m_pszHelpString) != 0) { - console->Msg("%s\n", ptr->m_pszHelpString); + console->Msg("\nVariables:\n"); + for (auto& cmd : CommandBase::GetList()) { + if (!!cmd && !cmd->IsCommand()) { + auto var = reinterpret_cast(cmd)->ThisPtr(); + + if (cmd->isRegistered) { + console->Print("\n%s ", var->m_pszName); + + if (var->m_bHasMin) { + console->Print("\n"); + } else { + console->Print("\n"); + } + console->Msg("%s", var->m_pszHelpString); + } else if (cmd->isReference) { + console->Print("\n%s (unlocked)\n", var->m_pszName); + if (std::strlen(var->m_pszHelpString) != 0) { + console->Msg("%s\n", var->m_pszHelpString); + } } } } @@ -131,7 +127,7 @@ void Cvars::PrintHelp(const CCommand& args) return console->Print("Prints help string of cvar. Usage: help \n"); } - auto cmd = reinterpret_cast(tier1->FindCommandBase(tier1->g_pCVar->ThisPtr(), args[1])); + auto cmd = tier1->FindCommandBase(tier1->g_pCVar->ThisPtr(), args[1]); if (cmd) { auto IsCommand = reinterpret_cast(Memory::VMT(cmd, Offsets::IsCommand)); if (!IsCommand(cmd)) { diff --git a/src/Features/DataMapDumper.cpp b/src/Features/DataMapDumper.cpp index 9d32c576..cb540d09 100644 --- a/src/Features/DataMapDumper.cpp +++ b/src/Features/DataMapDumper.cpp @@ -15,6 +15,7 @@ #include "Modules/Server.hpp" #include "Utils/Memory.hpp" +#include "Utils/Platform.hpp" #include "Utils/SDK.hpp" #include "SAR.hpp" @@ -38,7 +39,6 @@ DataMapDumper::DataMapDumper() , serverResult() , clientResult() { - this->hasLoaded = true; } void DataMapDumper::Dump(bool dumpServer) { @@ -82,7 +82,7 @@ void DataMapDumper::Dump(bool dumpServer) } map = map->baseMap; } - file.seekp(-1, std::ios_base::_Seekcur); + file.seekp(-1, SEEK_DIR_CUR); file << "]}"; }; std::function DumpMap2; @@ -115,14 +115,14 @@ void DataMapDumper::Dump(bool dumpServer) } map = map->baseMap; } - file.seekp(-1, std::ios_base::_Seekcur); + file.seekp(-1, SEEK_DIR_CUR); file << "]}"; }; auto results = (dumpServer) ? &this->serverResult : &this->clientResult; if (results->empty()) { auto hl2 = sar.game->Is(SourceGame_HalfLife2Engine); - auto moduleName = (dumpServer) ? server->Name() : client->Name(); + auto moduleName = (dumpServer) ? server->filename : client->filename; *results = Memory::MultiScan(moduleName, &DATAMAP_PATTERNS); for (auto const& result : *results) { @@ -139,7 +139,7 @@ void DataMapDumper::Dump(bool dumpServer) } } - file.seekp(-1, std::ios_base::_Seekcur); + file.seekp(-1, SEEK_DIR_CUR); file << "]}"; file.close(); diff --git a/src/Features/Demo/DemoParser.cpp b/src/Features/Demo/DemoParser.cpp index 0724e2a6..7fdb00da 100644 --- a/src/Features/Demo/DemoParser.cpp +++ b/src/Features/Demo/DemoParser.cpp @@ -216,8 +216,8 @@ CON_COMMAND_AUTOCOMPLETEFILE(sar_time_demo, "Parses a demo and prints some infor std::string name; if (args[1][0] == '\0') { - if (engine->demoplayer->DemoName[0] != '\0') { - name = std::string(engine->demoplayer->DemoName); + if (demoplayer->DemoName[0] != '\0') { + name = std::string(demoplayer->DemoName); } else { return console->Print("No demo was recorded or played back!\n"); } @@ -290,14 +290,14 @@ CON_COMMAND_AUTOCOMPLETEFILE(sar_time_demos, "Parses multiple demos and prints t HUD_ELEMENT(demo, "0", "Draws name, tick and time of current demo.\n", HudType_InGame | HudType_Paused | HudType_LoadingScreen) { - if (!*engine->m_bLoadgame && *engine->demorecorder->m_bRecording && !engine->demorecorder->currentDemo.empty()) { - auto tick = engine->demorecorder->GetTick(); + if (!*engine->m_bLoadgame && *demorecorder->m_bRecording && !demorecorder->currentDemo.empty()) { + auto tick = demorecorder->GetTick(); auto time = engine->ToTime(tick); - ctx->DrawElement("demo: %s %i (%.3f)", engine->demorecorder->currentDemo.c_str(), tick, time); - } else if (!*engine->m_bLoadgame && engine->demoplayer->IsPlaying()) { - auto tick = engine->demoplayer->GetTick(); + ctx->DrawElement("demo: %s %i (%.3f)", demorecorder->currentDemo.c_str(), tick, time); + } else if (!*engine->m_bLoadgame && demoplayer->IsPlaying()) { + auto tick = demoplayer->GetTick(); auto time = engine->ToTime(tick); - ctx->DrawElement("demo: %s %i (%.3f)", engine->demoplayer->DemoName, tick, time); + ctx->DrawElement("demo: %s %i (%.3f)", demoplayer->DemoName, tick, time); } else { ctx->DrawElement("demo: -"); } diff --git a/src/Features/EntityList.cpp b/src/Features/EntityList.cpp index 0cf6073c..399f371a 100644 --- a/src/Features/EntityList.cpp +++ b/src/Features/EntityList.cpp @@ -14,7 +14,6 @@ EntityList* entityList; EntityList::EntityList() { - this->hasLoaded = true; } CEntInfo* EntityList::GetEntityInfoByIndex(int index) { diff --git a/src/Features/Feature.cpp b/src/Features/Feature.cpp index b1a42d7e..39d541fa 100644 --- a/src/Features/Feature.cpp +++ b/src/Features/Feature.cpp @@ -4,6 +4,10 @@ Features::Features() : list() { } +Features::~Features() +{ + this->DeleteAll(); +} void Features::DeleteAll() { for (auto& feature : this->list) { @@ -13,7 +17,3 @@ void Features::DeleteAll() } this->list.clear(); } -Features::~Features() -{ - this->DeleteAll(); -} diff --git a/src/Features/Feature.hpp b/src/Features/Feature.hpp index e7adebd8..4515494c 100644 --- a/src/Features/Feature.hpp +++ b/src/Features/Feature.hpp @@ -2,9 +2,6 @@ #include class Feature { -public: - bool hasLoaded = false; - public: virtual ~Feature() = default; }; @@ -15,17 +12,20 @@ class Features { public: Features(); + ~Features(); + template void AddFeature(T** featurePtr) { *featurePtr = new T(); this->list.push_back(*featurePtr); } + template void RemoveFeature(T** featurePtr) { this->list.erase(*featurePtr); } + void DeleteAll(); - ~Features(); }; diff --git a/src/Features/FovChanger.cpp b/src/Features/FovChanger.cpp index cd608556..ac0b6a61 100644 --- a/src/Features/FovChanger.cpp +++ b/src/Features/FovChanger.cpp @@ -11,7 +11,6 @@ FovChanger* fovChanger; FovChanger::FovChanger() : defaultFov(0) { - this->hasLoaded = true; } void FovChanger::SetFov(const int fov) { diff --git a/src/Features/Hud/Hud.cpp b/src/Features/Hud/Hud.cpp index 2ef01272..95b6b887 100644 --- a/src/Features/Hud/Hud.cpp +++ b/src/Features/Hud/Hud.cpp @@ -1,5 +1,6 @@ #include "Hud.hpp" +#include #include #include "Features/Session.hpp" @@ -11,13 +12,21 @@ #include "Modules/Surface.hpp" #include "Modules/VGui.hpp" +#include "Game.hpp" #include "Variable.hpp" -Variable sar_hud_default_spacing("sar_hud_default_spacing", "1", 0, "Spacing between elements of HUD.\n"); -Variable sar_hud_default_padding_x("sar_hud_default_padding_x", "2", 0, "X padding of HUD.\n"); -Variable sar_hud_default_padding_y("sar_hud_default_padding_y", "2", 0, "Y padding of HUD.\n"); -Variable sar_hud_default_font_index("sar_hud_default_font_index", "0", 0, "Font index of HUD.\n"); -Variable sar_hud_default_font_color("sar_hud_default_font_color", "255 255 255 255", "RGBA font color of HUD.\n", 0); +Variable sar_hud_default_spacing("sar_hud_default_spacing", "1", 0, + "Spacing between elements of HUD.\n"); +Variable sar_hud_default_padding_x("sar_hud_default_padding_x", "2", 0, + "X padding of HUD.\n"); +Variable sar_hud_default_padding_y("sar_hud_default_padding_y", "2", 0, + "Y padding of HUD.\n"); +Variable sar_hud_default_font_index("sar_hud_default_font_index", "0", 0, + "Font index of HUD.\n"); +Variable sar_hud_default_font_color("sar_hud_default_font_color", "255 255 255 255", + "RGBA font color of HUD.\n", + SourceGame_Unknown, + 0); BaseHud::BaseHud(int type, bool drawSecondSplitScreen, int version) : type(type) @@ -193,7 +202,9 @@ CON_COMMAND_COMPLETION(sar_hud_default_order_top, "Orders hud element to top. Us console->Print("Moved HUD element %s to top.\n", args[1]); } -CON_COMMAND_COMPLETION(sar_hud_default_order_bottom, "Orders hud element to bottom : sar_hud_default_order_bottom \n", (elementOrder)) +CON_COMMAND_COMPLETION(sar_hud_default_order_bottom, + "Orders hud element to bottom : sar_hud_default_order_bottom \n", + (elementOrder)) { if (args.ArgC() != 2) { return console->Print("Set!\n"); @@ -230,14 +241,17 @@ CON_COMMAND(sar_hud_default_order_reset, "Resets order of hud element.\n") // HUD -HUD_ELEMENT_STRING(text, "", "Draws specified text when not empty.\n", HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) +HUD_ELEMENT_STRING(text, "", + "Draws specified text when not empty.\n", + HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) { ctx->DrawElement("%s", text); } -HUD_ELEMENT_MODE2(position, "0", 0, 2, "Draws absolute position of the client.\n" - "0 = Default,\n" - "1 = Player position,\n" - "2 = Camera position.\n", +HUD_ELEMENT_MODE2(position, "0", 0, 2, + "Draws absolute position of the client.\n" + "0 = Default,\n" + "1 = Player position,\n" + "2 = Camera position.\n", HudType_InGame | HudType_Paused | HudType_LoadingScreen) { auto player = client->GetPlayer(ctx->slot + 1); @@ -251,10 +265,11 @@ HUD_ELEMENT_MODE2(position, "0", 0, 2, "Draws absolute position of the client.\n ctx->DrawElement("pos: -"); } } -HUD_ELEMENT_MODE2(angles, "0", 0, 2, "Draws absolute view angles of the client.\n" - "0 = Default,\n" - "1 = XY,\n" - "2 = XYZ.\n", +HUD_ELEMENT_MODE2(angles, "0", 0, 2, + "Draws absolute view angles of the client.\n" + "0 = Default,\n" + "1 = XY,\n" + "2 = XYZ.\n", HudType_InGame | HudType_Paused | HudType_LoadingScreen) { auto ang = engine->GetAngles(ctx->slot); @@ -264,11 +279,12 @@ HUD_ELEMENT_MODE2(angles, "0", 0, 2, "Draws absolute view angles of the client.\ ctx->DrawElement("ang: %.3f %.3f %.3f", ang.x, ang.y, ang.z); } } -HUD_ELEMENT_MODE2(velocity, "0", 0, 3, "Draws velocity of the client.\n" - "0 = Default,\n" - "1 = X/Y/Z,\n" - "2 = X/Y,\n" - "3 = X : Y : Z.\n", +HUD_ELEMENT_MODE2(velocity, "0", 0, 3, + "Draws velocity of the client.\n" + "0 = Default,\n" + "1 = X/Y/Z,\n" + "2 = X/Y,\n" + "3 = X : Y : Z.\n", HudType_InGame | HudType_Paused | HudType_LoadingScreen) { auto player = client->GetPlayer(ctx->slot + 1); diff --git a/src/Features/Hud/Hud.hpp b/src/Features/Hud/Hud.hpp index ebf2bba8..5b4a59b5 100644 --- a/src/Features/Hud/Hud.hpp +++ b/src/Features/Hud/Hud.hpp @@ -103,7 +103,7 @@ class HudStringElement : public HudElement { HudElement sar_hud_element_##name(&sar_hud##name, sar_hud_element_##name##_callback, type); \ void sar_hud_element_##name##_callback(HudContext* ctx) #define HUD_ELEMENT_STRING(name, value, desc, type) \ - Variable sar_hud##name("sar_hud_" #name, value, desc, 0); \ + Variable sar_hud##name("sar_hud_" #name, value, desc, SourceGame_Unknown, 0); \ void sar_hud_element_##name##_callback(HudContext* ctx, const char* text); \ HudStringElement sar_hud_element_##name(&sar_hud##name, sar_hud_element_##name##_callback, type); \ void sar_hud_element_##name##_callback(HudContext* ctx, const char* text) @@ -113,34 +113,34 @@ class HudStringElement : public HudElement { HudModeElement sar_hud_element_##name(&sar_hud##name, sar_hud_element_##name##_callback, type); \ void sar_hud_element_##name##_callback(HudContext* ctx, int mode) // First+second screen -#define HUD_ELEMENT2(name, value, desc, type) \ +#define HUD_ELEMENT2(name, value, desc, type) \ Variable sar_hud##name("sar_hud_" #name, value, desc); \ void sar_hud_element_##name##_callback(HudContext* ctx); \ HudElement sar_hud_element_##name(&sar_hud##name, sar_hud_element_##name##_callback, type, true); \ void sar_hud_element_##name##_callback(HudContext* ctx) -#define HUD_ELEMENT_STRING2(name, value, desc, type) \ - Variable sar_hud##name("sar_hud_" #name, value, desc, 0); \ +#define HUD_ELEMENT_STRING2(name, value, desc, type) \ + Variable sar_hud##name("sar_hud_" #name, value, desc, SourceGame_Unknown, 0); \ void sar_hud_element_##name##_callback(HudContext* ctx, const char* text); \ HudStringElement sar_hud_element_##name(&sar_hud##name, sar_hud_element_##name##_callback, type, true); \ void sar_hud_element_##name##_callback(HudContext* ctx, const char* text) -#define HUD_ELEMENT_MODE2(name, value, min, max, desc, type) \ +#define HUD_ELEMENT_MODE2(name, value, min, max, desc, type) \ Variable sar_hud##name("sar_hud_" #name, value, min, max, desc); \ void sar_hud_element_##name##_callback(HudContext* ctx, int mode); \ HudModeElement sar_hud_element_##name(&sar_hud##name, sar_hud_element_##name##_callback, type, true); \ void sar_hud_element_##name##_callback(HudContext* ctx, int mode) // Specify game version #define HUD_ELEMENT3(name, value, desc, type, showOnSecondScreen, version) \ - Variable sar_hud##name("sar_hud_" #name, value, desc); \ + Variable sar_hud##name("sar_hud_" #name, value, desc, version); \ void sar_hud_element_##name##_callback(HudContext* ctx); \ HudElement sar_hud_element_##name(&sar_hud##name, sar_hud_element_##name##_callback, type, showOnSecondScreen, version); \ void sar_hud_element_##name##_callback(HudContext* ctx) #define HUD_ELEMENT_STRING3(name, value, desc, type, showOnSecondScreen, version) \ - Variable sar_hud##name("sar_hud_" #name, value, desc, 0); \ + Variable sar_hud##name("sar_hud_" #name, value, desc, version, 0); \ void sar_hud_element_##name##_callback(HudContext* ctx, const char* text); \ HudStringElement sar_hud_element_##name(&sar_hud##name, sar_hud_element_##name##_callback, type, showOnSecondScreen, version); \ void sar_hud_element_##name##_callback(HudContext* ctx, const char* text) #define HUD_ELEMENT_MODE3(name, value, min, max, desc, type, showOnSecondScreen, version) \ - Variable sar_hud##name("sar_hud_" #name, value, min, max, desc); \ + Variable sar_hud##name("sar_hud_" #name, value, min, max, desc, version); \ void sar_hud_element_##name##_callback(HudContext* ctx, int mode); \ HudModeElement sar_hud_element_##name(&sar_hud##name, sar_hud_element_##name##_callback, type, showOnSecondScreen, version); \ void sar_hud_element_##name##_callback(HudContext* ctx, int mode) diff --git a/src/Features/Hud/InputHud.cpp b/src/Features/Hud/InputHud.cpp index d1738cdd..30eeb8df 100644 --- a/src/Features/Hud/InputHud.cpp +++ b/src/Features/Hud/InputHud.cpp @@ -10,37 +10,58 @@ #include "Variable.hpp" -Variable sar_ihud("sar_ihud", "0", 0, "Draws movement inputs of client.\n" - "0 = Default,\n" - "1 = forward;back;moveleft;moveright,\n" - "2 = 1 + duck;jump;use,\n" - "3 = 2 + attack;attack2,\n" - "4 = 3 + speed;reload.\n"); -Variable sar_ihud_x("sar_ihud_x", "0", 0, "X offset of input HUD.\n"); -Variable sar_ihud_y("sar_ihud_y", "0", 0, "Y offset of input HUD.\n"); -Variable sar_ihud_button_padding("sar_ihud_button_padding", "2", 0, "Padding between buttons of input HUD.\n"); -Variable sar_ihud_button_size("sar_ihud_button_size", "60", 0, "Button size of input HUD.\n"); -Variable sar_ihud_button_color("sar_ihud_button_color", "0 0 0 255", "RGBA button color of input HUD.\n", 0); -Variable sar_ihud_font_color("sar_ihud_font_color", "255 255 255 255", "RGBA font color of input HUD.\n", 0); -Variable sar_ihud_font_index("sar_ihud_font_index", "1", 0, "Font index of input HUD.\n"); -Variable sar_ihud_layout("sar_ihud_layout", "WASDCSELRSR", "Layout of input HUD.\n" - "Labels are in this order:\n" - "forward,\n" - "moveleft,\n" - "back,\n" - "moveright,\n" - "duck,\n" - "jump,\n" - "use,\n" - "attack,\n" - "attack2,\n" - "speed,\n" - "reload.\n" - "Pass an empty string to disable drawing labels completely.\n", +Variable sar_ihud("sar_ihud", "0", 0, + "Draws movement inputs of client.\n" + "0 = Default,\n" + "1 = forward;back;moveleft;moveright,\n" + "2 = 1 + duck;jump;use,\n" + "3 = 2 + attack;attack2,\n" + "4 = 3 + speed;reload.\n"); +Variable sar_ihud_x("sar_ihud_x", "0", 0, + "X offset of input HUD.\n"); +Variable sar_ihud_y("sar_ihud_y", "0", 0, + "Y offset of input HUD.\n"); +Variable sar_ihud_button_padding("sar_ihud_button_padding", "2", 0, + "Padding between buttons of input HUD.\n"); +Variable sar_ihud_button_size("sar_ihud_button_size", "60", 0, + "Button size of input HUD.\n"); +Variable sar_ihud_button_color("sar_ihud_button_color", "0 0 0 255", + "RGBA button color of input HUD.\n", + SourceGame_Unknown, + 0); +Variable sar_ihud_font_color("sar_ihud_font_color", "255 255 255 255", + "RGBA font color of input HUD.\n", + SourceGame_Unknown, + 0); +Variable sar_ihud_font_index("sar_ihud_font_index", "1", 0, + "Font index of input HUD.\n"); +Variable sar_ihud_layout("sar_ihud_layout", "WASDCSELRSR", + "Layout of input HUD.\n" + "Labels are in this order:\n" + "forward,\n" + "moveleft,\n" + "back,\n" + "moveright,\n" + "duck,\n" + "jump,\n" + "use,\n" + "attack,\n" + "attack2,\n" + "speed,\n" + "reload.\n" + "Pass an empty string to disable drawing labels completely.\n", + SourceGame_Unknown, + 0); +Variable sar_ihud_shadow("sar_ihud_shadow", "1", + "Draws button shadows of input HUD.\n"); +Variable sar_ihud_shadow_color("sar_ihud_shadow_color", "0 0 0 64", + "RGBA button shadow color of input HUD.\n", + SourceGame_Unknown, + 0); +Variable sar_ihud_shadow_font_color("sar_ihud_shadow_font_color", "255 255 255 64", + "RGBA button shadow font color of input HUD.\n", + SourceGame_Unknown, 0); -Variable sar_ihud_shadow("sar_ihud_shadow", "1", "Draws button shadows of input HUD.\n"); -Variable sar_ihud_shadow_color("sar_ihud_shadow_color", "0 0 0 64", "RGBA button shadow color of input HUD.\n", 0); -Variable sar_ihud_shadow_font_color("sar_ihud_shadow_font_color", "255 255 255 64", "RGBA button shadow font color of input HUD.\n", 0); const int row0 = 0; const int row1 = 1; @@ -61,7 +82,7 @@ InputHud inputHud2; InputHud::InputHud() : Hud(HudType_InGame, true, SourceGame_Portal2Engine) - , buttonBits { 0, 0 } + , buttonBits{ 0, 0 } { } void InputHud::SetButtonBits(int slot, int buttonBits) @@ -78,17 +99,17 @@ void InputHud::Paint(int slot) auto button = this->buttonBits[slot]; - auto mvForward =button & IN_FORWARD; - auto mvBack =button & IN_BACK; - auto mvLeft =button & IN_MOVELEFT; - auto mvRight =button & IN_MOVERIGHT; - auto mvJump =button & IN_JUMP; - auto mvDuck =button & IN_DUCK; - auto mvUse =button & IN_USE; - auto mvAttack =button & IN_ATTACK; - auto mvAttack2 =button & IN_ATTACK2; - auto mvReload =button & IN_RELOAD; - auto mvSpeed =button & IN_SPEED; + auto mvForward = button & IN_FORWARD; + auto mvBack = button & IN_BACK; + auto mvLeft = button & IN_MOVELEFT; + auto mvRight = button & IN_MOVERIGHT; + auto mvJump = button & IN_JUMP; + auto mvDuck = button & IN_DUCK; + auto mvUse = button & IN_USE; + auto mvAttack = button & IN_ATTACK; + auto mvAttack2 = button & IN_ATTACK2; + auto mvReload = button & IN_RELOAD; + auto mvSpeed = button & IN_SPEED; auto xOffset = sar_ihud_x.GetInt(); auto yOffset = sar_ihud_y.GetInt(); diff --git a/src/Features/Hud/InspectionHud.cpp b/src/Features/Hud/InspectionHud.cpp index fad840c8..c8b01913 100644 --- a/src/Features/Hud/InspectionHud.cpp +++ b/src/Features/Hud/InspectionHud.cpp @@ -6,15 +6,27 @@ #include "Modules/Scheme.hpp" #include "Modules/Surface.hpp" +#include "Game.hpp" #include "Variable.hpp" -Variable sar_ei_hud("sar_ei_hud", "0", 0, "Draws entity inspection data.\n"); -Variable sar_ei_hud_x("sar_ei_hud_x", "0", 0, "X offset of entity inspection HUD.\n"); -Variable sar_ei_hud_y("sar_ei_hud_y", "0", 0, "Y offset of entity inspection HUD.\n"); -Variable sar_ei_hud_z("sar_ei_hud_z", "0", 0, "Z offset of entity inspection HUD.\n"); -Variable sar_ei_hud_font_color("sar_ei_hud_font_color", "255 255 255 255", "RGBA font color of entity inspection HUD when not recording.\n", 0); -Variable sar_ei_hud_font_color2("sar_ei_hud_font_color2", "153 23 9 255", "RGBA font color of entity inspection HUD when recording.\n", 0); -Variable sar_ei_hud_font_index("sar_ei_hud_font_index", "1", 0, "Font index of entity inspection HUD.\n"); +Variable sar_ei_hud("sar_ei_hud", "0", 0, + "Draws entity inspection data.\n"); +Variable sar_ei_hud_x("sar_ei_hud_x", "0", 0, + "X offset of entity inspection HUD.\n"); +Variable sar_ei_hud_y("sar_ei_hud_y", "0", 0, + "Y offset of entity inspection HUD.\n"); +Variable sar_ei_hud_z("sar_ei_hud_z", "0", 0, + "Z offset of entity inspection HUD.\n"); +Variable sar_ei_hud_font_color("sar_ei_hud_font_color", "255 255 255 255", + "RGBA font color of entity inspection HUD when not recording.\n", + SourceGame_Unknown, + 0); +Variable sar_ei_hud_font_color2("sar_ei_hud_font_color2", "153 23 9 255", + "RGBA font color of entity inspection HUD when recording.\n", + SourceGame_Unknown, + 0); +Variable sar_ei_hud_font_index("sar_ei_hud_font_index", "1", 0, + "Font index of entity inspection HUD.\n"); InspectionHud inspectionHud; @@ -39,7 +51,7 @@ void InspectionHud::Paint(int slot) auto data = inspector->GetData(); - auto offset = Vector { + auto offset = Vector{ (float)sar_ei_hud_x.GetInt(), (float)sar_ei_hud_y.GetInt(), (float)sar_ei_hud_z.GetInt() diff --git a/src/Features/Hud/SpeedrunHud.cpp b/src/Features/Hud/SpeedrunHud.cpp index d0a5676f..7b8beb11 100644 --- a/src/Features/Hud/SpeedrunHud.cpp +++ b/src/Features/Hud/SpeedrunHud.cpp @@ -7,11 +7,22 @@ #include "Variable.hpp" -Variable sar_sr_hud("sar_sr_hud", "0", 0, "Draws speedrun timer.\n"); -Variable sar_sr_hud_x("sar_sr_hud_x", "0", 0, "X offset of speedrun timer HUD.\n"); -Variable sar_sr_hud_y("sar_sr_hud_y", "100", 0, "Y offset of speedrun timer HUD.\n"); -Variable sar_sr_hud_font_color("sar_sr_hud_font_color", "255 255 255 255", "RGBA font color of speedrun timer HUD.\n", 0); -Variable sar_sr_hud_font_index("sar_sr_hud_font_index", "70", 0, "Font index of speedrun timer HUD.\n"); +Variable sar_sr_hud("sar_sr_hud", "0", 0, + "Draws speedrun timer.\n", + SourceGame_SupportsS3); +Variable sar_sr_hud_x("sar_sr_hud_x", "0", 0, + "X offset of speedrun timer HUD.\n", + SourceGame_SupportsS3); +Variable sar_sr_hud_y("sar_sr_hud_y", "100", 0, + "Y offset of speedrun timer HUD.\n", + SourceGame_SupportsS3); +Variable sar_sr_hud_font_color("sar_sr_hud_font_color", "255 255 255 255", + "RGBA font color of speedrun timer HUD.\n", + SourceGame_SupportsS3, + 0); +Variable sar_sr_hud_font_index("sar_sr_hud_font_index", "70", 0, + "Font index of speedrun timer HUD.\n", + SourceGame_SupportsS3); SpeedrunHud speedrunHud; diff --git a/src/Features/Imitator.cpp b/src/Features/Imitator.cpp index f4c9cb6b..e4e20ff8 100644 --- a/src/Features/Imitator.cpp +++ b/src/Features/Imitator.cpp @@ -2,16 +2,16 @@ #include "Utils/SDK.hpp" +#include "Game.hpp" #include "Variable.hpp" -Variable sar_mimic("sar_mimic", "0", "Copies inputs to secondary split screen. Similar to ss_mimic.\n"); +Variable sar_mimic("sar_mimic", "0", "Copies inputs to secondary split screen. Similar to ss_mimic.\n", SourceGame_Portal2 | SourceGame_ApertureTag); Imitator* imitator; Imitator::Imitator() : frame() { - this->hasLoaded = true; } void Imitator::Save(const CUserCmd* cmd) { diff --git a/src/Features/Listener.cpp b/src/Features/Listener.cpp index 72382c61..d30aa6fe 100644 --- a/src/Features/Listener.cpp +++ b/src/Features/Listener.cpp @@ -13,7 +13,9 @@ #include "Command.hpp" #include "Variable.hpp" -Variable sar_debug_listener("sar_debug_listener", "0", "Prints event data of registered listener.\n"); +Variable sar_debug_listener("sar_debug_listener", "0", + "Prints event data of registered listener.\n", + SourceGame_Portal2 | SourceGame_ApertureTag); Listener* listener; @@ -22,11 +24,10 @@ Listener::Listener() , installedChangeCallback(false) , changeCount(0) { - this->hasLoaded = true; } void Listener::Init() { - if (engine->hasLoaded && engine->AddListener && !this->m_bRegisteredForEvents) { + if (engine && engine->AddListener && !this->m_bRegisteredForEvents) { for (const auto& event : EVENTS) { this->m_bRegisteredForEvents = engine->AddListener(engine->s_GameEventManager->ThisPtr(), this, event, true); @@ -46,7 +47,7 @@ void Listener::Init() } void Listener::Shutdown() { - if (engine->hasLoaded && engine->RemoveListener && this->m_bRegisteredForEvents) { + if (engine && engine->RemoveListener && this->m_bRegisteredForEvents) { engine->RemoveListener(engine->s_GameEventManager->ThisPtr(), this); this->m_bRegisteredForEvents = false; } @@ -105,7 +106,9 @@ void Listener::OnCheatsChanged(IConVar* pVar, const char* pOldString, float flOl // Commands -CON_COMMAND(sar_dump_events, "Dumps all registered game events of the game event manager.\n") +CON_COMMAND_U(sar_dump_events, + "Dumps all registered game events of the game event manager.\n", + SourceGame_Portal2 | SourceGame_ApertureTag) { if (!engine->s_GameEventManager) { return; diff --git a/src/Features/OffsetFinder.cpp b/src/Features/OffsetFinder.cpp index b5887d0c..965746bc 100644 --- a/src/Features/OffsetFinder.cpp +++ b/src/Features/OffsetFinder.cpp @@ -13,7 +13,6 @@ OffsetFinder* offsetFinder; OffsetFinder::OffsetFinder() { - this->hasLoaded = true; } void OffsetFinder::ServerSide(const char* className, const char* propName, int* offset) { diff --git a/src/Features/Rebinder.cpp b/src/Features/Rebinder.cpp index 2ef73519..5031ba47 100644 --- a/src/Features/Rebinder.cpp +++ b/src/Features/Rebinder.cpp @@ -6,11 +6,14 @@ #include "Modules/InputSystem.hpp" #include "Command.hpp" +#include "Game.hpp" #include "Variable.hpp" -Variable sar_save_flag("sar_save_flag", "#SAVE#", "Echo message when using sar_bind_save.\n" - "Default is \"#SAVE#\", a SourceRuns standard.\n" - "Keep this empty if no echo message should be binded.\n", +Variable sar_save_flag("sar_save_flag", "#SAVE#", + "Echo message when using sar_bind_save.\n" + "Default is \"#SAVE#\", a SourceRuns standard.\n" + "Keep this empty if no echo message should be binded.\n", + SourceGame_Unknown, 0); Rebinder* rebinder; @@ -24,7 +27,6 @@ Rebinder::Rebinder() , isReloadBinding(false) , lastIndexNumber(0) { - this->hasLoaded = true; } void Rebinder::SetSaveBind(int button, const char* name) { diff --git a/src/Features/ReplaySystem/ReplayPlayer.cpp b/src/Features/ReplaySystem/ReplayPlayer.cpp index 34152266..96088ede 100644 --- a/src/Features/ReplaySystem/ReplayPlayer.cpp +++ b/src/Features/ReplaySystem/ReplayPlayer.cpp @@ -6,8 +6,8 @@ #include "Modules/Server.hpp" -#include "Variable.hpp" #include "Utils.hpp" +#include "Variable.hpp" Variable sar_replay_autoloop("sar_replay_autoloop", "0", "Plays replay again when it ended.\n"); diff --git a/src/Features/ReplaySystem/ReplayPlayer.hpp b/src/Features/ReplaySystem/ReplayPlayer.hpp index 9edd1d87..790293b2 100644 --- a/src/Features/ReplaySystem/ReplayPlayer.hpp +++ b/src/Features/ReplaySystem/ReplayPlayer.hpp @@ -3,8 +3,8 @@ #include "Features/Feature.hpp" -#include "Variable.hpp" #include "Utils.hpp" +#include "Variable.hpp" class ReplayPlayer : public Feature { private: diff --git a/src/Features/ReplaySystem/ReplayProvider.cpp b/src/Features/ReplaySystem/ReplayProvider.cpp index 1667e256..30634413 100644 --- a/src/Features/ReplaySystem/ReplayProvider.cpp +++ b/src/Features/ReplaySystem/ReplayProvider.cpp @@ -22,14 +22,14 @@ Variable sar_replay_viewmode("sar_replay_viewmode", "0", 0, "Fallback mode of replay system.\n" "0 = Default,\n" "1 = Automatically records first view and plays second view after a load,\n" - "2 = Automatically records second view and plays first view after a load.\n"); + "2 = Automatically records second view and plays first view after a load.\n", + SourceGame_Portal2 | SourceGame_ApertureTag); ReplayProvider* replayProvider; ReplayProvider::ReplayProvider() : replays() { - this->hasLoaded = true; } ReplayProvider::~ReplayProvider() { diff --git a/src/Features/Routing/EntityInspector.cpp b/src/Features/Routing/EntityInspector.cpp index fff6bdff..73952765 100644 --- a/src/Features/Routing/EntityInspector.cpp +++ b/src/Features/Routing/EntityInspector.cpp @@ -29,7 +29,6 @@ EntityInspector::EntityInspector() , latest() , data() { - this->hasLoaded = true; } void EntityInspector::Start() { @@ -172,7 +171,9 @@ CON_COMMAND(sar_inspection_index, "Sets entity index for inspection.\n") // HUD -HUD_ELEMENT(inspection, "0", "Draws entity inspection data.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT(inspection, "0", + "Draws entity inspection data.\n", + HudType_InGame | HudType_Paused) { ctx->DrawElement(inspector->IsRunning() ? "inspection (recording)" : "inspection"); diff --git a/src/Features/Routing/Tracer.cpp b/src/Features/Routing/Tracer.cpp index 49696b2a..dd20691d 100644 --- a/src/Features/Routing/Tracer.cpp +++ b/src/Features/Routing/Tracer.cpp @@ -20,7 +20,6 @@ Tracer::Tracer() for (auto i = 0; i < Offsets::MAX_SPLITSCREEN_PLAYERS; ++i) { this->traces.push_back(new TraceResult()); } - this->hasLoaded = true; } Tracer::~Tracer() { @@ -104,10 +103,11 @@ CON_COMMAND(sar_trace_reset, "Resets tracer.\n") // HUD -HUD_ELEMENT_MODE2(trace, "0", 0, 2, "Draws distance values of tracer. " - "0 = Default,\n" - "1 = Vec3,\n" - "2 = Vec2.\n", +HUD_ELEMENT_MODE2(trace, "0", 0, 2, + "Draws distance values of tracer. " + "0 = Default,\n" + "1 = Vec3,\n" + "2 = Vec2.\n", HudType_InGame | HudType_Paused) { auto result = tracer->GetTraceResult(ctx->slot); diff --git a/src/Features/Session.cpp b/src/Features/Session.cpp index 31602a45..97a7c5d7 100644 --- a/src/Features/Session.cpp +++ b/src/Features/Session.cpp @@ -28,7 +28,6 @@ Session::Session() , lastFrame(0) , prevState(HS_RUN) { - this->hasLoaded = true; } int Session::GetTick() { @@ -74,8 +73,8 @@ void Session::Start() speedrun->Resume(tick); if (rebinder->isSaveBinding || rebinder->isReloadBinding) { - if (engine->demorecorder->isRecordingDemo) { - rebinder->UpdateIndex(*engine->demorecorder->m_nDemoNumber); + if (demorecorder->isRecordingDemo) { + rebinder->UpdateIndex(*demorecorder->m_nDemoNumber); } else { rebinder->UpdateIndex(rebinder->lastIndexNumber + 1); } @@ -160,7 +159,7 @@ void Session::Ended() stats->ResetAll(); } - engine->demorecorder->currentDemo = ""; + demorecorder->currentDemo = ""; this->lastFrame = this->currentFrame; this->currentFrame = 0; @@ -208,16 +207,22 @@ void Session::Changed(int state) // HUD -HUD_ELEMENT(session, "0", "Draws current session tick.\n", HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) +HUD_ELEMENT(session, "0", + "Draws current session tick.\n", + HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) { auto tick = (session->isRunning) ? session->GetTick() : 0; ctx->DrawElement("session: %i (%.3f)", tick, engine->ToTime(tick)); } -HUD_ELEMENT(last_session, "0", "Draws value of latest completed session.\n", HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) +HUD_ELEMENT(last_session, "0", + "Draws value of latest completed session.\n", + HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) { ctx->DrawElement("last session: %i (%.3f)", session->lastSession, engine->ToTime(session->lastSession)); } -HUD_ELEMENT(sum, "0", "Draws summary value of sessions.\n", HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) +HUD_ELEMENT(sum, "0", + "Draws summary value of sessions.\n", + HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) { if (summary->isRunning && sar_sum_during_session.GetBool()) { auto tick = (session->isRunning) ? session->GetTick() : 0; @@ -227,11 +232,15 @@ HUD_ELEMENT(sum, "0", "Draws summary value of sessions.\n", HudType_InGame | Hud ctx->DrawElement("sum: %i (%.3f)", summary->totalTicks, engine->ToTime(summary->totalTicks)); } } -HUD_ELEMENT(frame, "0", "Draws current frame count.\n", HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) +HUD_ELEMENT(frame, "0", + "Draws current frame count.\n", + HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) { ctx->DrawElement("frame: %i", session->currentFrame); } -HUD_ELEMENT(last_frame, "0", "Draws last saved frame value.\n", HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) +HUD_ELEMENT(last_frame, "0", + "Draws last saved frame value.\n", + HudType_InGame | HudType_Paused | HudType_Menu | HudType_LoadingScreen) { ctx->DrawElement("last frame: %i", session->lastFrame); } diff --git a/src/Features/Speedrun/Rules/ApertureTagRules.cpp b/src/Features/Speedrun/Rules/ApertureTagRules.cpp index ee1438b0..317e5a76 100644 --- a/src/Features/Speedrun/Rules/ApertureTagRules.cpp +++ b/src/Features/Speedrun/Rules/ApertureTagRules.cpp @@ -32,7 +32,7 @@ SAR_RULE3(out_of_shower, "gg_intro_wakeup", "tele_out_shower", SearchMode::Names SAR_RULE3(end_credits, "gg_stage_theend", "die_ending_math_final", SearchMode::Names) { // CMathCounter aka math_counter - auto m_bHitMax = reinterpret_cast((uintptr_t)entity + Offset_m_bHitMax); + auto m_bHitMax = reinterpret_cast((uintptr_t)entity + Offset_m_bHitMax); if (*m_bHitMax) { return TimerAction::End; @@ -44,7 +44,7 @@ SAR_RULE3(end_credits, "gg_stage_theend", "die_ending_math_final", SearchMode::N SAR_RULE3(door_closes, "gg_stage_theend", "ele_exit_door", SearchMode::Names) { // CRotDoor aka func_door_rotating - auto m_toggle_state = reinterpret_cast((uintptr_t)entity + Offset_m_toggle_state); + auto m_toggle_state = reinterpret_cast((uintptr_t)entity + Offset_m_toggle_state); if (*m_toggle_state == TS_GOING_DOWN) { return TimerAction::End; diff --git a/src/Features/Speedrun/Rules/Portal2Rules.cpp b/src/Features/Speedrun/Rules/Portal2Rules.cpp index 37e732c0..0ae12063 100644 --- a/src/Features/Speedrun/Rules/Portal2Rules.cpp +++ b/src/Features/Speedrun/Rules/Portal2Rules.cpp @@ -104,5 +104,5 @@ SAR_RULE3(vehicle_lock, "e1912", "crash-vehicle_outro", SearchMode::Names) } SAR_CATEGORY(Portal2, SinglePlayer, _Rules({ &view_change, &moon_shot })); -SAR_CATEGORY(Portal2, Cooperative, _Rules({ &players_teleport, &players_taunt, &gate_opens })); -SAR_CATEGORY(Portal2, Super8, _Rules({ &gain_control, &vehicle_lock })); +SAR_CATEGORY(Portal2, Cooperative, _Rules({ &players_teleport, &players_taunt, &gate_opens })); +SAR_CATEGORY(Portal2, Super8, _Rules({ &gain_control, &vehicle_lock })); diff --git a/src/Features/Speedrun/Rules/PortalRules.cpp b/src/Features/Speedrun/Rules/PortalRules.cpp index 7c156f76..4c41fe8a 100644 --- a/src/Features/Speedrun/Rules/PortalRules.cpp +++ b/src/Features/Speedrun/Rules/PortalRules.cpp @@ -8,8 +8,8 @@ #include "Games/Windows/PortalUnpack.hpp" -#include "Utils/SDK.hpp" #include "SAR.hpp" +#include "Utils/SDK.hpp" #ifdef _WIN32 #define testchmb_a_00 "testchmb_a_00" @@ -34,7 +34,7 @@ SAR_RULE3(waking_up, testchmb_a_00, "blackout_viewcontroller", SearchMode::Names static auto isUnpack = false; #endif - // CTriggerCamera aka point_viewcontrol + // CTriggerCamera aka point_viewcontrol auto m_state = reinterpret_cast((uintptr_t)entity + (isUnpack ? Offset_m_state_Unpack : Offset_m_state)); // Give it some time to get enabled... diff --git a/src/Features/Speedrun/SpeedrunTimer.cpp b/src/Features/Speedrun/SpeedrunTimer.cpp index 4caeab7a..4876eb4f 100644 --- a/src/Features/Speedrun/SpeedrunTimer.cpp +++ b/src/Features/Speedrun/SpeedrunTimer.cpp @@ -22,15 +22,20 @@ #include "Variable.hpp" Variable sar_speedrun_autostart("sar_speedrun_autostart", "0", - "Starts speedrun timer automatically on first frame after a load.\n"); + "Starts speedrun timer automatically on first frame after a load.\n", + SourceGame_SupportsS3); Variable sar_speedrun_autostop("sar_speedrun_autostop", "0", - "Stops speedrun timer automatically when going into the menu.\n"); + "Stops speedrun timer automatically when going into the menu.\n", + SourceGame_SupportsS3); Variable sar_speedrun_standard("sar_speedrun_standard", "1", - "Timer automatically starts, splits and stops.\n"); + "Timer automatically starts, splits and stops.\n", + SourceGame_SupportsS3); Variable sar_speedrun_time_pauses("sar_speedrun_time_pauses", "1", - "Timer automatically adds non-simulated ticks when server pauses.\n"); + "Timer automatically adds non-simulated ticks when server pauses.\n", + SourceGame_SupportsS3); Variable sar_speedrun_smartsplit("sar_speedrun_smartsplit", "0", - "Timer interface only splits once per level change.\n"); + "Timer interface only splits once per level change.\n", + SourceGame_SupportsS3); SpeedrunTimer* speedrun; @@ -51,8 +56,6 @@ SpeedrunTimer::SpeedrunTimer() this->pubInterface = std::make_unique(); this->result = std::make_unique(); this->pb = std::make_unique(); - - this->hasLoaded = true; } bool SpeedrunTimer::IsActive() { @@ -470,34 +473,34 @@ int sar_category_CompletionFunc(const char* partial, // Commands -CON_COMMAND(sar_speedrun_start, "Starts speedrun timer manually.\n") +CON_COMMAND_U(sar_speedrun_start, "Starts speedrun timer manually.\n", SourceGame_SupportsS3) { speedrun->Start(engine->GetTick()); } -CON_COMMAND(sar_speedrun_stop, "Stops speedrun timer manually.\n") +CON_COMMAND_U(sar_speedrun_stop, "Stops speedrun timer manually.\n", SourceGame_SupportsS3) { speedrun->Stop(); } -CON_COMMAND(sar_speedrun_split, "Splits speedrun timer manually.\n") +CON_COMMAND_U(sar_speedrun_split, "Splits speedrun timer manually.\n", SourceGame_SupportsS3) { speedrun->Split(false); } -CON_COMMAND(sar_speedrun_pause, "Pauses speedrun timer manually.\n") +CON_COMMAND_U(sar_speedrun_pause, "Pauses speedrun timer manually.\n", SourceGame_SupportsS3) { speedrun->Pause(); } -CON_COMMAND(sar_speedrun_resume, "Resumes speedrun timer manually.\n") +CON_COMMAND_U(sar_speedrun_resume, "Resumes speedrun timer manually.\n", SourceGame_SupportsS3) { speedrun->Resume(engine->GetTick()); } -CON_COMMAND(sar_speedrun_reset, "Resets speedrun timer.\n") +CON_COMMAND_U(sar_speedrun_reset, "Resets speedrun timer.\n", SourceGame_SupportsS3) { if (speedrun->IsActive()) { speedrun->Stop(); } speedrun->Stop(); } -CON_COMMAND(sar_speedrun_result, "Prints result of speedrun.\n") +CON_COMMAND_U(sar_speedrun_result, "Prints result of speedrun.\n", SourceGame_SupportsS3) { auto pb = (args.ArgC() == 2 && !std::strcmp(args[1], "pb")); @@ -531,8 +534,10 @@ CON_COMMAND(sar_speedrun_result, "Prints result of speedrun.\n") console->Print("Total: %s (%i)\n", SpeedrunTimer::Format(result->total * ipt).c_str(), result->total); } } -CON_COMMAND(sar_speedrun_export, "Saves speedrun result to a csv file.\n" - "Usage: sar_speedrun_export \n") +CON_COMMAND_U(sar_speedrun_export, + "Saves speedrun result to a csv file.\n" + "Usage: sar_speedrun_export \n", + SourceGame_SupportsS3) { if (args.ArgC() != 2) { return console->Print(sar_speedrun_export.ThisPtr()->m_pszHelpString); @@ -548,8 +553,10 @@ CON_COMMAND(sar_speedrun_export, "Saves speedrun result to a csv file.\n" console->Warning("Failed to export result!\n"); } } -CON_COMMAND(sar_speedrun_export_pb, "Saves speedrun personal best to a csv file.\n" - "Usage: sar_speedrun_export_pb \n") +CON_COMMAND_U(sar_speedrun_export_pb, + "Saves speedrun personal best to a csv file.\n" + "Usage: sar_speedrun_export_pb \n", + SourceGame_SupportsS3) { if (args.ArgC() != 2) { return console->Print(sar_speedrun_export_pb.ThisPtr()->m_pszHelpString); @@ -565,9 +572,10 @@ CON_COMMAND(sar_speedrun_export_pb, "Saves speedrun personal best to a csv file. console->Warning("Failed to export personal best!\n"); } } -CON_COMMAND_AUTOCOMPLETEFILE(sar_speedrun_import, "Imports speedrun data file.\n" - "Usage: sar_speedrun_import \n", - 0, 0, csv) +CON_COMMAND_AUTOCOMPLETEFILE_U(sar_speedrun_import, + "Imports speedrun data file.\n" + "Usage: sar_speedrun_import \n", + 0, 0, csv, SourceGame_SupportsS3) { if (args.ArgC() != 2) { return console->Print(sar_speedrun_import.ThisPtr()->m_pszHelpString); @@ -583,7 +591,9 @@ CON_COMMAND_AUTOCOMPLETEFILE(sar_speedrun_import, "Imports speedrun data file.\n console->Warning("Failed to import file!\n"); } } -CON_COMMAND_F_COMPLETION(sar_speedrun_category, "Sets the category for a speedrun.\n", 0, sar_category_CompletionFunc) +CON_COMMAND_FU_COMPLETION(sar_speedrun_category, + "Sets the category for a speedrun.\n", + 0, sar_category_CompletionFunc, SourceGame_SupportsS3) { if (!speedrun->GetCategory() || TimerCategory::GetList().empty()) { return console->Print("This game does not have any categories!\n"); @@ -611,7 +621,7 @@ CON_COMMAND_F_COMPLETION(sar_speedrun_category, "Sets the category for a speedru return PrintCategory(); } -CON_COMMAND(sar_speedrun_offset, "Sets offset in ticks at which the timer should start.\n") +CON_COMMAND_U(sar_speedrun_offset, "Sets offset in ticks at which the timer should start.\n", SourceGame_SupportsS3) { if (args.ArgC() == 2) { if (speedrun->IsActive()) { @@ -626,5 +636,6 @@ CON_COMMAND(sar_speedrun_offset, "Sets offset in ticks at which the timer should speedrun->SetOffset(offset); } - console->Print("Timer will start at: %s\n", SpeedrunTimer::Format(speedrun->GetOffset() * speedrun->GetIntervalPerTick()).c_str()); + auto start = speedrun->GetOffset() * speedrun->GetIntervalPerTick(); + console->Print("Timer will start at: %s\n", SpeedrunTimer::Format(start).c_str()); } diff --git a/src/Features/Speedrun/SpeedrunTimer.hpp b/src/Features/Speedrun/SpeedrunTimer.hpp index 3c5966c2..21caa949 100644 --- a/src/Features/Speedrun/SpeedrunTimer.hpp +++ b/src/Features/Speedrun/SpeedrunTimer.hpp @@ -38,6 +38,7 @@ class SpeedrunTimer : public Feature { TimerCategory* category; int offset; int pause; + public: std::vector visitedMaps; diff --git a/src/Features/Speedrun/TimerRule.cpp b/src/Features/Speedrun/TimerRule.cpp index 94d2ef43..df49b269 100644 --- a/src/Features/Speedrun/TimerRule.cpp +++ b/src/Features/Speedrun/TimerRule.cpp @@ -16,6 +16,8 @@ TimerRule::TimerRule(const char* name, const char* mapName, const char* entityNa , name(name) , mapName(mapName) , entityName(entityName) + , className(nullptr) + , propName(nullptr) , callback0(callback) , entityPtr(nullptr) , callbackType(0) @@ -45,7 +47,8 @@ TimerRule::TimerRule(const char* name, const char* mapName, const char* entityNa bool TimerRule::Load() { if (this->IsEmpty()) { - return this->isActive = true; + this->isActive = true; + return true; } auto info = (this->searchMode == SearchMode::Classes) diff --git a/src/Features/Speedrun/TimerRule.hpp b/src/Features/Speedrun/TimerRule.hpp index ca5cbc01..78d0e2f3 100644 --- a/src/Features/Speedrun/TimerRule.hpp +++ b/src/Features/Speedrun/TimerRule.hpp @@ -61,7 +61,7 @@ class TimerRule { TimerAction ruleName##_callback(void* entity); \ TimerRule ruleName = TimerRule(#ruleName, mapName, entityName, ruleName##_callback, searchMode); \ TimerAction ruleName##_callback(void* entity) -#define SAR_RULE0(ruleName) \ - TimerAction ruleName##_callback(void* entity); \ +#define SAR_RULE0(ruleName) \ + TimerAction ruleName##_callback(void* entity); \ TimerRule ruleName = TimerRule(#ruleName, nullptr, nullptr, ruleName##_callback); \ TimerAction ruleName##_callback(void* entity) diff --git a/src/Features/Stats/Stats.cpp b/src/Features/Stats/Stats.cpp index e0dc2aa4..554ed2c2 100644 --- a/src/Features/Stats/Stats.cpp +++ b/src/Features/Stats/Stats.cpp @@ -31,8 +31,6 @@ Stats::Stats() for (auto i = 0; i < Offsets::MAX_SPLITSCREEN_PLAYERS; ++i) { this->playerStats.push_back(new PlayerStats()); } - - this->hasLoaded = true; } Stats::~Stats() { @@ -113,12 +111,18 @@ CON_COMMAND(sar_stats_reset, "Resets all saved stats.\n") // HUD -HUD_ELEMENT2(jumps, "0", "Draws total jump count.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT2(jumps, "0", + "Draws total jump count.\n", + HudType_InGame | HudType_Paused) { auto stat = stats->Get(ctx->slot); ctx->DrawElement("jumps: %i", stat->jumps->total); } -HUD_ELEMENT3(portals, "0", "Draws total portal count.\n", HudType_InGame | HudType_Paused, true, SourceGame_Portal2Game | SourceGame_Portal) +HUD_ELEMENT3(portals, "0", + "Draws total portal count.\n", + HudType_InGame | HudType_Paused, + true, + SourceGame_Portal2Game | SourceGame_Portal) { auto player = server->GetPlayer(ctx->slot + 1); if (player) { @@ -127,22 +131,30 @@ HUD_ELEMENT3(portals, "0", "Draws total portal count.\n", HudType_InGame | HudTy ctx->DrawElement("portals: -"); } } -HUD_ELEMENT2(steps, "0", "Draws total step count.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT2(steps, "0", + "Draws total step count.\n", + HudType_InGame | HudType_Paused) { auto stat = stats->Get(ctx->slot); ctx->DrawElement("steps: %i", stat->steps->total); } -HUD_ELEMENT2(jump, "0", "Draws current jump distance.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT2(jump, "0", + "Draws current jump distance.\n", + HudType_InGame | HudType_Paused) { auto stat = stats->Get(ctx->slot); ctx->DrawElement("jump: %.3f", stat->jumps->distance); } -HUD_ELEMENT2(jump_peak, "0", "Draws longest jump distance.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT2(jump_peak, "0", + "Draws longest jump distance.\n", + HudType_InGame | HudType_Paused) { auto stat = stats->Get(ctx->slot); ctx->DrawElement("jump peak: %.3f", stat->jumps->distancePeak); } -HUD_ELEMENT2(velocity_peak, "0", "Draws last saved velocity peak.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT2(velocity_peak, "0", + "Draws last saved velocity peak.\n", + HudType_InGame | HudType_Paused) { auto stat = stats->Get(ctx->slot); ctx->DrawElement("vel peak: %.3f", stat->velocity->peak); diff --git a/src/Features/Stats/Stats.hpp b/src/Features/Stats/Stats.hpp index fc83da0d..3efe93b4 100644 --- a/src/Features/Stats/Stats.hpp +++ b/src/Features/Stats/Stats.hpp @@ -5,8 +5,8 @@ #include "StepStats.hpp" #include "VelocityStats.hpp" -#include "Features/Hud/Hud.hpp" #include "Features/Feature.hpp" +#include "Features/Hud/Hud.hpp" #include "Variable.hpp" @@ -29,9 +29,9 @@ struct PlayerStats { } ~PlayerStats() { - SAFE_DELETE(this->jumps); - SAFE_DELETE(this->steps); - SAFE_DELETE(this->velocity); + sdelete(this->jumps); + sdelete(this->steps); + sdelete(this->velocity); } }; diff --git a/src/Features/StepCounter.cpp b/src/Features/StepCounter.cpp index 2cd79e11..8a2159f0 100644 --- a/src/Features/StepCounter.cpp +++ b/src/Features/StepCounter.cpp @@ -7,7 +7,6 @@ StepCounter* stepCounter; StepCounter::StepCounter() : stepSoundTime(0) { - this->hasLoaded = true; } // Calculate when to play next step sound void StepCounter::ReduceTimer(float frametime) diff --git a/src/Features/Summary.cpp b/src/Features/Summary.cpp index 3ee89284..a89e84d7 100644 --- a/src/Features/Summary.cpp +++ b/src/Features/Summary.cpp @@ -5,7 +5,6 @@ #include "Modules/Console.hpp" #include "Modules/Engine.hpp" - #include "Command.hpp" #include "Variable.hpp" @@ -18,7 +17,6 @@ Summary::Summary() , items() , totalTicks(0) { - this->hasLoaded = true; } void Summary::Start() { diff --git a/src/Features/Tas/AutoStrafer.cpp b/src/Features/Tas/AutoStrafer.cpp index 59f8febc..2929f74a 100644 --- a/src/Features/Tas/AutoStrafer.cpp +++ b/src/Features/Tas/AutoStrafer.cpp @@ -24,8 +24,6 @@ AutoStrafer::AutoStrafer() for (auto i = 0; i < Offsets::MAX_SPLITSCREEN_PLAYERS; ++i) { this->states.push_back(new StrafeState()); } - - this->hasLoaded = true; } AutoStrafer::~AutoStrafer() { @@ -155,12 +153,14 @@ float AutoStrafer::GetStrafeAngle(const StrafeState* strafe, void* pPlayer, cons void IN_AutoStrafeDown(const CCommand& args) { client->KeyDown(&autoStrafer->in_autostrafe, (args.ArgC() > 1) ? args[1] : nullptr); } void IN_AutoStrafeUp(const CCommand& args) { client->KeyUp(&autoStrafer->in_autostrafe, (args.ArgC() > 1) ? args[1] : nullptr); } -Command startautostrafe("+autostrafe", IN_AutoStrafeDown, "Auto-strafe button.\n"); -Command endautostrafe("-autostrafe", IN_AutoStrafeUp, "Auto-strafe button.\n"); +Command startautostrafe("+autostrafe", IN_AutoStrafeDown, "Auto-strafe button.\n", SourceGame_Portal2Engine); +Command endautostrafe("-autostrafe", IN_AutoStrafeUp, "Auto-strafe button.\n", SourceGame_Portal2Engine); -CON_COMMAND(sar_tas_strafe, "sar_tas_strafe : Automatic strafing.\n" - "Type: 0 = off, 1 = straight, 2 = turning and keeping velocity, 3 = turning with velocity gain.\n" - "Direction: -1 = left, 1 = right.\n") +CON_COMMAND_U(sar_tas_strafe, + "sar_tas_strafe : Automatic strafing.\n" + "Type: 0 = off, 1 = straight, 2 = turning and keeping velocity, 3 = turning with velocity gain.\n" + "Direction: -1 = left, 1 = right.\n", + SourceGame_Portal2Engine) { IGNORE_DEMO_PLAYER(); @@ -180,11 +180,13 @@ CON_COMMAND(sar_tas_strafe, "sar_tas_strafe : Automatic straf autoStrafer->states[nSlot]->type = type; autoStrafer->states[nSlot]->direction = direction; } -CON_COMMAND(sar_tas_strafe_vectorial, "sar_tas_strafe_vectorial : Change type of vectorial strafing.\n" - "0 = Auto-strafer calculates perfect viewangle,\n" - "1 = Auto-strafer calculates perfect forward-side movement,\n" - "2 = Auto-strafer calculates perfect forward-side movement, " - "while setting the viewangle toward current velocity, to make strafing visually visible.\n") +CON_COMMAND_U(sar_tas_strafe_vectorial, + "sar_tas_strafe_vectorial : Change type of vectorial strafing.\n" + "0 = Auto-strafer calculates perfect viewangle,\n" + "1 = Auto-strafer calculates perfect forward-side movement,\n" + "2 = Auto-strafer calculates perfect forward-side movement, " + "while setting the viewangle toward current velocity, to make strafing visually visible.\n", + SourceGame_Portal2Engine) { IGNORE_DEMO_PLAYER(); diff --git a/src/Features/Tas/CommandQueuer.cpp b/src/Features/Tas/CommandQueuer.cpp index 0107bce5..895297b0 100644 --- a/src/Features/Tas/CommandQueuer.cpp +++ b/src/Features/Tas/CommandQueuer.cpp @@ -11,8 +11,11 @@ #include "Command.hpp" #include "Variable.hpp" -Variable sar_tas_autostart("sar_tas_autostart", "1", "Starts queued commands automatically on first frame after a load.\n"); -Variable sar_tas_ss_forceuser("sar_tas_ss_forceuser", "0", "Forces engine to calculate movement for every splitescreen client.\n"); +Variable sar_tas_autostart("sar_tas_autostart", "1", + "Starts queued commands automatically on first frame after a load.\n"); +Variable sar_tas_ss_forceuser("sar_tas_ss_forceuser", "0", + "Forces engine to calculate movement for every splitescreen client.\n", + SourceGame_Portal2 | SourceGame_ApertureTag); CommandQueuer* cmdQueuer; @@ -26,7 +29,6 @@ CommandQueuer::CommandQueuer() , floatRegex("\\[" + numberRegex + ":" + numberRegex + "\\]") , intRegex("\\{" + numberRegex + ":" + numberRegex + "\\}") { - this->hasLoaded = true; } void CommandQueuer::AddFrame(int framesLeft, std::string command, bool relative) { @@ -97,7 +99,6 @@ void CommandQueuer::RandomRegex(std::string& input) input = std::regex_replace(input, this->floatRegex, std::to_string(rand), std::regex_constants::format_first_only); } - for (std::sregex_iterator it = std::sregex_iterator(input.begin(), input.end(), this->intRegex); it != std::sregex_iterator(); ++it) { std::smatch m = *it; int rand = Math::RandomNumber(std::stoi(m.str(1)), std::stoi(m.str(6))); @@ -220,8 +221,10 @@ CON_COMMAND(sar_tas_reset, "Stops executing commands and clears them from the qu cmdQueuer->Reset(); } -CON_COMMAND(sar_tas_ss, "Select split screen index for command buffer (0 or 1).\n" - "Usage: sar_tas_ss \n") +CON_COMMAND_U(sar_tas_ss, + "Select split screen index for command buffer (0 or 1).\n" + "Usage: sar_tas_ss \n", + SourceGame_Portal2 | SourceGame_ApertureTag) { IGNORE_DEMO_PLAYER(); diff --git a/src/Features/Tas/TasTools.cpp b/src/Features/Tas/TasTools.cpp index 0b4c485d..02a569e2 100644 --- a/src/Features/Tas/TasTools.cpp +++ b/src/Features/Tas/TasTools.cpp @@ -35,8 +35,6 @@ TasTools::TasTools() } offsetFinder->ServerSide(this->className, this->propName, &this->propOffset); - - this->hasLoaded = true; } TasTools::~TasTools() { @@ -275,7 +273,9 @@ CON_COMMAND(sar_tas_setang, "sar_tas_setang [z] [speed] : Sets {x, y, z} // HUD -HUD_ELEMENT2(velocity_angle, "0", "Draws velocity angles.\n", HudType_InGame | HudType_Paused | HudType_LoadingScreen) +HUD_ELEMENT2(velocity_angle, "0", + "Draws velocity angles.\n", + HudType_InGame | HudType_Paused | HudType_LoadingScreen) { auto player = server->GetPlayer(ctx->slot + 1); if (player) { @@ -285,7 +285,9 @@ HUD_ELEMENT2(velocity_angle, "0", "Draws velocity angles.\n", HudType_InGame | H ctx->DrawElement("vel ang: -"); } } -HUD_ELEMENT_MODE2(acceleration, "0", 0, 2, "Draws instant acceleration.\n", HudType_InGame | HudType_Paused | HudType_LoadingScreen) +HUD_ELEMENT_MODE2(acceleration, "0", 0, 2, + "Draws instant acceleration.\n", + HudType_InGame | HudType_Paused | HudType_LoadingScreen) { auto player = server->GetPlayer(ctx->slot + 1); if (player) { @@ -299,7 +301,8 @@ HUD_ELEMENT_MODE2(acceleration, "0", 0, 2, "Draws instant acceleration.\n", HudT ctx->DrawElement("accel: -"); } } -HUD_ELEMENT2(player_info, "0", "Draws player state defined with sar_tas_set_prop.\n", HudType_InGame | HudType_Paused | HudType_LoadingScreen) +HUD_ELEMENT2(player_info, "0", "Draws player state defined with sar_tas_set_prop.\n", + HudType_InGame | HudType_Paused | HudType_LoadingScreen) { auto player = server->GetPlayer(ctx->slot + 1); auto info = tasTools->GetPlayerInfo(player); diff --git a/src/Features/Tas/TasTools.hpp b/src/Features/Tas/TasTools.hpp index 9786b984..8305d5d4 100644 --- a/src/Features/Tas/TasTools.hpp +++ b/src/Features/Tas/TasTools.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include "Features/Hud/Hud.hpp" #include "Features/Feature.hpp" +#include "Features/Hud/Hud.hpp" #include "Utils/SDK.hpp" diff --git a/src/Features/Teleporter.cpp b/src/Features/Teleporter.cpp index 0475ffbe..4c3bd70a 100644 --- a/src/Features/Teleporter.cpp +++ b/src/Features/Teleporter.cpp @@ -17,8 +17,6 @@ Teleporter::Teleporter() for (auto i = 0; i < Offsets::MAX_SPLITSCREEN_PLAYERS; ++i) { this->locations.push_back(new TeleportLocation()); } - - this->hasLoaded = true; } Teleporter::~Teleporter() { diff --git a/src/Features/Timer/PauseTimer.cpp b/src/Features/Timer/PauseTimer.cpp index 0843bf14..de27e0d2 100644 --- a/src/Features/Timer/PauseTimer.cpp +++ b/src/Features/Timer/PauseTimer.cpp @@ -10,7 +10,6 @@ PauseTimer::PauseTimer() : isActive(false) , ticks(0) { - this->hasLoaded = true; } void PauseTimer::Start() { @@ -36,7 +35,9 @@ int PauseTimer::GetTotal() // HUD -HUD_ELEMENT(pause_timer, "0", "Draws current value of pause timer.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT(pause_timer, "0", + "Draws current value of pause timer.\n", + HudType_InGame | HudType_Paused) { auto tick = pauseTimer->GetTotal(); auto time = engine->ToTime(tick); diff --git a/src/Features/Timer/Timer.cpp b/src/Features/Timer/Timer.cpp index 6de6108a..0dfb68e7 100644 --- a/src/Features/Timer/Timer.cpp +++ b/src/Features/Timer/Timer.cpp @@ -27,12 +27,11 @@ Timer::Timer() , avg(new TimerAverage()) , cps(new TimerCheckPoints()) { - this->hasLoaded = this->avg && this->cps; } Timer::~Timer() { - SAFE_DELETE(this->avg) - SAFE_DELETE(this->cps) + sdelete(this->avg) + sdelete(this->cps) } void Timer::Start(int engineTick) { @@ -179,17 +178,23 @@ CON_COMMAND(sar_cps_result, "Prints result of timer checkpoints.\n") // HUD -HUD_ELEMENT(timer, "0", "Draws current value of timer.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT(timer, "0", + "Draws current value of timer.\n", + HudType_InGame | HudType_Paused) { auto tick = (!timer->isPaused) ? timer->GetTick(engine->GetTick()) : timer->totalTicks; auto time = engine->ToTime(tick); ctx->DrawElement("timer: %i (%.3f)", tick, time); } -HUD_ELEMENT(avg, "0", "Draws calculated average of timer.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT(avg, "0", + "Draws calculated average of timer.\n", + HudType_InGame | HudType_Paused) { ctx->DrawElement("avg: %i (%.3f)", timer->avg->averageTicks, timer->avg->averageTime); } -HUD_ELEMENT(cps, "0", "Draws latest checkpoint of timer.\n", HudType_InGame | HudType_Paused) +HUD_ELEMENT(cps, "0", + "Draws latest checkpoint of timer.\n", + HudType_InGame | HudType_Paused) { ctx->DrawElement("last cp: %i (%.3f)", timer->cps->latestTick, timer->cps->latestTime); } diff --git a/src/Features/WorkshopList.cpp b/src/Features/WorkshopList.cpp index 04a94b1f..84b80f1f 100644 --- a/src/Features/WorkshopList.cpp +++ b/src/Features/WorkshopList.cpp @@ -1,7 +1,13 @@ #include "WorkshopList.hpp" #include +#if _WIN32 +#include +#define fs std::filesystem +#else #include +#define fs std::experimental::filesystem +#endif #include #include "Modules/Engine.hpp" @@ -15,7 +21,6 @@ WorkshopList::WorkshopList() : maps() , path(std::string(engine->GetGameDirectory()) + std::string("/maps/workshop")) { - this->hasLoaded = true; } int WorkshopList::Update() { @@ -26,10 +31,10 @@ int WorkshopList::Update() auto index = path.length() + 1; // Scan through all directories and find the map file - for (auto& dir : std::experimental::filesystem::recursive_directory_iterator(path)) { - if (dir.status().type() == std::experimental::filesystem::file_type::directory) { + for (auto& dir : fs::recursive_directory_iterator(path)) { + if (dir.status().type() == fs::file_type::directory) { auto curdir = dir.path().string(); - for (auto& dirdir : std::experimental::filesystem::directory_iterator(curdir)) { + for (auto& dirdir : fs::directory_iterator(curdir)) { auto file = dirdir.path().string(); if (Utils::EndsWith(file, std::string(".bsp"))) { auto map = file.substr(index); @@ -71,10 +76,10 @@ DECL_COMMAND_COMPLETION(sar_workshop) // Commands -CON_COMMAND_F_COMPLETION(sar_workshop, "Same as \"map\" command but lists workshop maps.\n" - "Usage: sar_workshop [ss/changelevel]\n", - 0, - sar_workshop_CompletionFunc) +CON_COMMAND_FU_COMPLETION(sar_workshop, + "Same as \"map\" command but lists workshop maps.\n" + "Usage: sar_workshop [ss/changelevel]\n", + 0, sar_workshop_CompletionFunc, SourceGame_Portal2 | SourceGame_ApertureTag) { if (args.ArgC() < 2) { return console->Print(sar_workshop.ThisPtr()->m_pszHelpString); @@ -92,11 +97,11 @@ CON_COMMAND_F_COMPLETION(sar_workshop, "Same as \"map\" command but lists worksh engine->ExecuteCommand((command + std::string(" workshop/") + std::string(args[1])).c_str()); } -CON_COMMAND(sar_workshop_update, "Updates the workshop map list.\n") +CON_COMMAND_U(sar_workshop_update, "Updates the workshop map list.\n", SourceGame_Portal2 | SourceGame_ApertureTag) { console->Print("Added or removed %i map(s) to or from the list.\n", workshop->Update()); } -CON_COMMAND(sar_workshop_list, "Prints all workshop maps.\n") +CON_COMMAND_U(sar_workshop_list, "Prints all workshop maps.\n", SourceGame_Portal2 | SourceGame_ApertureTag) { if (workshop->maps.empty()) { workshop->Update(); diff --git a/src/Features/WorkshopList.hpp b/src/Features/WorkshopList.hpp index 281a7773..6acd5f74 100644 --- a/src/Features/WorkshopList.hpp +++ b/src/Features/WorkshopList.hpp @@ -13,7 +13,6 @@ class WorkshopList : public Feature { public: WorkshopList(); - std::string Path(); int Update(); }; diff --git a/src/Game.hpp b/src/Game.hpp index 29453739..81cbfe9a 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -14,7 +14,7 @@ enum SourceGameVersion { SourceGame_PortalStoriesMel = (1 << 6), SourceGame_ThinkingWithTimeMachine = (1 << 7), - SourceGame_INFRA = (1 << 8), + SourceGame_INFRA = (1 << 8), SourceGame_HalfLife2Episodic = (1 << 9), SourceGame_HalfLifeSource = (1 << 10), diff --git a/src/Games/Linux/Portal2.cpp b/src/Games/Linux/Portal2.cpp index 11a30db2..45fa78ec 100644 --- a/src/Games/Linux/Portal2.cpp +++ b/src/Games/Linux/Portal2.cpp @@ -24,7 +24,6 @@ void Portal2::LoadOffsets() Cbuf_AddText = 45; // CEngineClient::ClientCmd s_CommandBuffer = 69; // Cbuf_AddText CCommandBufferSize = 9556; // Cbuf_AddText - m_bWaitEnabled = 8265; // CCommandBuffer::AddText GetLocalPlayer = 12; // CEngineClient GetViewAngles = 18; // CEngineClient SetViewAngles = 19; // CEngineClient diff --git a/src/Games/Linux/TheStanleyParable.cpp b/src/Games/Linux/TheStanleyParable.cpp index e27e7957..ec69d017 100644 --- a/src/Games/Linux/TheStanleyParable.cpp +++ b/src/Games/Linux/TheStanleyParable.cpp @@ -18,7 +18,6 @@ void TheStanleyParable::LoadOffsets() GetLocalClient = 92; // CEngineClient::SetViewAngles viewangles = 19084; // CEngineClient::SetViewAngles s_CommandBuffer = 71; // Cbuf_AddText - //m_bWaitEnabled = 8264; // CCommandBuffer::AddText tickcount = 74; // CClientState::ProcessTick interval_per_tick = 82; // CClientState::ProcessTick HostState_OnClientConnected = 1523; // CClientState::SetSignonState diff --git a/src/Games/Windows/Portal2.cpp b/src/Games/Windows/Portal2.cpp index 4f8adc66..2c4101b5 100644 --- a/src/Games/Windows/Portal2.cpp +++ b/src/Games/Windows/Portal2.cpp @@ -24,7 +24,6 @@ void Portal2::LoadOffsets() Cbuf_AddText = 46; // CEngineClient::ClientCmd s_CommandBuffer = 82; // Cbuf_AddText CCommandBufferSize = 9556; // Cbuf_AddText - m_bWaitEnabled = 8265; // CCommandBuffer::AddText GetLocalPlayer = 12; // CEngineClient GetViewAngles = 18; // CEngineClient SetViewAngles = 19; // CEngineClient diff --git a/src/Games/Windows/TheStanleyParable.cpp b/src/Games/Windows/TheStanleyParable.cpp index 05f9e07e..6e54096a 100644 --- a/src/Games/Windows/TheStanleyParable.cpp +++ b/src/Games/Windows/TheStanleyParable.cpp @@ -17,7 +17,6 @@ void TheStanleyParable::LoadOffsets() GetLocalClient = 138; // CEngineClient::SetViewAngles viewangles = 19112; // CEngineClient::SetViewAngles - //m_bWaitEnabled = 8264; // CCommandBuffer::AddText tickcount = 103; // CClientState::ProcessTick interval_per_tick = 73; // CClientState::ProcessTick HostState_OnClientConnected = 695; // CClientState::SetSignonStatey diff --git a/src/Interface.cpp b/src/Interface.cpp index 1ff20e8b..4a5b2669 100644 --- a/src/Interface.cpp +++ b/src/Interface.cpp @@ -1,8 +1,11 @@ #include "Interface.hpp" #include +#include +#include #include "Modules/Console.hpp" +#include "Modules/Module.hpp" #include "Utils/Memory.hpp" #include "Utils/SDK.hpp" @@ -14,88 +17,184 @@ #define s_pInterfaceRegs_Offset 11 #endif -Interface::Interface() - : baseclass(nullptr) - , vtable(nullptr) - , vtableSize(0) - , isHooked(false) - , copy(nullptr) +Interface::Interface(void* baseclass) + : Interface(reinterpret_cast(baseclass)) { } -Interface::Interface(void* baseclass, bool copyVtable, bool autoHook) - : Interface() +Interface::Interface(uintptr_t baseclass) { this->baseclass = reinterpret_cast(baseclass); this->vtable = *this->baseclass; - - while (this->vtable[this->vtableSize]) { - ++this->vtableSize; - } - - if (copyVtable) { - this->CopyVtable(); - if (autoHook) { - this->EnableHooks(); - } - } } Interface::~Interface() { this->DisableHooks(); if (this->copy) { - this->copy.reset(); + delete[] this->copy; + this->copy = nullptr; } + this->hooks.clear(); } -void Interface::CopyVtable() +void Interface::AllocVtable() { if (!this->copy) { - this->copy = std::make_unique(this->vtableSize + 1); - std::memcpy(this->copy.get(), this->vtable - 1, sizeof(uintptr_t) + this->vtableSize * sizeof(uintptr_t)); + this->vtableSize = 0; + while (this->vtable[this->vtableSize]) { + ++this->vtableSize; + } + + this->copy = new uintptr_t[this->vtableSize + 1]; + std::memcpy(this->copy, this->vtable - 1, sizeof(uintptr_t) + this->vtableSize * sizeof(uintptr_t)); + + for (auto const& hk : this->hooks) { + auto index = hk.first; + auto hook = hk.second; + + if (index >= 0 && index < this->vtableSize) { + this->copy[index + 1] = hook->detour; + *hook->original = this->Original(index); + } else { + throw std::runtime_error("invalid vtable index value of " + std::to_string(index)); + } + } } } void Interface::EnableHooks() { - if (!this->isHooked) { - *this->baseclass = this->copy.get() + 1; + this->AllocVtable(); + + if (this->IsHookable() && !this->isHooked) { + *this->baseclass = this->copy + 1; this->isHooked = true; } } void Interface::DisableHooks() { - if (this->isHooked) { + if (this->IsHookable() && this->isHooked) { *this->baseclass = this->vtable; this->isHooked = false; } } bool Interface::Unhook(int index) { - if (index >= 0 && index < this->vtableSize) { + if (this->IsHookable() && index >= 0 && index < this->vtableSize) { this->copy[index + 1] = this->vtable[index]; return true; } return false; } -Interface* Interface::Create(void* ptr, bool copyVtable, bool autoHook) + +void Interface::Hook(VHook* hook, int index) +{ + if (this->IsHookable()) { + throw std::runtime_error("interface is not hookable"); + } + if (this->hooks.find(index) != this->hooks.end()) { + throw std::runtime_error("vtable index already in use"); + } + this->hooks.insert({ index, hook }); +} + +Interface* Interface::CreateNew(void* ptr) +{ + return (ptr) ? new Interface(ptr) : throw std::runtime_error("called Interface::CreateNew with nullptr"); +} +Interface* Interface::CreateNew(uintptr_t ptr) +{ + return (ptr) ? new Interface(ptr) : throw std::runtime_error("called Interface::CreateNew with nullptr"); +} +Interface* Interface::CreateNew(const Module* mod, const char* interfaceSymbol) +{ + auto ptr = Interface::This(mod, interfaceSymbol); + return (ptr) ? new Interface(ptr) : throw std::runtime_error("Interface::This could not resolve interface"); +} + +Interface* Interface::Hookable(Module* mod, void* ptr) +{ + if (!ptr) { + throw std::runtime_error("called Interface::Hookable with nullptr"); + } + + auto res = new Interface(ptr); + mod->interfaces.push_back(res); + return res; +} +Interface* Interface::Hookable(Module* mod, uintptr_t ptr) { - return (ptr) ? new Interface(ptr, copyVtable, autoHook) : nullptr; + if (!ptr) { + throw std::runtime_error("called Interface::Hookable with nullptr"); + } + + auto res = new Interface(ptr); + mod->interfaces.push_back(res); + return res; } -Interface* Interface::Create(const char* filename, const char* interfaceSymbol, bool copyVtable, bool autoHook) +Interface* Interface::Hookable(Module* mod, const char* interfaceSymbol) { - auto ptr = Interface::GetPtr(filename, interfaceSymbol); - return (ptr) ? new Interface(ptr, copyVtable, autoHook) : nullptr; + auto ptr = Interface::This(mod, interfaceSymbol); + if (!ptr) { + throw std::runtime_error("Interface::This could not resolve interface"); + } + + auto res = new Interface(ptr); + mod->interfaces.push_back(res); + return res; +} + +void Interface::Temp(void* ptr, std::function callback) +{ + if (!ptr) { + throw std::runtime_error("called Interface::Temp with nullptr"); + } + + auto temp = Interface(ptr); + try { + callback(&temp); + } catch (std::exception& ex) { + throw ex; + } } -void Interface::Delete(Interface* ptr) +void Interface::Temp(uintptr_t ptr, std::function callback) +{ + if (!ptr) { + throw std::runtime_error("called Interface::Temp with nullptr"); + } + + auto temp = Interface(ptr); + try { + callback(&temp); + } catch (std::exception& ex) { + throw ex; + } +} +void Interface::Temp(const Module* mod, const char* interfaceSymbol, std::function callback) +{ + auto ptr = Interface::This(mod, interfaceSymbol); + if (!ptr) { + throw std::runtime_error("Interface::This could not resolve interface"); + } + + auto temp = Interface(ptr); + try { + callback(&temp); + } catch (std::exception& ex) { + throw ex; + } +} + +void Interface::Destroy(Interface* ptr) { if (ptr) { delete ptr; ptr = nullptr; } } -void* Interface::GetPtr(const char* filename, const char* interfaceSymbol) + +void* Interface::This(const Module* mod, const char* interfaceSymbol) { - auto handle = Memory::GetModuleHandleByName(filename); + auto handle = Memory::GetModuleHandleByName(mod->filename); if (!handle) { - console->DevWarning("SAR: Failed to open module %s!\n", filename); + console->DevWarning("SAR: Failed to open module %s!\n", mod->filename); return nullptr; } @@ -103,7 +202,7 @@ void* Interface::GetPtr(const char* filename, const char* interfaceSymbol) Memory::CloseModuleHandle(handle); if (!CreateInterface) { - console->DevWarning("SAR: Failed to find symbol CreateInterface for %s!\n", filename); + console->DevWarning("SAR: Failed to find symbol CreateInterface for %s!\n", mod->filename); return nullptr; } @@ -120,13 +219,12 @@ void* Interface::GetPtr(const char* filename, const char* interfaceSymbol) for (auto& current = s_pInterfaceRegs; current; current = current->m_pNext) { if (std::strncmp(current->m_pName, interfaceSymbol, std::strlen(interfaceSymbol)) == 0) { result = current->m_CreateFn(); - //console->DevMsg("SAR: Found interface %s at %p in %s!\n", current->m_pName, result, filename); break; } } if (!result) { - console->DevWarning("SAR: Failed to find interface with symbol %s in %s!\n", interfaceSymbol, filename); + console->DevWarning("SAR: Failed to find interface with symbol %s in %s!\n", interfaceSymbol, mod->filename); return nullptr; } return result; diff --git a/src/Interface.hpp b/src/Interface.hpp index 30955e9c..226a0020 100644 --- a/src/Interface.hpp +++ b/src/Interface.hpp @@ -1,27 +1,42 @@ #pragma once +#include "Modules/Module.hpp" + +#include +#include +#include + #include "Utils/Memory.hpp" +#include "Utils/Platform.hpp" + +class Module; class Interface { public: - uintptr_t** baseclass; - uintptr_t* vtable; - int vtableSize; + uintptr_t** baseclass = nullptr; + uintptr_t* vtable = nullptr; + int vtableSize = 0; private: - bool isHooked; - std::unique_ptr copy; + bool isHooked = false; + uintptr_t* copy = nullptr; + std::map hooks = std::map(); public: - Interface(); - Interface(void* baseclass, bool copyVtable = true, bool autoHook = true); + Interface(void* baseclass); + Interface(uintptr_t baseclass); ~Interface(); - void CopyVtable(); +private: + void AllocVtable(); + +public: void EnableHooks(); void DisableHooks(); + inline bool IsHookable() { return this->copy != nullptr; } + template - T Original(int index, bool readJmp = false) + T Original(int index, bool readJmp = false) const { if (readJmp) { auto source = this->vtable[index] + 1; @@ -33,39 +48,47 @@ class Interface { template T Hooked(int index) { - return (T)this->copy[index + 1]; + return IsHookable() ? (T)this->copy[index + 1] : (T) nullptr; } template T Current(int index) { return (T)(*this->baseclass)[index]; } - template - bool Hook(T detour, U& original, int index) - { - if (index >= 0 && index < this->vtableSize) { - this->copy[index + 1] = reinterpret_cast(detour); - original = this->Original(index); - return true; - } - return false; - } bool Unhook(int index); - inline void* ThisPtr() + inline void* ThisPtr() const { return reinterpret_cast(this->baseclass); } - static Interface* Create(void* ptr, bool copyVtable = true, bool autoHook = true); - static Interface* Create(const char* filename, const char* interfaceSymbol, bool copyVtable = true, bool autoHook = true); - static void Delete(Interface* ptr); - static void* GetPtr(const char* filename, const char* interfaceSymbol); + void Hook(VHook* hook, int index); + + inline uintptr_t ThisUPtr() + { + return reinterpret_cast(this->baseclass); + } + + static Interface* CreateNew(void* ptr); + static Interface* CreateNew(uintptr_t ptr); + static Interface* CreateNew(const Module* mod, const char* interfaceSymbol); + + static Interface* Hookable(Module* mod, void* ptr); + static Interface* Hookable(Module* mod, uintptr_t ptr); + static Interface* Hookable(Module* mod, const char* interfaceSymbol); + + static void Temp(void* ptr, std::function callback); + static void Temp(uintptr_t ptr, std::function callback); + static void Temp(const Module* mod, const char* interfaceSymbol, std::function callback); + + static void Destroy(Interface* ptr); + + static void* This(const Module* mod, const char* interfaceSymbol); template - static T Get(const char* filename, const char* interfaceSymbol) + static T This(const Module* mod, const char* interfaceSymbol) { - return (T)Interface::GetPtr(filename, interfaceSymbol); + return (T)Interface::This(mod, interfaceSymbol); } }; diff --git a/src/Modules/Client.cpp b/src/Modules/Client.cpp index 0c8efbc0..f7ae5cf3 100644 --- a/src/Modules/Client.cpp +++ b/src/Modules/Client.cpp @@ -29,21 +29,6 @@ Variable cl_forwardspeed; Variable in_forceuser; Variable cl_fov; -REDECL(Client::HudUpdate); -REDECL(Client::CreateMove); -REDECL(Client::CreateMove2); -REDECL(Client::GetName); -REDECL(Client::DecodeUserCmdFromBuffer); -REDECL(Client::DecodeUserCmdFromBuffer2); -REDECL(Client::CInput_CreateMove); -REDECL(Client::GetButtonBits); -REDECL(Client::playvideo_end_level_transition_callback); - -MDECL(Client::GetAbsOrigin, Vector, C_m_vecAbsOrigin); -MDECL(Client::GetAbsAngles, QAngle, C_m_angAbsRotation); -MDECL(Client::GetLocalVelocity, Vector, C_m_vecVelocity); -MDECL(Client::GetViewOffset, Vector, C_m_vecViewOffset); - void* Client::GetPlayer(int index) { return this->GetClientEntity(this->s_EntityList->ThisPtr(), index); @@ -66,7 +51,7 @@ void Client::CalcButtonBits(int nSlot, int& bits, int in_button, int in_ignore, } // CHLClient::HudUpdate -DETOUR(Client::HudUpdate, unsigned int a2) +DETOUR(HudUpdate, unsigned int a2) { if (cmdQueuer->isRunning) { for (auto&& tas = cmdQueuer->frames.begin(); tas != cmdQueuer->frames.end();) { @@ -96,11 +81,11 @@ DETOUR(Client::HudUpdate, unsigned int a2) } ++session->currentFrame; - return Client::HudUpdate(thisptr, a2); + return HudUpdate(thisptr, a2); } // ClientModeShared::CreateMove -DETOUR(Client::CreateMove, float flInputSampleTime, CUserCmd* cmd) +DETOUR(CreateMove, float flInputSampleTime, CUserCmd* cmd) { if (cmd->command_number) { if (replayPlayer1->IsPlaying()) { @@ -118,9 +103,9 @@ DETOUR(Client::CreateMove, float flInputSampleTime, CUserCmd* cmd) inputHud.SetButtonBits(0, cmd->buttons); } - return Client::CreateMove(thisptr, flInputSampleTime, cmd); + return CreateMove(thisptr, flInputSampleTime, cmd); } -DETOUR(Client::CreateMove2, float flInputSampleTime, CUserCmd* cmd) +DETOUR(CreateMove2, float flInputSampleTime, CUserCmd* cmd) { if (cmd->command_number) { if (replayPlayer2->IsPlaying()) { @@ -138,23 +123,23 @@ DETOUR(Client::CreateMove2, float flInputSampleTime, CUserCmd* cmd) inputHud.SetButtonBits(1, cmd->buttons); } - return Client::CreateMove2(thisptr, flInputSampleTime, cmd); + return CreateMove2(thisptr, flInputSampleTime, cmd); } // CHud::GetName -DETOUR_T(const char*, Client::GetName) +DETOUR_T(const char*, GetName) { // Never allow CHud::FindElement to find this HUD if (sar_disable_challenge_stats_hud.GetBool()) return ""; - return Client::GetName(thisptr); + return GetName(thisptr); } // CInput::DecodeUserCmdFromBuffer -DETOUR(Client::DecodeUserCmdFromBuffer, int nSlot, int buf, signed int sequence_number) +DETOUR(DecodeUserCmdFromBuffer, int nSlot, int buf, signed int sequence_number) { - auto result = Client::DecodeUserCmdFromBuffer(thisptr, nSlot, buf, sequence_number); + auto result = DecodeUserCmdFromBuffer(thisptr, nSlot, buf, sequence_number); auto m_pCommands = *reinterpret_cast((uintptr_t)thisptr + nSlot * Offsets::PerUserInput_tSize + Offsets::m_pCommands); auto cmd = reinterpret_cast(m_pCommands + Offsets::CUserCmdSize * (sequence_number % Offsets::MULTIPLAYER_BACKUP)); @@ -163,9 +148,9 @@ DETOUR(Client::DecodeUserCmdFromBuffer, int nSlot, int buf, signed int sequence_ return result; } -DETOUR(Client::DecodeUserCmdFromBuffer2, int buf, signed int sequence_number) +DETOUR(DecodeUserCmdFromBuffer2, int buf, signed int sequence_number) { - auto result = Client::DecodeUserCmdFromBuffer2(thisptr, buf, sequence_number); + auto result = DecodeUserCmdFromBuffer2(thisptr, buf, sequence_number); auto m_pCommands = *reinterpret_cast((uintptr_t)thisptr + Offsets::m_pCommands); auto cmd = reinterpret_cast(m_pCommands + Offsets::CUserCmdSize * (sequence_number % Offsets::MULTIPLAYER_BACKUP)); @@ -176,7 +161,7 @@ DETOUR(Client::DecodeUserCmdFromBuffer2, int buf, signed int sequence_number) } // CInput::CreateMove -DETOUR(Client::CInput_CreateMove, int sequence_number, float input_sample_frametime, bool active) +DETOUR(CInput_CreateMove, int sequence_number, float input_sample_frametime, bool active) { auto originalValue = 0; if (sar_tas_ss_forceuser.GetBool()) { @@ -184,7 +169,7 @@ DETOUR(Client::CInput_CreateMove, int sequence_number, float input_sample_framet in_forceuser.SetValue(GET_SLOT()); } - auto result = Client::CInput_CreateMove(thisptr, sequence_number, input_sample_frametime, active); + auto result = CInput_CreateMove(thisptr, sequence_number, input_sample_frametime, active); if (sar_tas_ss_forceuser.GetBool()) { in_forceuser.SetValue(originalValue); @@ -194,113 +179,105 @@ DETOUR(Client::CInput_CreateMove, int sequence_number, float input_sample_framet } // CInput::GetButtonBits -DETOUR(Client::GetButtonBits, bool bResetState) +DETOUR(GetButtonBits, bool bResetState) { - auto bits = Client::GetButtonBits(thisptr, bResetState); + auto bits = GetButtonBits(thisptr, bResetState); client->CalcButtonBits(GET_SLOT(), bits, IN_AUTOSTRAFE, 0, &autoStrafer->in_autostrafe, bResetState); return bits; } -DETOUR_COMMAND(Client::playvideo_end_level_transition) +DETOUR_COMMAND(playvideo_end_level_transition) { console->DevMsg("%s\n", args.m_pArgSBuffer); session->Ended(); - return Client::playvideo_end_level_transition_callback(args); + return playvideo_end_level_transition_callback(args); } -bool Client::Init() +void Client::Init() { bool readJmp = false; #ifdef _WIN32 readJmp = sar.game->Is(SourceGame_TheStanleyParable | SourceGame_TheBeginnersGuide); #endif - this->g_ClientDLL = Interface::Create(this->Name(), "VClient0"); - this->s_EntityList = Interface::Create(this->Name(), "VClientEntityList0", false); - - if (this->g_ClientDLL) { - this->GetAllClasses = this->g_ClientDLL->Original<_GetAllClasses>(Offsets::GetAllClasses, readJmp); + this->g_ClientDLL = Interface::Hookable(this, "VClient0"); + this->GetAllClasses = this->g_ClientDLL->Original<_GetAllClasses>(Offsets::GetAllClasses, readJmp); - this->g_ClientDLL->Hook(Client::HudUpdate_Hook, Client::HudUpdate, Offsets::HudUpdate); + this->g_ClientDLL->Hook(&hkHudUpdate, Offsets::HudUpdate); - if (sar.game->Is(SourceGame_Portal2)) { - auto leaderboard = Command("+leaderboard"); - if (!!leaderboard) { - using _GetHud = void*(__cdecl*)(int unk); - using _FindElement = void*(__rescall*)(void* thisptr, const char* pName); + if (sar.game->Is(SourceGame_Portal2)) { + auto leaderboard = Command("+leaderboard"); + if (!!leaderboard) { + using _GetHud = void*(__cdecl*)(int unk); + using _FindElement = void*(__rescall*)(void* thisptr, const char* pName); - auto cc_leaderboard_enable = (uintptr_t)leaderboard.ThisPtr()->m_pCommandCallback; - auto GetHud = Memory::Read<_GetHud>(cc_leaderboard_enable + Offsets::GetHud); - auto FindElement = Memory::Read<_FindElement>(cc_leaderboard_enable + Offsets::FindElement); - auto CHUDChallengeStats = FindElement(GetHud(-1), "CHUDChallengeStats"); + auto cc_leaderboard_enable = (uintptr_t)leaderboard.ThisPtr()->m_pCommandCallback; + auto GetHud = Memory::Read<_GetHud>(cc_leaderboard_enable + Offsets::GetHud); + auto FindElement = Memory::Read<_FindElement>(cc_leaderboard_enable + Offsets::FindElement); + auto CHUDChallengeStats = FindElement(GetHud(-1), "CHUDChallengeStats"); - if (this->g_HUDChallengeStats = Interface::Create(CHUDChallengeStats)) { - this->g_HUDChallengeStats->Hook(Client::GetName_Hook, Client::GetName, Offsets::GetName); - } + if (this->g_HUDChallengeStats = Interface::Hookable(this, CHUDChallengeStats)) { + this->g_HUDChallengeStats->Hook(&hkGetName, Offsets::GetName); } } + } - auto IN_ActivateMouse = this->g_ClientDLL->Original(Offsets::IN_ActivateMouse, readJmp); - auto g_InputAddr = Memory::DerefDeref(IN_ActivateMouse + Offsets::g_Input); - - if (g_Input = Interface::Create(g_InputAddr)) { - if (sar.game->Is(SourceGame_Portal2Engine)) { - g_Input->Hook(Client::DecodeUserCmdFromBuffer_Hook, Client::DecodeUserCmdFromBuffer, Offsets::DecodeUserCmdFromBuffer); - g_Input->Hook(Client::GetButtonBits_Hook, Client::GetButtonBits, Offsets::GetButtonBits); - - auto JoyStickApplyMovement = g_Input->Original(Offsets::JoyStickApplyMovement, readJmp); - Memory::Read(JoyStickApplyMovement + Offsets::KeyDown, &this->KeyDown); - Memory::Read(JoyStickApplyMovement + Offsets::KeyUp, &this->KeyUp); - - if (sar.game->Is(SourceGame_TheStanleyParable)) { - auto GetButtonBits = g_Input->Original(Offsets::GetButtonBits, readJmp); - Memory::Deref(GetButtonBits + Offsets::in_jump, &this->in_jump); - } else if (sar.game->Is(SourceGame_Portal2 | SourceGame_ApertureTag)) { - in_forceuser = Variable("in_forceuser"); - if (!!in_forceuser && this->g_Input) { - this->g_Input->Hook(CInput_CreateMove_Hook, CInput_CreateMove, Offsets::GetButtonBits + 1); - } - - Command::Hook("playvideo_end_level_transition", Client::playvideo_end_level_transition_callback_hook, Client::playvideo_end_level_transition_callback); - } - } else { - g_Input->Hook(Client::DecodeUserCmdFromBuffer2_Hook, Client::DecodeUserCmdFromBuffer2, Offsets::DecodeUserCmdFromBuffer); - } + auto IN_ActivateMouse = this->g_ClientDLL->Original(Offsets::IN_ActivateMouse, readJmp); + auto g_InputAddr = Memory::DerefDeref(IN_ActivateMouse + Offsets::g_Input); + + this->g_Input = Interface::Hookable(this, g_InputAddr); + if (sar.game->Is(SourceGame_Portal2Engine)) { + this->g_Input->Hook(&hkDecodeUserCmdFromBuffer, Offsets::DecodeUserCmdFromBuffer); + this->g_Input->Hook(&hkGetButtonBits, Offsets::GetButtonBits); + + auto JoyStickApplyMovement = this->g_Input->Original(Offsets::JoyStickApplyMovement, readJmp); + Memory::Read(JoyStickApplyMovement + Offsets::KeyDown, &this->KeyDown); + Memory::Read(JoyStickApplyMovement + Offsets::KeyUp, &this->KeyUp); + + if (sar.game->Is(SourceGame_TheStanleyParable)) { + auto GetButtonBits = this->g_Input->Original(Offsets::GetButtonBits, readJmp); + Memory::Deref(GetButtonBits + Offsets::in_jump, &this->in_jump); + } else if (sar.game->Is(SourceGame_Portal2 | SourceGame_ApertureTag)) { + in_forceuser = Variable("in_forceuser"); + this->g_Input->Hook(&hkCInput_CreateMove, Offsets::GetButtonBits + 1); + playvideo_end_level_transition_hook.Register(this); } + } else { + this->g_Input->Hook(&hkDecodeUserCmdFromBuffer2, Offsets::DecodeUserCmdFromBuffer); + } - auto HudProcessInput = this->g_ClientDLL->Original(Offsets::HudProcessInput, readJmp); - void* clientMode = nullptr; - void* clientMode2 = nullptr; - if (sar.game->Is(SourceGame_Portal2Engine)) { - if (sar.game->Is(SourceGame_Portal2 | SourceGame_ApertureTag)) { - auto GetClientMode = Memory::Read(HudProcessInput + Offsets::GetClientMode); - auto g_pClientMode = Memory::Deref(GetClientMode + Offsets::g_pClientMode); - clientMode = Memory::Deref(g_pClientMode); - clientMode2 = Memory::Deref(g_pClientMode + sizeof(void*)); - } else { - typedef void* (*_GetClientMode)(); - auto GetClientMode = Memory::Read<_GetClientMode>(HudProcessInput + Offsets::GetClientMode); - clientMode = GetClientMode(); - } - } else if (sar.game->Is(SourceGame_HalfLife2Engine)) { - clientMode = Memory::DerefDeref(HudProcessInput + Offsets::GetClientMode); + auto HudProcessInput = this->g_ClientDLL->Original(Offsets::HudProcessInput, readJmp); + uintptr_t clientMode = 0; + uintptr_t clientMode2 = 0; + + if (sar.game->Is(SourceGame_Portal2Engine)) { + if (sar.game->Is(SourceGame_Portal2 | SourceGame_ApertureTag)) { + auto GetClientMode = Memory::Read(HudProcessInput + Offsets::GetClientMode); + auto g_pClientMode = Memory::Deref(GetClientMode + Offsets::g_pClientMode); + clientMode = Memory::Deref(g_pClientMode); + clientMode2 = Memory::Deref(g_pClientMode + sizeof(uintptr_t)); + } else { + typedef uintptr_t (*_GetClientMode)(); + auto GetClientMode = Memory::Read<_GetClientMode>(HudProcessInput + Offsets::GetClientMode); + clientMode = GetClientMode(); } + } else if (sar.game->Is(SourceGame_HalfLife2Engine)) { + clientMode = Memory::DerefDeref(HudProcessInput + Offsets::GetClientMode); + } - if (this->g_pClientMode = Interface::Create(clientMode)) { - this->g_pClientMode->Hook(Client::CreateMove_Hook, Client::CreateMove, Offsets::CreateMove); - } + this->g_pClientMode = Interface::Hookable(this, clientMode); + this->g_pClientMode->Hook(&hkCreateMove, Offsets::CreateMove); - if (this->g_pClientMode2 = Interface::Create(clientMode2)) { - this->g_pClientMode2->Hook(Client::CreateMove2_Hook, Client::CreateMove2, Offsets::CreateMove); - } + if (clientMode2) { + this->g_pClientMode2 = Interface::Hookable(this, clientMode2); + this->g_pClientMode2->Hook(&hkCreateMove2, Offsets::CreateMove); } - if (this->s_EntityList) { - this->GetClientEntity = this->s_EntityList->Original<_GetClientEntity>(Offsets::GetClientEntity, readJmp); - } + this->s_EntityList = Interface::CreateNew(this, "VClientEntityList0"); + this->GetClientEntity = this->s_EntityList->Original<_GetClientEntity>(Offsets::GetClientEntity, readJmp); offsetFinder->ClientSide("CBasePlayer", "m_vecVelocity[0]", &Offsets::C_m_vecVelocity); offsetFinder->ClientSide("CBasePlayer", "m_vecViewOffset[0]", &Offsets::C_m_vecViewOffset); @@ -309,18 +286,15 @@ bool Client::Init() cl_sidespeed = Variable("cl_sidespeed"); cl_forwardspeed = Variable("cl_forwardspeed"); cl_fov = Variable("cl_fov"); - - return this->hasLoaded = this->g_ClientDLL && this->s_EntityList; } void Client::Shutdown() { - Interface::Delete(this->g_ClientDLL); - Interface::Delete(this->g_pClientMode); - Interface::Delete(this->g_pClientMode2); - Interface::Delete(this->g_HUDChallengeStats); - Interface::Delete(this->s_EntityList); - Interface::Delete(this->g_Input); - Command::Unhook("playvideo_end_level_transition", Client::playvideo_end_level_transition_callback); + Interface::Destroy(this->g_ClientDLL); + Interface::Destroy(this->g_pClientMode); + Interface::Destroy(this->g_pClientMode2); + Interface::Destroy(this->g_HUDChallengeStats); + Interface::Destroy(this->s_EntityList); + Interface::Destroy(this->g_Input); } Client* client; diff --git a/src/Modules/Client.hpp b/src/Modules/Client.hpp index 27b662d9..fa3b4542 100644 --- a/src/Modules/Client.hpp +++ b/src/Modules/Client.hpp @@ -5,6 +5,7 @@ #include "Command.hpp" #include "Interface.hpp" +#include "Offsets.hpp" #include "Utils.hpp" #include "Variable.hpp" @@ -31,40 +32,22 @@ class Client : public Module { void* in_jump = nullptr; public: - DECL_M(GetAbsOrigin, Vector); - DECL_M(GetAbsAngles, QAngle); - DECL_M(GetLocalVelocity, Vector); - DECL_M(GetViewOffset, Vector); + ENTPROP(GetAbsOrigin, Vector, C_m_vecAbsOrigin); + ENTPROP(GetAbsAngles, QAngle, C_m_angAbsRotation); + ENTPROP(GetLocalVelocity, Vector, C_m_vecVelocity); + ENTPROP(GetViewOffset, Vector, C_m_vecViewOffset); void* GetPlayer(int index); void CalcButtonBits(int nSlot, int& bits, int in_button, int in_ignore, kbutton_t* button, bool reset); -public: - // CHLClient::HudUpdate - DECL_DETOUR(HudUpdate, unsigned int a2); - - // ClientModeShared::CreateMove - DECL_DETOUR(CreateMove, float flInputSampleTime, CUserCmd* cmd); - DECL_DETOUR(CreateMove2, float flInputSampleTime, CUserCmd* cmd); - - // CHud::GetName - DECL_DETOUR_T(const char*, GetName); - - // CInput::_DecodeUserCmdFromBuffer - DECL_DETOUR(DecodeUserCmdFromBuffer, int nSlot, int buf, signed int sequence_number); - DECL_DETOUR(DecodeUserCmdFromBuffer2, int buf, signed int sequence_number); - - // CInput::CreateMove - DECL_DETOUR(CInput_CreateMove, int sequence_number, float input_sample_frametime, bool active); - - // CInput::GetButtonBits - DECL_DETOUR(GetButtonBits, bool bResetState); - - DECL_DETOUR_COMMAND(playvideo_end_level_transition); + Client() + : Module(MODULE("client")) + { + this->isHookable = true; + } - bool Init() override; + void Init() override; void Shutdown() override; - const char* Name() override { return MODULE("client"); } }; extern Client* client; diff --git a/src/Modules/Console.cpp b/src/Modules/Console.cpp index 1b9c0a37..5adf7ec6 100644 --- a/src/Modules/Console.cpp +++ b/src/Modules/Console.cpp @@ -1,24 +1,16 @@ #include "Console.hpp" -bool Console::Init() +void Console::Init() { - auto tier0 = Memory::GetModuleHandleByName(this->Name()); - if (tier0) { - this->Msg = Memory::GetSymbolAddress<_Msg>(tier0, MSG_SYMBOL); - this->ColorMsg = Memory::GetSymbolAddress<_ColorMsg>(tier0, CONCOLORMSG_SYMBOL); - this->Warning = Memory::GetSymbolAddress<_Warning>(tier0, WARNING_SYMBOL); - this->DevMsg = Memory::GetSymbolAddress<_DevMsg>(tier0, DEVMSG_SYMBOL); - this->DevWarning = Memory::GetSymbolAddress<_DevWarning>(tier0, DEVWARNINGMSG_SYMBOL); + auto tier0 = Memory::GetModuleHandleByName(this->filename); - Memory::CloseModuleHandle(tier0); - } + this->Msg = Memory::GetSymbolAddress<_Msg>(tier0, MSG_SYMBOL); + this->ColorMsg = Memory::GetSymbolAddress<_ColorMsg>(tier0, CONCOLORMSG_SYMBOL); + this->Warning = Memory::GetSymbolAddress<_Warning>(tier0, WARNING_SYMBOL); + this->DevMsg = Memory::GetSymbolAddress<_DevMsg>(tier0, DEVMSG_SYMBOL); + this->DevWarning = Memory::GetSymbolAddress<_DevWarning>(tier0, DEVWARNINGMSG_SYMBOL); - return this->hasLoaded = tier0 - && this->Msg - && this->ColorMsg - && this->Warning - && this->DevMsg - && this->DevWarning; + Memory::CloseModuleHandle(tier0); } void Console::Shutdown() { diff --git a/src/Modules/Console.hpp b/src/Modules/Console.hpp index d6a6e74e..095e40eb 100644 --- a/src/Modules/Console.hpp +++ b/src/Modules/Console.hpp @@ -47,9 +47,13 @@ class Console : public Module { this->ColorMsg(SAR_PRINT_ACTIVE_COLOR, fmt, args...); } - bool Init() override; + Console() + : Module(MODULE(TIER0)) + { + } + + void Init() override; void Shutdown() override; - const char* Name() override { return MODULE(TIER0); } }; extern Console* console; diff --git a/src/Modules/Engine.cpp b/src/Modules/Engine.cpp index 1ecc4eee..05c228e2 100644 --- a/src/Modules/Engine.cpp +++ b/src/Modules/Engine.cpp @@ -20,29 +20,6 @@ Variable host_framerate; Variable net_showmsg; -REDECL(Engine::Disconnect); -REDECL(Engine::Disconnect2); -REDECL(Engine::SetSignonState); -REDECL(Engine::SetSignonState2); -REDECL(Engine::Frame); -REDECL(Engine::OnGameOverlayActivated); -REDECL(Engine::OnGameOverlayActivatedBase); -REDECL(Engine::plugin_load_callback); -REDECL(Engine::plugin_unload_callback); -REDECL(Engine::exit_callback); -REDECL(Engine::quit_callback); -REDECL(Engine::help_callback); -REDECL(Engine::gameui_activate_callback); -#ifdef _WIN32 -REDECL(Engine::connect_callback); -REDECL(Engine::ParseSmoothingInfo_Skip); -REDECL(Engine::ParseSmoothingInfo_Default); -REDECL(Engine::ParseSmoothingInfo_Continue); -REDECL(Engine::ParseSmoothingInfo_Mid); -REDECL(Engine::ParseSmoothingInfo_Mid_Trampoline); -REDECL(Engine::ReadCustomData); -#endif - void Engine::ExecuteCommand(const char* cmd) { this->ClientCmd(this->engineClient->ThisPtr(), cmd); @@ -129,44 +106,44 @@ void Engine::SafeUnload(const char* postCommand) } // CClientState::Disconnect -DETOUR(Engine::Disconnect, bool bShowMainMenu) +DETOUR(Disconnect, bool bShowMainMenu) { session->Ended(); - return Engine::Disconnect(thisptr, bShowMainMenu); + return Disconnect(thisptr, bShowMainMenu); } #ifdef _WIN32 -DETOUR(Engine::Disconnect2, int unk1, int unk2, int unk3) +DETOUR(Disconnect2, int unk1, int unk2, int unk3) { session->Ended(); - return Engine::Disconnect2(thisptr, unk1, unk2, unk3); + return Disconnect2(thisptr, unk1, unk2, unk3); } -DETOUR_COMMAND(Engine::connect) +DETOUR_COMMAND(connect) { session->Ended(); - Engine::connect_callback(args); + connect_callback(args); } #else -DETOUR(Engine::Disconnect2, int unk, bool bShowMainMenu) +DETOUR(Disconnect2, int unk, bool bShowMainMenu) { session->Ended(); - return Engine::Disconnect2(thisptr, unk, bShowMainMenu); + return Disconnect2(thisptr, unk, bShowMainMenu); } #endif // CClientState::SetSignonState -DETOUR(Engine::SetSignonState, int state, int count, void* unk) +DETOUR(SetSignonState, int state, int count, void* unk) { session->Changed(state); - return Engine::SetSignonState(thisptr, state, count, unk); + return SetSignonState(thisptr, state, count, unk); } -DETOUR(Engine::SetSignonState2, int state, int count) +DETOUR(SetSignonState2, int state, int count) { session->Changed(state); - return Engine::SetSignonState2(thisptr, state, count); + return SetSignonState2(thisptr, state, count); } // CEngine::Frame -DETOUR(Engine::Frame) +DETOUR(Frame) { speedrun->PreUpdate(engine->GetTick(), engine->m_szLevelName); @@ -179,55 +156,18 @@ DETOUR(Engine::Frame) speedrun->PostUpdate(engine->GetTick(), engine->m_szLevelName); } - return Engine::Frame(thisptr); -} - -#ifdef _WIN32 -// CDemoFile::ReadCustomData -void __fastcall ReadCustomData_Wrapper(int demoFile, int edx, int unk1, int unk2) -{ - Engine::ReadCustomData((void*)demoFile, 0, nullptr, nullptr); -} -// CDemoSmootherPanel::ParseSmoothingInfo -DETOUR_MID_MH(Engine::ParseSmoothingInfo_Mid) -{ - __asm { - // Check if we have dem_customdata - cmp eax, 8 - jne _orig - - // Parse stuff that does not get parsed (thanks valve) - push edi - push edi - mov ecx, esi - call ReadCustomData_Wrapper - - jmp Engine::ParseSmoothingInfo_Skip - -_orig: // Original overwritten instructions - add eax, -3 - cmp eax, 6 - ja _def - - jmp Engine::ParseSmoothingInfo_Continue - -_def: - jmp Engine::ParseSmoothingInfo_Default - } + return Frame(thisptr); } -#endif // CSteam3Client::OnGameOverlayActivated -DETOUR_B(Engine::OnGameOverlayActivated, GameOverlayActivated_t* pGameOverlayActivated) +DETOUR_B(OnGameOverlayActivated, GameOverlayActivated_t* pGameOverlayActivated) { engine->overlayActivated = pGameOverlayActivated->m_bActive; - return Engine::OnGameOverlayActivatedBase(thisptr, pGameOverlayActivated); + return OnGameOverlayActivatedBase(thisptr, pGameOverlayActivated); } -DETOUR_COMMAND(Engine::plugin_load) +DETOUR_COMMAND(plugin_load) { - // Prevent crash when trying to load SAR twice or try to find the module in - // the plugin list if the initial search thread failed if (args.ArgC() >= 2) { auto file = std::string(args[1]); if (Utils::EndsWith(file, std::string(MODULE("sar"))) || Utils::EndsWith(file, std::string("sar"))) { @@ -239,242 +179,166 @@ DETOUR_COMMAND(Engine::plugin_load) } } - Engine::plugin_load_callback(args); + plugin_load_callback(args); } -DETOUR_COMMAND(Engine::plugin_unload) +DETOUR_COMMAND(plugin_unload) { if (args.ArgC() >= 2 && sar.GetPlugin() && std::atoi(args[1]) == sar.plugin->index) { engine->SafeUnload(); } else { - engine->plugin_unload_callback(args); + plugin_unload_callback(args); } } -DETOUR_COMMAND(Engine::exit) +DETOUR_COMMAND(exit) { engine->SafeUnload("exit"); } -DETOUR_COMMAND(Engine::quit) +DETOUR_COMMAND(quit) { engine->SafeUnload("quit"); } -DETOUR_COMMAND(Engine::help) +DETOUR_COMMAND(help) { cvars->PrintHelp(args); } -DETOUR_COMMAND(Engine::gameui_activate) +DETOUR_COMMAND(gameui_activate) { if (sar_disable_steam_pause.GetBool() && engine->overlayActivated) { return; } - Engine::gameui_activate_callback(args); + gameui_activate_callback(args); } -bool Engine::Init() +void Engine::Init() { - this->engineClient = Interface::Create(this->Name(), "VEngineClient0", false); - this->s_ServerPlugin = Interface::Create(this->Name(), "ISERVERPLUGINHELPERS0", false); - - if (this->engineClient) { - this->GetScreenSize = this->engineClient->Original<_GetScreenSize>(Offsets::GetScreenSize); - this->ClientCmd = this->engineClient->Original<_ClientCmd>(Offsets::ClientCmd); - this->GetLocalPlayer = this->engineClient->Original<_GetLocalPlayer>(Offsets::GetLocalPlayer); - this->GetViewAngles = this->engineClient->Original<_GetViewAngles>(Offsets::GetViewAngles); - this->SetViewAngles = this->engineClient->Original<_SetViewAngles>(Offsets::SetViewAngles); - this->GetMaxClients = this->engineClient->Original<_GetMaxClients>(Offsets::GetMaxClients); - this->GetGameDirectory = this->engineClient->Original<_GetGameDirectory>(Offsets::GetGameDirectory); - - Memory::Read<_Cbuf_AddText>((uintptr_t)this->ClientCmd + Offsets::Cbuf_AddText, &this->Cbuf_AddText); - Memory::Deref((uintptr_t)this->Cbuf_AddText + Offsets::s_CommandBuffer, &this->s_CommandBuffer); - - if (sar.game->Is(SourceGame_Portal2Engine)) { - Memory::Read((uintptr_t)this->SetViewAngles + Offsets::GetLocalClient, &this->GetLocalClient); - - if (sar.game->Is(SourceGame_Portal2Game | SourceGame_INFRA)) { - this->m_bWaitEnabled = reinterpret_cast((uintptr_t)s_CommandBuffer + Offsets::m_bWaitEnabled); - this->m_bWaitEnabled2 = reinterpret_cast((uintptr_t)this->m_bWaitEnabled + Offsets::CCommandBufferSize); - } + this->s_ServerPlugin = Interface::CreateNew(this, "ISERVERPLUGINHELPERS0"); - if (sar.game->Is(SourceGame_Portal2Game)) { - auto GetSteamAPIContext = this->engineClient->Original(Offsets::GetSteamAPIContext); - auto OnGameOverlayActivated = reinterpret_cast<_OnGameOverlayActivated*>(GetSteamAPIContext() + Offsets::OnGameOverlayActivated); + this->engineClient = Interface::CreateNew(this, "VEngineClient0"); + this->GetScreenSize = this->engineClient->Original<_GetScreenSize>(Offsets::GetScreenSize); + this->ClientCmd = this->engineClient->Original<_ClientCmd>(Offsets::ClientCmd); + this->GetLocalPlayer = this->engineClient->Original<_GetLocalPlayer>(Offsets::GetLocalPlayer); + this->GetViewAngles = this->engineClient->Original<_GetViewAngles>(Offsets::GetViewAngles); + this->SetViewAngles = this->engineClient->Original<_SetViewAngles>(Offsets::SetViewAngles); + this->GetMaxClients = this->engineClient->Original<_GetMaxClients>(Offsets::GetMaxClients); + this->GetGameDirectory = this->engineClient->Original<_GetGameDirectory>(Offsets::GetGameDirectory); - Engine::OnGameOverlayActivatedBase = *OnGameOverlayActivated; - *OnGameOverlayActivated = reinterpret_cast<_OnGameOverlayActivated>(Engine::OnGameOverlayActivated_Hook); - } + Memory::Read<_Cbuf_AddText>((uintptr_t)this->ClientCmd + Offsets::Cbuf_AddText, &this->Cbuf_AddText); + Memory::Deref((uintptr_t)this->Cbuf_AddText + Offsets::s_CommandBuffer, &this->s_CommandBuffer); - if (auto g_VEngineServer = Interface::Create(this->Name(), "VEngineServer0", false)) { - this->ClientCommand = g_VEngineServer->Original<_ClientCommand>(Offsets::ClientCommand); - Interface::Delete(g_VEngineServer); - } + if (sar.game->Is(SourceGame_Portal2Engine)) { + Memory::Read((uintptr_t)this->SetViewAngles + Offsets::GetLocalClient, &this->GetLocalClient); + + if (sar.game->Is(SourceGame_Portal2Game)) { + auto GetSteamAPIContext = this->engineClient->Original(Offsets::GetSteamAPIContext); + auto OnGameOverlayActivated = reinterpret_cast<_OnGameOverlayActivated*>(GetSteamAPIContext() + Offsets::OnGameOverlayActivated); + + OnGameOverlayActivatedBase = *OnGameOverlayActivated; + *OnGameOverlayActivated = reinterpret_cast<_OnGameOverlayActivated>(OnGameOverlayActivated_Hook); } - void* clPtr = nullptr; - if (sar.game->Is(SourceGame_Portal2Engine)) { - typedef void* (*_GetClientState)(); - auto GetClientState = Memory::Read<_GetClientState>((uintptr_t)this->ClientCmd + Offsets::GetClientStateFunction); - clPtr = GetClientState(); + Interface::Temp(this, "VEngineServer0", [this](const Interface* g_VEngineServer) { + this->ClientCommand = g_VEngineServer->Original<_ClientCommand>(Offsets::ClientCommand); + }); + } - this->GetActiveSplitScreenPlayerSlot = this->engineClient->Original<_GetActiveSplitScreenPlayerSlot>(Offsets::GetActiveSplitScreenPlayerSlot); - } else if (sar.game->Is(SourceGame_HalfLife2Engine)) { - auto ServerCmdKeyValues = this->engineClient->Original(Offsets::ServerCmdKeyValues); - clPtr = Memory::Deref(ServerCmdKeyValues + Offsets::cl); + void* clPtr = nullptr; + if (sar.game->Is(SourceGame_Portal2Engine)) { + typedef void* (*_GetClientState)(); + auto GetClientState = Memory::Read<_GetClientState>((uintptr_t)this->ClientCmd + Offsets::GetClientStateFunction); + clPtr = GetClientState(); - Memory::Read<_AddText>((uintptr_t)this->Cbuf_AddText + Offsets::AddText, &this->AddText); - } + this->GetActiveSplitScreenPlayerSlot = this->engineClient->Original<_GetActiveSplitScreenPlayerSlot>(Offsets::GetActiveSplitScreenPlayerSlot); + } else if (sar.game->Is(SourceGame_HalfLife2Engine)) { + auto ServerCmdKeyValues = this->engineClient->Original(Offsets::ServerCmdKeyValues); + clPtr = Memory::Deref(ServerCmdKeyValues + Offsets::cl); + + Memory::Read<_AddText>((uintptr_t)this->Cbuf_AddText + Offsets::AddText, &this->AddText); + } - if (this->cl = Interface::Create(clPtr)) { - if (!this->demoplayer) - this->demoplayer = new EngineDemoPlayer(); - if (!this->demorecorder) - this->demorecorder = new EngineDemoRecorder(); - - if (sar.game->Is(SourceGame_Portal2Engine)) { - this->cl->Hook(Engine::SetSignonState_Hook, Engine::SetSignonState, Offsets::Disconnect - 1); - this->cl->Hook(Engine::Disconnect_Hook, Engine::Disconnect, Offsets::Disconnect); - } else if (sar.game->Is(SourceGame_HalfLife2Engine)) { - this->cl->Hook(Engine::SetSignonState2_Hook, Engine::SetSignonState2, Offsets::Disconnect - 1); + this->cl = Interface::Hookable(this, clPtr); + if (sar.game->Is(SourceGame_Portal2Engine)) { + this->cl->Hook(&hkSetSignonState, Offsets::Disconnect - 1); + this->cl->Hook(&hkDisconnect, Offsets::Disconnect); + } else if (sar.game->Is(SourceGame_HalfLife2Engine)) { + this->cl->Hook(&hkSetSignonState2, Offsets::Disconnect - 1); #ifdef _WIN32 - Command::Hook("connect", Engine::connect_callback_hook, Engine::connect_callback); + connect_hook.Register(this); #else - this->cl->Hook(Engine::Disconnect2_Hook, Engine::Disconnect2, Offsets::Disconnect); + this->cl->Hook(&hkDisconnect2, Offsets::Disconnect); #endif - } + } #if _WIN32 - auto IServerMessageHandler_VMT = Memory::Deref((uintptr_t)this->cl->ThisPtr() + IServerMessageHandler_VMT_Offset); - auto ProcessTick = Memory::Deref(IServerMessageHandler_VMT + sizeof(uintptr_t) * Offsets::ProcessTick); + auto IServerMessageHandler_VMT = Memory::Deref((uintptr_t)this->cl->ThisPtr() + IServerMessageHandler_VMT_Offset); + auto ProcessTick = Memory::Deref(IServerMessageHandler_VMT + sizeof(uintptr_t) * Offsets::ProcessTick); #else - auto ProcessTick = this->cl->Original(Offsets::ProcessTick); + auto ProcessTick = this->cl->Original(Offsets::ProcessTick); #endif - tickcount = Memory::Deref(ProcessTick + Offsets::tickcount); - interval_per_tick = Memory::Deref(ProcessTick + Offsets::interval_per_tick); - speedrun->SetIntervalPerTick(interval_per_tick); + tickcount = Memory::Deref(ProcessTick + Offsets::tickcount); + interval_per_tick = Memory::Deref(ProcessTick + Offsets::interval_per_tick); + speedrun->SetIntervalPerTick(interval_per_tick); - auto SetSignonState = this->cl->Original(Offsets::Disconnect - 1); - auto HostState_OnClientConnected = Memory::Read(SetSignonState + Offsets::HostState_OnClientConnected); - Memory::Deref(HostState_OnClientConnected + Offsets::hoststate, &hoststate); - } - } + auto SetSignonState = this->cl->Original(Offsets::Disconnect - 1); + auto HostState_OnClientConnected = Memory::Read(SetSignonState + Offsets::HostState_OnClientConnected); + Memory::Deref(HostState_OnClientConnected + Offsets::hoststate, &hoststate); - if (auto tool = Interface::Create(this->Name(), "VENGINETOOL0", false)) { + Interface::Temp(this, "VENGINETOOL0", [this](const Interface* tool) { auto GetCurrentMap = tool->Original(Offsets::GetCurrentMap); this->m_szLevelName = Memory::Deref(GetCurrentMap + Offsets::m_szLevelName); - - if (sar.game->Is(SourceGame_HalfLife2Engine) && std::strlen(this->m_szLevelName) != 0) { - console->Warning("SAR: DO NOT load this plugin when the server is active!\n"); - return false; - } - this->m_bLoadgame = reinterpret_cast((uintptr_t)this->m_szLevelName + Offsets::m_bLoadGame); - Interface::Delete(tool); - } + }); - if (auto s_EngineAPI = Interface::Create(this->Name(), "VENGINE_LAUNCHER_API_VERSION0", false)) { + Interface::Temp(this, "VENGINE_LAUNCHER_API_VERSION0", [this](const Interface* s_EngineAPI) { auto IsRunningSimulation = s_EngineAPI->Original(Offsets::IsRunningSimulation); auto engAddr = Memory::DerefDeref(IsRunningSimulation + Offsets::eng); - if (this->eng = Interface::Create(engAddr)) { + if (this->eng = Interface::Hookable(this, engAddr)) { if (this->tickcount && this->hoststate && this->m_szLevelName) { - this->eng->Hook(Engine::Frame_Hook, Engine::Frame, Offsets::Frame); + this->eng->Hook(&hkFrame, Offsets::Frame); } } - Interface::Delete(s_EngineAPI); - } + }); if (sar.game->Is(SourceGame_Portal2 | SourceGame_ApertureTag)) { - this->s_GameEventManager = Interface::Create(this->Name(), "GAMEEVENTSMANAGER002", false); - if (this->s_GameEventManager) { - this->AddListener = this->s_GameEventManager->Original<_AddListener>(Offsets::AddListener); - this->RemoveListener = this->s_GameEventManager->Original<_RemoveListener>(Offsets::RemoveListener); - - auto FireEventClientSide = s_GameEventManager->Original(Offsets::FireEventClientSide); - auto FireEventIntern = Memory::Read(FireEventClientSide + Offsets::FireEventIntern); - Memory::Read<_ConPrintEvent>(FireEventIntern + Offsets::ConPrintEvent, &this->ConPrintEvent); - } - } + this->s_GameEventManager = Interface::CreateNew(this, "GAMEEVENTSMANAGER002"); + this->AddListener = this->s_GameEventManager->Original<_AddListener>(Offsets::AddListener); + this->RemoveListener = this->s_GameEventManager->Original<_RemoveListener>(Offsets::RemoveListener); -#ifdef _WIN32 - if (sar.game->Is(SourceGame_Portal2Game)) { - auto parseSmoothingInfoAddr = Memory::Scan(this->Name(), "55 8B EC 0F 57 C0 81 EC ? ? ? ? B9 ? ? ? ? 8D 85 ? ? ? ? EB", 178); - auto readCustomDataAddr = Memory::Scan(this->Name(), "55 8B EC F6 05 ? ? ? ? ? 53 56 57 8B F1 75 2F"); - - console->DevMsg("CDemoSmootherPanel::ParseSmoothingInfo = %p\n", parseSmoothingInfoAddr); - console->DevMsg("CDemoFile::ReadCustomData = %p\n", readCustomDataAddr); - - if (parseSmoothingInfoAddr && readCustomDataAddr) { - MH_HOOK_MID(Engine::ParseSmoothingInfo_Mid, parseSmoothingInfoAddr); // Hook switch-case - Engine::ParseSmoothingInfo_Continue = parseSmoothingInfoAddr + 8; // Back to original function - Engine::ParseSmoothingInfo_Default = parseSmoothingInfoAddr + 133; // Default case - Engine::ParseSmoothingInfo_Skip = parseSmoothingInfoAddr - 29; // Continue loop - Engine::ReadCustomData = reinterpret_cast<_ReadCustomData>(readCustomDataAddr); // Function that handles dem_customdata - - this->demoSmootherPatch = new Memory::Patch(); - unsigned char nop3[] = { 0x90, 0x90, 0x90 }; - this->demoSmootherPatch->Execute(parseSmoothingInfoAddr + 5, nop3); // Nop rest - } + auto FireEventClientSide = s_GameEventManager->Original(Offsets::FireEventClientSide); + auto FireEventIntern = Memory::Read(FireEventClientSide + Offsets::FireEventIntern); + Memory::Read<_ConPrintEvent>(FireEventIntern + Offsets::ConPrintEvent, &this->ConPrintEvent); } -#endif - if (auto debugoverlay = Interface::Create(this->Name(), "VDebugOverlay0", false)) { - ScreenPosition = debugoverlay->Original<_ScreenPosition>(Offsets::ScreenPosition); - Interface::Delete(debugoverlay); - } + Interface::Temp(this, "VDebugOverlay0", [this](const Interface* debugoverlay) { + this->ScreenPosition = debugoverlay->Original<_ScreenPosition>(Offsets::ScreenPosition); + }); - Command::Hook("plugin_load", Engine::plugin_load_callback_hook, Engine::plugin_load_callback); - Command::Hook("plugin_unload", Engine::plugin_unload_callback_hook, Engine::plugin_unload_callback); - Command::Hook("exit", Engine::exit_callback_hook, Engine::exit_callback); - Command::Hook("quit", Engine::quit_callback_hook, Engine::quit_callback); - Command::Hook("help", Engine::help_callback_hook, Engine::help_callback); + plugin_load_hook.Register(this); + plugin_unload_hook.Register(this); + exit_hook.Register(this); + quit_hook.Register(this); + help_hook.Register(this); if (sar.game->Is(SourceGame_Portal2Game)) { - Command::Hook("gameui_activate", Engine::gameui_activate_callback_hook, Engine::gameui_activate_callback); + gameui_activate_hook.Register(this); } host_framerate = Variable("host_framerate"); net_showmsg = Variable("net_showmsg"); - - return this->hasLoaded = this->engineClient && this->s_ServerPlugin && this->demoplayer && this->demorecorder; } void Engine::Shutdown() { if (this->engineClient && sar.game->Is(SourceGame_Portal2Game)) { auto GetSteamAPIContext = this->engineClient->Original(Offsets::GetSteamAPIContext); auto OnGameOverlayActivated = reinterpret_cast<_OnGameOverlayActivated*>(GetSteamAPIContext() + Offsets::OnGameOverlayActivated); - *OnGameOverlayActivated = Engine::OnGameOverlayActivatedBase; - } - - Interface::Delete(this->engineClient); - Interface::Delete(this->s_ServerPlugin); - Interface::Delete(this->cl); - Interface::Delete(this->eng); - Interface::Delete(this->s_GameEventManager); - -#ifdef _WIN32 - Command::Unhook("connect", Engine::connect_callback); - - MH_UNHOOK(Engine::ParseSmoothingInfo_Mid); - - if (this->demoSmootherPatch) { - this->demoSmootherPatch->Restore(); - } - SAFE_DELETE(this->demoSmootherPatch) -#endif - Command::Unhook("plugin_load", Engine::plugin_load_callback); - Command::Unhook("plugin_unload", Engine::plugin_unload_callback); - Command::Unhook("exit", Engine::exit_callback); - Command::Unhook("quit", Engine::quit_callback); - Command::Unhook("help", Engine::help_callback); - Command::Unhook("gameui_activate", Engine::gameui_activate_callback); - - if (this->demoplayer) { - this->demoplayer->Shutdown(); - } - if (this->demorecorder) { - this->demorecorder->Shutdown(); + *OnGameOverlayActivated = OnGameOverlayActivatedBase; } - SAFE_DELETE(this->demoplayer) - SAFE_DELETE(this->demorecorder) + Interface::Destroy(this->engineClient); + Interface::Destroy(this->s_ServerPlugin); + Interface::Destroy(this->cl); + Interface::Destroy(this->eng); + Interface::Destroy(this->s_GameEventManager); } Engine* engine; diff --git a/src/Modules/Engine.hpp b/src/Modules/Engine.hpp index 1e182613..fab83c05 100644 --- a/src/Modules/Engine.hpp +++ b/src/Modules/Engine.hpp @@ -63,9 +63,6 @@ class Engine : public Module { _ClientCommand ClientCommand = nullptr; _GetLocalClient GetLocalClient = nullptr; - EngineDemoPlayer* demoplayer = nullptr; - EngineDemoRecorder* demorecorder = nullptr; - int* tickcount = nullptr; double* net_time = nullptr; float* interval_per_tick = nullptr; @@ -73,8 +70,6 @@ class Engine : public Module { bool* m_bLoadgame = nullptr; CHostState* hoststate = nullptr; void* s_CommandBuffer = nullptr; - bool* m_bWaitEnabled = nullptr; - bool* m_bWaitEnabled2 = nullptr; bool overlayActivated = false; @@ -90,48 +85,14 @@ class Engine : public Module { int PointToScreen(const Vector& point, Vector& screen); void SafeUnload(const char* postCommand = nullptr); - // CClientState::Disconnect - DECL_DETOUR(Disconnect, bool bShowMainMenu); -#ifdef _WIN32 - DECL_DETOUR(Disconnect2, int unk1, int unk2, int unk3); - DECL_DETOUR_COMMAND(connect); -#else - DECL_DETOUR(Disconnect2, int unk, bool bShowMainMenu); -#endif - - // CClientState::SetSignonState - DECL_DETOUR(SetSignonState, int state, int count, void* unk); - DECL_DETOUR(SetSignonState2, int state, int count); - - // CEngine::Frame - DECL_DETOUR(Frame); - - // CSteam3Client::OnGameOverlayActivated - DECL_DETOUR_B(OnGameOverlayActivated, GameOverlayActivated_t* pGameOverlayActivated); - - DECL_DETOUR_COMMAND(plugin_load); - DECL_DETOUR_COMMAND(plugin_unload); - DECL_DETOUR_COMMAND(exit); - DECL_DETOUR_COMMAND(quit); - DECL_DETOUR_COMMAND(help); - DECL_DETOUR_COMMAND(gameui_activate); - -#ifdef _WIN32 - using _ReadCustomData = int(__fastcall*)(void* thisptr, int edx, void* unk1, void* unk2); - static _ReadCustomData ReadCustomData; - - // CDemoSmootherPanel::ParseSmoothingInfo - static uintptr_t ParseSmoothingInfo_Skip; - static uintptr_t ParseSmoothingInfo_Default; - static uintptr_t ParseSmoothingInfo_Continue; - DECL_DETOUR_MID_MH(ParseSmoothingInfo_Mid); - - Memory::Patch* demoSmootherPatch = nullptr; -#endif + Engine() + : Module(MODULE("engine")) + { + this->isHookable = true; + } - bool Init() override; + void Init() override; void Shutdown() override; - const char* Name() override { return MODULE("engine"); } }; extern Engine* engine; @@ -141,7 +102,9 @@ extern Variable net_showmsg; #define TIME_TO_TICKS(dt) ((int)(0.5f + (float)(dt) / *engine->interval_per_tick)) #define GET_SLOT() engine->GetLocalPlayerIndex() - 1 -#define IGNORE_DEMO_PLAYER() if (engine->demoplayer->IsPlaying()) return; +#define IGNORE_DEMO_PLAYER() \ + if (demoplayer->IsPlaying()) \ + return; #ifdef _WIN32 #define GET_ACTIVE_SPLITSCREEN_SLOT() engine->GetActiveSplitScreenPlayerSlot() diff --git a/src/Modules/EngineDemoPlayer.cpp b/src/Modules/EngineDemoPlayer.cpp index b411675c..16873044 100644 --- a/src/Modules/EngineDemoPlayer.cpp +++ b/src/Modules/EngineDemoPlayer.cpp @@ -1,5 +1,7 @@ #include "EngineDemoPlayer.hpp" +#include + #include "Features/Demo/Demo.hpp" #include "Features/Demo/DemoParser.hpp" @@ -11,8 +13,6 @@ #include "SAR.hpp" #include "Utils.hpp" -REDECL(EngineDemoPlayer::StartPlayback); - int EngineDemoPlayer::GetTick() { return this->GetPlaybackTick(this->s_ClientDemoPlayer->ThisPtr()); @@ -23,15 +23,15 @@ bool EngineDemoPlayer::IsPlaying() } // CDemoRecorder::StartPlayback -DETOUR(EngineDemoPlayer::StartPlayback, const char* filename, bool bAsTimeDemo) +DETOUR(StartPlayback, const char* filename, bool bAsTimeDemo) { - auto result = EngineDemoPlayer::StartPlayback(thisptr, filename, bAsTimeDemo); + auto result = StartPlayback(thisptr, filename, bAsTimeDemo); if (result) { DemoParser parser; Demo demo; auto dir = std::string(engine->GetGameDirectory()) + std::string("/") - + std::string(engine->demoplayer->DemoName); + + std::string(demoplayer->DemoName); if (parser.Parse(dir, &demo)) { parser.Adjust(&demo); console->Print("Client: %s\n", demo.clientName); @@ -40,27 +40,31 @@ DETOUR(EngineDemoPlayer::StartPlayback, const char* filename, bool bAsTimeDemo) console->Print("Time: %.3f\n", demo.playbackTime); console->Print("Tickrate: %.3f\n", demo.Tickrate()); } else { - console->Print("Could not parse \"%s\"!\n", engine->demoplayer->DemoName); + console->Print("Could not parse \"%s\"!\n", demoplayer->DemoName); } } return result; } -bool EngineDemoPlayer::Init() +void EngineDemoPlayer::Init() { + if (!engine->Loaded()) { + throw std::runtime_error("engine module is required to be loaded"); + } + auto disconnect = engine->cl->Original(Offsets::Disconnect); - auto demoplayer = Memory::DerefDeref(disconnect + Offsets::demoplayer); - if (this->s_ClientDemoPlayer = Interface::Create(demoplayer)) { - this->s_ClientDemoPlayer->Hook(EngineDemoPlayer::StartPlayback_Hook, EngineDemoPlayer::StartPlayback, Offsets::StartPlayback); + auto demoplayer = Memory::DerefDeref(disconnect + Offsets::demoplayer); - this->GetPlaybackTick = s_ClientDemoPlayer->Original<_GetPlaybackTick>(Offsets::GetPlaybackTick); - this->IsPlayingBack = s_ClientDemoPlayer->Original<_IsPlayingBack>(Offsets::IsPlayingBack); - this->DemoName = reinterpret_cast((uintptr_t)demoplayer + Offsets::m_szFileName); - } + this->s_ClientDemoPlayer = Interface::Hookable(this, demoplayer); + this->s_ClientDemoPlayer->Hook(&hkStartPlayback, Offsets::StartPlayback); - return this->hasLoaded = this->s_ClientDemoPlayer; + this->GetPlaybackTick = s_ClientDemoPlayer->Original<_GetPlaybackTick>(Offsets::GetPlaybackTick); + this->IsPlayingBack = s_ClientDemoPlayer->Original<_IsPlayingBack>(Offsets::IsPlayingBack); + this->DemoName = reinterpret_cast(demoplayer + Offsets::m_szFileName); } void EngineDemoPlayer::Shutdown() { - Interface::Delete(this->s_ClientDemoPlayer); + Interface::Destroy(this->s_ClientDemoPlayer); } + +EngineDemoPlayer* demoplayer; diff --git a/src/Modules/EngineDemoPlayer.hpp b/src/Modules/EngineDemoPlayer.hpp index 0c795b88..f35bc41b 100644 --- a/src/Modules/EngineDemoPlayer.hpp +++ b/src/Modules/EngineDemoPlayer.hpp @@ -22,10 +22,14 @@ class EngineDemoPlayer : public Module { int GetTick(); bool IsPlaying(); - // CDemoRecorder::StartPlayback - DECL_DETOUR(StartPlayback, const char* filename, bool bAsTimeDemo); + EngineDemoPlayer() + : Module(MODULE("engine")) + { + this->isHookable = true; + } - bool Init() override; + void Init() override; void Shutdown() override; - const char* Name() override { return MODULE("engine"); } }; + +extern EngineDemoPlayer* demoplayer; diff --git a/src/Modules/EngineDemoRecorder.cpp b/src/Modules/EngineDemoRecorder.cpp index 5a682d47..72a446a5 100644 --- a/src/Modules/EngineDemoRecorder.cpp +++ b/src/Modules/EngineDemoRecorder.cpp @@ -1,5 +1,7 @@ #include "EngineDemoRecorder.hpp" +#include + #include "Features/Rebinder.hpp" #include "Features/Session.hpp" #include "Features/Timer/Timer.hpp" @@ -12,95 +14,94 @@ #include "Offsets.hpp" #include "Utils.hpp" -REDECL(EngineDemoRecorder::SetSignonState); -REDECL(EngineDemoRecorder::StopRecording); -REDECL(EngineDemoRecorder::stop_callback); - int EngineDemoRecorder::GetTick() { return this->GetRecordingTick(this->s_ClientDemoRecorder->ThisPtr()); } // CDemoRecorder::SetSignonState -DETOUR(EngineDemoRecorder::SetSignonState, int state) +DETOUR(SetSignonState3, int state) { //SIGNONSTATE_FULL is set twice during first CM load. Using SINGONSTATE_SPAWN for demo number increase instead if (state == SIGNONSTATE_SPAWN) { - if (engine->demorecorder->isRecordingDemo || *engine->demorecorder->m_bRecording || sar_record_at_increment.GetBool()) { - engine->demorecorder->lastDemoNumber++; + if (demorecorder->isRecordingDemo || *demorecorder->m_bRecording || sar_record_at_increment.GetBool()) { + demorecorder->lastDemoNumber++; } } if (state == SIGNONSTATE_FULL) { //autorecording in different session (save deletion) - if (engine->demorecorder->isRecordingDemo) { - *engine->demorecorder->m_bRecording = true; + if (demorecorder->isRecordingDemo) { + *demorecorder->m_bRecording = true; } - if (*engine->demorecorder->m_bRecording) { - engine->demorecorder->isRecordingDemo = true; - *engine->demorecorder->m_nDemoNumber = engine->demorecorder->lastDemoNumber; - engine->demorecorder->currentDemo = std::string(engine->demorecorder->m_szDemoBaseName); + if (*demorecorder->m_bRecording) { + demorecorder->isRecordingDemo = true; + *demorecorder->m_nDemoNumber = demorecorder->lastDemoNumber; + demorecorder->currentDemo = std::string(demorecorder->m_szDemoBaseName); - if (*engine->demorecorder->m_nDemoNumber > 1) { - engine->demorecorder->currentDemo += std::string("_") + std::to_string(*engine->demorecorder->m_nDemoNumber); + if (*demorecorder->m_nDemoNumber > 1) { + demorecorder->currentDemo += std::string("_") + std::to_string(*demorecorder->m_nDemoNumber); } } } - return EngineDemoRecorder::SetSignonState(thisptr, state); + return SetSignonState3(thisptr, state); } // CDemoRecorder::StopRecording -DETOUR(EngineDemoRecorder::StopRecording) +DETOUR(StopRecording) { // This function does: // m_bRecording = false // m_nDemoNumber = 0 - auto result = EngineDemoRecorder::StopRecording(thisptr); + auto result = StopRecording(thisptr); - if (engine->demorecorder->isRecordingDemo && sar_autorecord.GetBool() && !engine->demorecorder->requestedStop) { - *engine->demorecorder->m_nDemoNumber = engine->demorecorder->lastDemoNumber; - *engine->demorecorder->m_bRecording = true; + if (demorecorder->isRecordingDemo && sar_autorecord.GetBool() && !demorecorder->requestedStop) { + *demorecorder->m_nDemoNumber = demorecorder->lastDemoNumber; + *demorecorder->m_bRecording = true; } else if (sar_record_at_increment.GetBool()) { - *engine->demorecorder->m_nDemoNumber = engine->demorecorder->lastDemoNumber; - engine->demorecorder->isRecordingDemo = false; + *demorecorder->m_nDemoNumber = demorecorder->lastDemoNumber; + demorecorder->isRecordingDemo = false; } else { - engine->demorecorder->isRecordingDemo = false; - engine->demorecorder->lastDemoNumber = 1; + demorecorder->isRecordingDemo = false; + demorecorder->lastDemoNumber = 1; } return result; } -DETOUR_COMMAND(EngineDemoRecorder::stop) +DETOUR_COMMAND(stop) { - engine->demorecorder->requestedStop = true; - EngineDemoRecorder::stop_callback(args); - engine->demorecorder->requestedStop = false; + demorecorder->requestedStop = true; + stop_callback(args); + demorecorder->requestedStop = false; } -bool EngineDemoRecorder::Init() +void EngineDemoRecorder::Init() { + if (!engine->Loaded()) { + throw std::runtime_error("engine module is required to be loaded"); + } + auto disconnect = engine->cl->Original(Offsets::Disconnect); - auto demorecorder = Memory::DerefDeref(disconnect + Offsets::demorecorder); - if (this->s_ClientDemoRecorder = Interface::Create(demorecorder)) { - this->s_ClientDemoRecorder->Hook(EngineDemoRecorder::SetSignonState_Hook, EngineDemoRecorder::SetSignonState, Offsets::SetSignonState); - this->s_ClientDemoRecorder->Hook(EngineDemoRecorder::StopRecording_Hook, EngineDemoRecorder::StopRecording, Offsets::StopRecording); + auto demorecorder = Memory::DerefDeref(disconnect + Offsets::demorecorder); - this->GetRecordingTick = s_ClientDemoRecorder->Original<_GetRecordingTick>(Offsets::GetRecordingTick); - this->m_szDemoBaseName = reinterpret_cast((uintptr_t)demorecorder + Offsets::m_szDemoBaseName); - this->m_nDemoNumber = reinterpret_cast((uintptr_t)demorecorder + Offsets::m_nDemoNumber); - this->m_bRecording = reinterpret_cast((uintptr_t)demorecorder + Offsets::m_bRecording); + this->s_ClientDemoRecorder = Interface::Hookable(this, demorecorder); + this->s_ClientDemoRecorder->Hook(&hkSetSignonState3, Offsets::SetSignonState); + this->s_ClientDemoRecorder->Hook(&hkStopRecording, Offsets::StopRecording); - engine->net_time = Memory::Deref((uintptr_t)this->GetRecordingTick + Offsets::net_time); - } + this->GetRecordingTick = s_ClientDemoRecorder->Original<_GetRecordingTick>(Offsets::GetRecordingTick); + this->m_szDemoBaseName = reinterpret_cast(demorecorder + Offsets::m_szDemoBaseName); + this->m_nDemoNumber = reinterpret_cast(demorecorder + Offsets::m_nDemoNumber); + this->m_bRecording = reinterpret_cast(demorecorder + Offsets::m_bRecording); - Command::Hook("stop", EngineDemoRecorder::stop_callback_hook, EngineDemoRecorder::stop_callback); + engine->net_time = Memory::Deref((uintptr_t)this->GetRecordingTick + Offsets::net_time); - return this->hasLoaded = this->s_ClientDemoRecorder; + stop_hook.Register(this); } void EngineDemoRecorder::Shutdown() { - Interface::Delete(this->s_ClientDemoRecorder); - Command::Unhook("stop", EngineDemoRecorder::stop_callback); + Interface::Destroy(this->s_ClientDemoRecorder); } + +EngineDemoRecorder* demorecorder; diff --git a/src/Modules/EngineDemoRecorder.hpp b/src/Modules/EngineDemoRecorder.hpp index 1d7962c8..83e21e5c 100644 --- a/src/Modules/EngineDemoRecorder.hpp +++ b/src/Modules/EngineDemoRecorder.hpp @@ -26,15 +26,14 @@ class EngineDemoRecorder : public Module { public: int GetTick(); - // CDemoRecorder::SetSignonState - DECL_DETOUR(SetSignonState, int state); + EngineDemoRecorder() + : Module(MODULE("engine")) + { + this->isHookable = true; + } - // CDemoRecorder::StopRecording - DECL_DETOUR(StopRecording); - - DECL_DETOUR_COMMAND(stop); - - bool Init() override; + void Init() override; void Shutdown() override; - const char* Name() override { return MODULE("engine"); } }; + +extern EngineDemoRecorder* demorecorder; diff --git a/src/Modules/InputSystem.cpp b/src/Modules/InputSystem.cpp index 5a820ec5..797ff710 100644 --- a/src/Modules/InputSystem.cpp +++ b/src/Modules/InputSystem.cpp @@ -8,45 +8,37 @@ #include "SAR.hpp" #include "Utils.hpp" -REDECL(InputSystem::SleepUntilInput); - int InputSystem::GetButton(const char* pString) { return this->StringToButtonCode(this->g_InputSystem->ThisPtr(), pString); } // CInputSystem::SleepUntilInput -DETOUR(InputSystem::SleepUntilInput, int nMaxSleepTimeMS) +DETOUR(SleepUntilInput, int nMaxSleepTimeMS) { if (sar_disable_no_focus_sleep.GetBool()) { nMaxSleepTimeMS = 0; } - return InputSystem::SleepUntilInput(thisptr, nMaxSleepTimeMS); + return SleepUntilInput(thisptr, nMaxSleepTimeMS); } -bool InputSystem::Init() +void InputSystem::Init() { - this->g_InputSystem = Interface::Create(this->Name(), "InputSystemVersion0"); - if (this->g_InputSystem) { - this->StringToButtonCode = this->g_InputSystem->Original<_StringToButtonCode>(Offsets::StringToButtonCode); + this->g_InputSystem = Interface::Hookable(this, "InputSystemVersion0"); + this->StringToButtonCode = this->g_InputSystem->Original<_StringToButtonCode>(Offsets::StringToButtonCode); - if (sar.game->Is(SourceGame_Portal2Engine)) { - this->g_InputSystem->Hook(InputSystem::SleepUntilInput_Hook, InputSystem::SleepUntilInput, Offsets::SleepUntilInput); - } + if (sar.game->Is(SourceGame_Portal2Engine)) { + this->g_InputSystem->Hook(&hkSleepUntilInput, Offsets::SleepUntilInput); } auto unbind = Command("unbind"); - if (!!unbind) { - auto cc_unbind_callback = (uintptr_t)unbind.ThisPtr()->m_pCommandCallback; - this->KeySetBinding = Memory::Read<_KeySetBinding>(cc_unbind_callback + Offsets::Key_SetBinding); - } - - return this->hasLoaded = this->g_InputSystem && !!unbind; + auto cc_unbind_callback = (uintptr_t)unbind.ThisPtr()->m_pCommandCallback; + this->KeySetBinding = Memory::Read<_KeySetBinding>(cc_unbind_callback + Offsets::Key_SetBinding); } void InputSystem::Shutdown() { - Interface::Delete(this->g_InputSystem); + Interface::Destroy(this->g_InputSystem); } InputSystem* inputSystem; diff --git a/src/Modules/InputSystem.hpp b/src/Modules/InputSystem.hpp index f83bff1c..97fed5ba 100644 --- a/src/Modules/InputSystem.hpp +++ b/src/Modules/InputSystem.hpp @@ -22,12 +22,14 @@ class InputSystem : public Module { public: int GetButton(const char* pString); - // CInputSystem::SleepUntilInput - DECL_DETOUR(SleepUntilInput, int nMaxSleepTimeMS); + InputSystem() + : Module(MODULE("inputsystem")) + { + this->isHookable = true; + } - bool Init() override; + void Init() override; void Shutdown() override; - const char* Name() override { return MODULE("inputsystem"); } }; extern InputSystem* inputSystem; diff --git a/src/Modules/Module.cpp b/src/Modules/Module.cpp index 76cccf7d..dd7bda9b 100644 --- a/src/Modules/Module.cpp +++ b/src/Modules/Module.cpp @@ -1,36 +1,56 @@ #include "Module.hpp" +#include #include +Module::Module(const char* filename) + : filename(filename) +{ +} +bool Module::Load() +{ + if (!this->isLoaded) { + try { + this->Init(); + this->isLoaded = true; + } catch (std::exception& ex) { + throw std::runtime_error(std::string("Module::Init error in ") + this->filename + " -> " + ex.what()); + } + } + return this->isLoaded; +} +bool Module::Unload() +{ + if (this->isLoaded) { + this->Shutdown(); + this->isLoaded = false; + } + return this->isLoaded; +} + Modules::Modules() : list() { } -void Modules::InitAll() +void Modules::LoadAll() { for (const auto& mod : this->list) { - if (!mod->hasLoaded) { - mod->Init(); - } + mod->Load(); } } -void Modules::ShutdownAll() +void Modules::UnloadAll() { for (const auto& mod : this->list) { - mod->Shutdown(); - mod->hasLoaded = false; + mod->Unload(); } } -void Modules::DeleteAll() +Modules::~Modules() { + this->UnloadAll(); for (auto& mod : this->list) { if (mod) { delete mod; } } -} -Modules::~Modules() -{ - this->DeleteAll(); this->list.clear(); } diff --git a/src/Modules/Module.hpp b/src/Modules/Module.hpp index 1f324a63..fd7a65e7 100644 --- a/src/Modules/Module.hpp +++ b/src/Modules/Module.hpp @@ -1,22 +1,35 @@ #pragma once #include -#define DECL_M(name, type) type name(void* entity) -#define MDECL(name, type, offset) \ - type name(void* entity) \ - { \ - return *reinterpret_cast((uintptr_t)entity + Offsets::offset); \ - } +#include "Interface.hpp" + +#define ENTPROP(name, type, offset) \ + inline type name(void* entity) { return *reinterpret_cast((uintptr_t)entity + Offsets::offset); } + +class Interface; +class CommandHook; class Module { +private: + bool isLoaded = false; + +protected: + bool isHookable = false; + public: - bool hasLoaded = false; + const char* filename = nullptr; + std::vector interfaces = std::vector(); + std::vector cmdHooks = std::vector(); public: + Module(const char* filename); + inline bool Loaded() { return this->isLoaded; } + inline bool CanHook() { return this->isHookable; } virtual ~Module() = default; - virtual bool Init() = 0; + virtual void Init() = 0; virtual void Shutdown() = 0; - virtual const char* Name() = 0; + virtual bool Load() final; + virtual bool Unload() final; }; class Modules { @@ -36,8 +49,7 @@ class Modules { { this->list.erase(*modulePtr); } - void InitAll(); - void ShutdownAll(); - void DeleteAll(); + void LoadAll(); + void UnloadAll(); ~Modules(); }; diff --git a/src/Modules/Scheme.cpp b/src/Modules/Scheme.cpp index 9d6d44b9..42ae4478 100644 --- a/src/Modules/Scheme.cpp +++ b/src/Modules/Scheme.cpp @@ -9,25 +9,20 @@ unsigned long Scheme::GetDefaultFont() { return this->GetFont(this->g_pScheme->ThisPtr(), "DefaultFixedOutline", 0); } -bool Scheme::Init() +void Scheme::Init() { - if (auto g_pVGuiSchemeManager = Interface::Create(this->Name(), "VGUI_Scheme0", false)) { - using _GetIScheme = void*(__rescall*)(void* thisptr, unsigned long scheme); + Interface::Temp(this, "VGUI_Scheme0", [this](const Interface* g_pVGuiSchemeManager) { + using _GetIScheme = uintptr_t(__rescall*)(void* thisptr, unsigned long scheme); auto GetIScheme = g_pVGuiSchemeManager->Original<_GetIScheme>(Offsets::GetIScheme); // Default scheme is 1 - this->g_pScheme = Interface::Create(GetIScheme(g_pVGuiSchemeManager->ThisPtr(), 1)); - if (this->g_pScheme) { - this->GetFont = this->g_pScheme->Original<_GetFont>(Offsets::GetFont); - } - Interface::Delete(g_pVGuiSchemeManager); - } - - return this->hasLoaded = this->g_pScheme; + this->g_pScheme = Interface::CreateNew(GetIScheme(g_pVGuiSchemeManager->ThisPtr(), 1)); + this->GetFont = this->g_pScheme->Original<_GetFont>(Offsets::GetFont); + }); } void Scheme::Shutdown() { - Interface::Delete(this->g_pScheme); + Interface::Destroy(this->g_pScheme); } Scheme* scheme; diff --git a/src/Modules/Scheme.hpp b/src/Modules/Scheme.hpp index fb6cbc8f..b3626049 100644 --- a/src/Modules/Scheme.hpp +++ b/src/Modules/Scheme.hpp @@ -4,7 +4,6 @@ #include "Interface.hpp" #include "Utils.hpp" -// TODO: Custom fonts class Scheme : public Module { public: Interface* g_pScheme = nullptr; @@ -15,9 +14,13 @@ class Scheme : public Module { public: unsigned long GetDefaultFont(); - bool Init() override; + Scheme() + : Module(MODULE("vgui2")) + { + } + + void Init() override; void Shutdown() override; - const char* Name() override { return MODULE("vgui2"); } }; extern Scheme* scheme; diff --git a/src/Modules/Server.cpp b/src/Modules/Server.cpp index d8a4ce9d..8f5cfdf9 100644 --- a/src/Modules/Server.cpp +++ b/src/Modules/Server.cpp @@ -42,33 +42,6 @@ Variable sar_record_at("sar_record_at", "0", 0, "Start recording a demo at the t Variable sar_record_at_demo_name("sar_record_at_demo_name", "chamber", "Name of the demo automatically recorded.\n", 0); Variable sar_record_at_increment("sar_record_at_increment", "0", "Increment automatically the demo name.\n"); -REDECL(Server::CheckJumpButton); -REDECL(Server::CheckJumpButtonBase); -REDECL(Server::PlayerMove); -REDECL(Server::FinishGravity); -REDECL(Server::AirMove); -REDECL(Server::AirMoveBase); -REDECL(Server::GameFrame); -REDECL(Server::ProcessMovement); -#ifdef _WIN32 -REDECL(Server::AirMove_Skip); -REDECL(Server::AirMove_Continue); -REDECL(Server::AirMove_Mid); -REDECL(Server::AirMove_Mid_Trampoline); -#endif - -MDECL(Server::GetPortals, int, iNumPortalsPlaced); -MDECL(Server::GetAbsOrigin, Vector, S_m_vecAbsOrigin); -MDECL(Server::GetAbsAngles, QAngle, S_m_angAbsRotation); -MDECL(Server::GetLocalVelocity, Vector, S_m_vecVelocity); -MDECL(Server::GetFlags, int, m_fFlags); -MDECL(Server::GetEFlags, int, m_iEFlags); -MDECL(Server::GetMaxSpeed, float, m_flMaxspeed); -MDECL(Server::GetGravity, float, m_flGravity); -MDECL(Server::GetViewOffset, Vector, S_m_vecViewOffset); -MDECL(Server::GetEntityName, char*, m_iName); -MDECL(Server::GetEntityClassName, char*, m_iClassName); - void* Server::GetPlayer(int index) { return this->UTIL_PlayerByIndex(index); @@ -94,7 +67,7 @@ int Server::GetSplitScreenPlayerSlot(void* entity) } // CGameMovement::CheckJumpButton -DETOUR_T(bool, Server::CheckJumpButton) +DETOUR_BT(bool, CheckJumpButton) { auto jumped = false; @@ -110,15 +83,15 @@ DETOUR_T(bool, Server::CheckJumpButton) server->callFromCheckJumpButton = true; jumped = (sar_duckjump.isRegistered && sar_duckjump.GetBool()) - ? Server::CheckJumpButtonBase(thisptr) - : Server::CheckJumpButton(thisptr); + ? CheckJumpButtonBase(thisptr) + : CheckJumpButton(thisptr); server->callFromCheckJumpButton = false; if (jumped) { server->jumpedLastTime = true; } } else { - jumped = Server::CheckJumpButton(thisptr); + jumped = CheckJumpButton(thisptr); } if (jumped) { @@ -133,7 +106,7 @@ DETOUR_T(bool, Server::CheckJumpButton) } // CGameMovement::PlayerMove -DETOUR(Server::PlayerMove) +DETOUR(PlayerMove) { auto player = *reinterpret_cast((uintptr_t)thisptr + Offsets::player); auto mv = *reinterpret_cast((uintptr_t)thisptr + Offsets::mv); @@ -166,22 +139,22 @@ DETOUR(Server::PlayerMove) stat->velocity->Save(server->GetLocalVelocity(player), sar_stats_velocity_peak_xy.GetBool()); inspector->Record(); - return Server::PlayerMove(thisptr); + return PlayerMove(thisptr); } // CGameMovement::ProcessMovement -DETOUR(Server::ProcessMovement, void* pPlayer, CMoveData* pMove) +DETOUR(ProcessMovement, void* pPlayer, CMoveData* pMove) { if (sv_cheats.GetBool()) { autoStrafer->Strafe(pPlayer, pMove); tasTools->SetAngles(pPlayer); } - return Server::ProcessMovement(thisptr, pPlayer, pMove); + return ProcessMovement(thisptr, pPlayer, pMove); } // CGameMovement::FinishGravity -DETOUR(Server::FinishGravity) +DETOUR(FinishGravity) { if (server->callFromCheckJumpButton) { if (sar_duckjump.GetBool()) { @@ -232,49 +205,24 @@ DETOUR(Server::FinishGravity) } } - return Server::FinishGravity(thisptr); + return FinishGravity(thisptr); } // CGameMovement::AirMove -DETOUR_B(Server::AirMove) +DETOUR_B(AirMove) { if (sar_aircontrol.GetInt() >= 2 && server->AllowsMovementChanges()) { - return Server::AirMoveBase(thisptr); + return AirMoveBase(thisptr); } - return Server::AirMove(thisptr); + return AirMove(thisptr); } -#ifdef _WIN32 -DETOUR_MID_MH(Server::AirMove_Mid) -{ - __asm { - pushad - pushfd - } - - if (sar_aircontrol.GetBool() && server->AllowsMovementChanges()) - { - __asm { - popfd - popad - jmp Server::AirMove_Skip - } - } - - __asm { - popfd - popad - movss xmm2, dword ptr[eax + 0x40] - jmp Server::AirMove_Continue - } -} -#endif // CServerGameDLL::GameFrame #ifdef _WIN32 -DETOUR_STD(void, Server::GameFrame, bool simulating) +DETOUR_STD(void, GameFrame, bool simulating) #else -DETOUR(Server::GameFrame, bool simulating) +DETOUR(GameFrame, bool simulating) #endif { if (simulating && sar_record_at.GetFloat() > 0 && sar_record_at.GetFloat() == session->GetTick()) { @@ -292,9 +240,9 @@ DETOUR(Server::GameFrame, bool simulating) } #ifdef _WIN32 - Server::GameFrame(simulating); + GameFrame(simulating); #else - auto result = Server::GameFrame(thisptr, simulating); + auto result = GameFrame(thisptr, simulating); #endif if (sar_pause.GetBool()) { @@ -338,60 +286,41 @@ DETOUR(Server::GameFrame, bool simulating) #endif } -bool Server::Init() +void Server::Init() { - this->g_GameMovement = Interface::Create(this->Name(), "GameMovement0"); - this->g_ServerGameDLL = Interface::Create(this->Name(), "ServerGameDLL0"); - - if (this->g_GameMovement) { - this->g_GameMovement->Hook(Server::CheckJumpButton_Hook, Server::CheckJumpButton, Offsets::CheckJumpButton); - this->g_GameMovement->Hook(Server::PlayerMove_Hook, Server::PlayerMove, Offsets::PlayerMove); + this->g_GameMovement = Interface::Hookable(this, "GameMovement0"); + this->g_ServerGameDLL = Interface::Hookable(this, "ServerGameDLL0"); - if (sar.game->Is(SourceGame_Portal2Engine)) { - this->g_GameMovement->Hook(Server::ProcessMovement_Hook, Server::ProcessMovement, Offsets::ProcessMovement); - this->g_GameMovement->Hook(Server::FinishGravity_Hook, Server::FinishGravity, Offsets::FinishGravity); - this->g_GameMovement->Hook(Server::AirMove_Hook, Server::AirMove, Offsets::AirMove); + this->g_GameMovement->Hook(&hkCheckJumpButton, Offsets::CheckJumpButton); + this->g_GameMovement->Hook(&hkPlayerMove, Offsets::PlayerMove); - auto ctor = this->g_GameMovement->Original(0); - auto baseCtor = Memory::Read(ctor + Offsets::AirMove_Offset1); - auto baseOffset = Memory::Deref(baseCtor + Offsets::AirMove_Offset2); - Memory::Deref<_AirMove>(baseOffset + Offsets::AirMove * sizeof(uintptr_t*), &Server::AirMoveBase); + if (sar.game->Is(SourceGame_Portal2Engine)) { + this->g_GameMovement->Hook(&hkProcessMovement, Offsets::ProcessMovement); + this->g_GameMovement->Hook(&hkFinishGravity, Offsets::FinishGravity); + this->g_GameMovement->Hook(&hkAirMove, Offsets::AirMove); - Memory::Deref<_CheckJumpButton>(baseOffset + Offsets::CheckJumpButton * sizeof(uintptr_t*), &Server::CheckJumpButtonBase); + auto ctor = this->g_GameMovement->Original(0); + auto baseCtor = Memory::Read(ctor + Offsets::AirMove_Offset1); + auto baseOffset = Memory::Deref(baseCtor + Offsets::AirMove_Offset2); + Memory::Deref<_AirMove>(baseOffset + Offsets::AirMove * sizeof(uintptr_t), &AirMoveBase); -#ifdef _WIN32 - if (!sar.game->Is(SourceGame_INFRA)) { - auto airMoveMid = this->g_GameMovement->Original(Offsets::AirMove) + AirMove_Mid_Offset; - if (Memory::FindAddress(airMoveMid, airMoveMid + 5, AirMove_Signature) == airMoveMid) { - MH_HOOK_MID(this->AirMove_Mid, airMoveMid); - this->AirMove_Continue = airMoveMid + AirMove_Continue_Offset; - this->AirMove_Skip = airMoveMid + AirMove_Skip_Offset; - console->DevMsg("SAR: Verified sar_aircontrol 1!\n"); - } else { - console->Warning("SAR: Failed to enable sar_aircontrol 1 style!\n"); - } - } -#endif - } + Memory::Deref<_CheckJumpButton>(baseOffset + Offsets::CheckJumpButton * sizeof(uintptr_t), &CheckJumpButtonBase); } - if (auto g_ServerTools = Interface::Create(this->Name(), "VSERVERTOOLS0")) { + Interface::Temp(this, "VSERVERTOOLS0", [this](const Interface* g_ServerTools) { auto GetIServerEntity = g_ServerTools->Original(Offsets::GetIServerEntity); Memory::Deref(GetIServerEntity + Offsets::m_EntPtrArray, &this->m_EntPtrArray); - Interface::Delete(g_ServerTools); - } + }); - if (this->g_ServerGameDLL) { - auto Think = this->g_ServerGameDLL->Original(Offsets::Think); - Memory::Read<_UTIL_PlayerByIndex>(Think + Offsets::UTIL_PlayerByIndex, &this->UTIL_PlayerByIndex); - Memory::DerefDeref((uintptr_t)this->UTIL_PlayerByIndex + Offsets::gpGlobals, &this->gpGlobals); + auto Think = this->g_ServerGameDLL->Original(Offsets::Think); + Memory::Read<_UTIL_PlayerByIndex>(Think + Offsets::UTIL_PlayerByIndex, &this->UTIL_PlayerByIndex); + Memory::DerefDeref((uintptr_t)this->UTIL_PlayerByIndex + Offsets::gpGlobals, &this->gpGlobals); - this->GetAllServerClasses = this->g_ServerGameDLL->Original<_GetAllServerClasses>(Offsets::GetAllServerClasses); - this->IsRestoring = this->g_ServerGameDLL->Original<_IsRestoring>(Offsets::IsRestoring); + this->GetAllServerClasses = this->g_ServerGameDLL->Original<_GetAllServerClasses>(Offsets::GetAllServerClasses); + this->IsRestoring = this->g_ServerGameDLL->Original<_IsRestoring>(Offsets::IsRestoring); - if (sar.game->Is(SourceGame_Portal2Game | SourceGame_Portal)) { - this->g_ServerGameDLL->Hook(Server::GameFrame_Hook, Server::GameFrame, Offsets::GameFrame); - } + if (sar.game->Is(SourceGame_Portal2Game | SourceGame_Portal)) { + this->g_ServerGameDLL->Hook(&hkGameFrame, Offsets::GameFrame); } offsetFinder->ServerSide("CBasePlayer", "m_nWaterLevel", &Offsets::m_nWaterLevel); @@ -421,16 +350,11 @@ bool Server::Init() sv_stopspeed = Variable("sv_stopspeed"); sv_maxvelocity = Variable("sv_maxvelocity"); sv_gravity = Variable("sv_gravity"); - - return this->hasLoaded = this->g_GameMovement && this->g_ServerGameDLL; } void Server::Shutdown() { -#if _WIN32 - MH_UNHOOK(this->AirMove_Mid); -#endif - Interface::Delete(this->g_GameMovement); - Interface::Delete(this->g_ServerGameDLL); + Interface::Destroy(this->g_GameMovement); + Interface::Destroy(this->g_ServerGameDLL); } Server* server; diff --git a/src/Modules/Server.hpp b/src/Modules/Server.hpp index 0fc82e2e..c3db8607 100644 --- a/src/Modules/Server.hpp +++ b/src/Modules/Server.hpp @@ -6,13 +6,6 @@ #include "Utils.hpp" #include "Variable.hpp" -#ifdef _WIN32 -#define AirMove_Mid_Offset 679 -#define AirMove_Signature "F3 0F 10 50 40" -#define AirMove_Continue_Offset 5 -#define AirMove_Skip_Offset 142 -#endif - class Server : public Module { public: Interface* g_GameMovement = nullptr; @@ -20,7 +13,7 @@ class Server : public Module { using _UTIL_PlayerByIndex = void*(__cdecl*)(int index); using _GetAllServerClasses = ServerClass* (*)(); - using _IsRestoring = bool(*)(); + using _IsRestoring = bool (*)(); _UTIL_PlayerByIndex UTIL_PlayerByIndex = nullptr; _GetAllServerClasses GetAllServerClasses = nullptr; @@ -29,66 +22,38 @@ class Server : public Module { CGlobalVars* gpGlobals = nullptr; CEntInfo* m_EntPtrArray = nullptr; -private: bool jumpedLastTime = false; float savedVerticalVelocity = 0.0f; bool callFromCheckJumpButton = false; bool paused = false; - int pauseTick; + int pauseTick = 0; public: - DECL_M(GetPortals, int); - DECL_M(GetAbsOrigin, Vector); - DECL_M(GetAbsAngles, QAngle); - DECL_M(GetLocalVelocity, Vector); - DECL_M(GetFlags, int); - DECL_M(GetEFlags, int); - DECL_M(GetMaxSpeed, float); - DECL_M(GetGravity, float); - DECL_M(GetViewOffset, Vector); - DECL_M(GetEntityName, char*); - DECL_M(GetEntityClassName, char*); + ENTPROP(GetPortals, int, iNumPortalsPlaced); + ENTPROP(GetAbsOrigin, Vector, S_m_vecAbsOrigin); + ENTPROP(GetAbsAngles, QAngle, S_m_angAbsRotation); + ENTPROP(GetLocalVelocity, Vector, S_m_vecVelocity); + ENTPROP(GetFlags, int, m_fFlags); + ENTPROP(GetEFlags, int, m_iEFlags); + ENTPROP(GetMaxSpeed, float, m_flMaxspeed); + ENTPROP(GetGravity, float, m_flGravity); + ENTPROP(GetViewOffset, Vector, S_m_vecViewOffset); + ENTPROP(GetEntityName, char*, m_iName); + ENTPROP(GetEntityClassName, char*, m_iClassName); void* GetPlayer(int index); bool IsPlayer(void* entity); bool AllowsMovementChanges(); int GetSplitScreenPlayerSlot(void* entity); -public: - // CGameMovement::ProcessMovement - DECL_DETOUR(ProcessMovement, void* pPlayer, CMoveData* pMove); - - // CGameMovement::CheckJumpButton - DECL_DETOUR_T(bool, CheckJumpButton); - - static _CheckJumpButton CheckJumpButtonBase; - - // CGameMovement::PlayerMove - DECL_DETOUR(PlayerMove); - - // CGameMovement::FinishGravity - DECL_DETOUR(FinishGravity); - - // CGameMovement::AirMove - DECL_DETOUR_B(AirMove); - -#ifdef _WIN32 - // CGameMovement::AirMove - static uintptr_t AirMove_Skip; - static uintptr_t AirMove_Continue; - DECL_DETOUR_MID_MH(AirMove_Mid); -#endif - -// CServerGameDLL::GameFrame -#ifdef _WIN32 - DECL_DETOUR_STD(void, GameFrame, bool simulating); -#else - DECL_DETOUR(GameFrame, bool simulating); -#endif + Server() + : Module(MODULE("server")) + { + this->isHookable = true; + } - bool Init() override; + void Init() override; void Shutdown() override; - const char* Name() override { return MODULE("server"); } }; extern Server* server; diff --git a/src/Modules/Surface.cpp b/src/Modules/Surface.cpp index 8fe0ff91..c31a3b43 100644 --- a/src/Modules/Surface.cpp +++ b/src/Modules/Surface.cpp @@ -57,29 +57,26 @@ void Surface::DrawRectAndCenterTxt(Color clr, int x0, int y0, int x1, int y1, HF this->DrawTxt(font, xc - (tw / 2), yc - (th / 2), fontClr, data); } -bool Surface::Init() +void Surface::Init() { - this->matsurface = Interface::Create(this->Name(), "VGUI_Surface0", false); - if (this->matsurface) { - this->DrawSetColor = matsurface->Original<_DrawSetColor>(Offsets::DrawSetColor); - this->DrawFilledRect = matsurface->Original<_DrawFilledRect>(Offsets::DrawFilledRect); - this->DrawLine = matsurface->Original<_DrawLine>(Offsets::DrawLine); - this->DrawSetTextFont = matsurface->Original<_DrawSetTextFont>(Offsets::DrawSetTextFont); - this->DrawSetTextColor = matsurface->Original<_DrawSetTextColor>(Offsets::DrawSetTextColor); - this->GetFontTall = matsurface->Original<_GetFontTall>(Offsets::GetFontTall); - this->DrawColoredText = matsurface->Original<_DrawColoredText>(Offsets::DrawColoredText); - this->DrawTextLen = matsurface->Original<_DrawTextLen>(Offsets::DrawTextLen); + this->matsurface = Interface::CreateNew(this, "VGUI_Surface0"); - auto PaintTraverseEx = matsurface->Original(Offsets::PaintTraverseEx); - this->StartDrawing = Memory::Read<_StartDrawing>(PaintTraverseEx + Offsets::StartDrawing); - this->FinishDrawing = Memory::Read<_FinishDrawing>(PaintTraverseEx + Offsets::FinishDrawing); - } + this->DrawSetColor = matsurface->Original<_DrawSetColor>(Offsets::DrawSetColor); + this->DrawFilledRect = matsurface->Original<_DrawFilledRect>(Offsets::DrawFilledRect); + this->DrawLine = matsurface->Original<_DrawLine>(Offsets::DrawLine); + this->DrawSetTextFont = matsurface->Original<_DrawSetTextFont>(Offsets::DrawSetTextFont); + this->DrawSetTextColor = matsurface->Original<_DrawSetTextColor>(Offsets::DrawSetTextColor); + this->GetFontTall = matsurface->Original<_GetFontTall>(Offsets::GetFontTall); + this->DrawColoredText = matsurface->Original<_DrawColoredText>(Offsets::DrawColoredText); + this->DrawTextLen = matsurface->Original<_DrawTextLen>(Offsets::DrawTextLen); - return this->hasLoaded = this->matsurface; + auto PaintTraverseEx = matsurface->Original(Offsets::PaintTraverseEx); + this->StartDrawing = Memory::Read<_StartDrawing>(PaintTraverseEx + Offsets::StartDrawing); + this->FinishDrawing = Memory::Read<_FinishDrawing>(PaintTraverseEx + Offsets::FinishDrawing); } void Surface::Shutdown() { - Interface::Delete(this->matsurface); + Interface::Destroy(this->matsurface); } Surface* surface; diff --git a/src/Modules/Surface.hpp b/src/Modules/Surface.hpp index 26580582..65422729 100644 --- a/src/Modules/Surface.hpp +++ b/src/Modules/Surface.hpp @@ -46,9 +46,13 @@ class Surface : public Module { void DrawRect(Color clr, int x0, int y0, int x1, int y1); void DrawRectAndCenterTxt(Color clr, int x0, int y0, int x1, int y1, HFont font, Color fontClr, const char* fmt, ...); - bool Init() override; + Surface() + : Module(MODULE("vguimatsurface")) + { + } + + void Init() override; void Shutdown() override; - const char* Name() override { return MODULE("vguimatsurface"); } }; extern Surface* surface; diff --git a/src/Modules/Tier1.cpp b/src/Modules/Tier1.cpp index cfbf1d6c..8941ee17 100644 --- a/src/Modules/Tier1.cpp +++ b/src/Modules/Tier1.cpp @@ -1,64 +1,60 @@ #include "Tier1.hpp" +#include + #include "Game.hpp" #include "Interface.hpp" #include "Offsets.hpp" #include "SAR.hpp" #include "Utils.hpp" -bool Tier1::Init() +void Tier1::Init() { - this->g_pCVar = Interface::Create(this->Name(), "VEngineCvar0", false); - if (this->g_pCVar) { - this->RegisterConCommand = this->g_pCVar->Original<_RegisterConCommand>(Offsets::RegisterConCommand); - this->UnregisterConCommand = this->g_pCVar->Original<_UnregisterConCommand>(Offsets::UnregisterConCommand); - this->FindCommandBase = this->g_pCVar->Original<_FindCommandBase>(Offsets::FindCommandBase); + this->g_pCVar = Interface::CreateNew(this, "VEngineCvar0"); + + this->RegisterConCommand = this->g_pCVar->Original<_RegisterConCommand>(Offsets::RegisterConCommand); + this->UnregisterConCommand = this->g_pCVar->Original<_UnregisterConCommand>(Offsets::UnregisterConCommand); + this->FindCommandBase = this->g_pCVar->Original<_FindCommandBase>(Offsets::FindCommandBase); + + this->m_pConCommandList = reinterpret_cast((uintptr_t)this->g_pCVar->ThisPtr() + Offsets::m_pConCommandList); - this->m_pConCommandList = reinterpret_cast((uintptr_t)this->g_pCVar->ThisPtr() + Offsets::m_pConCommandList); + auto listdemo = reinterpret_cast(this->FindCommandBase(this->g_pCVar->ThisPtr(), "listdemo")); + if (!listdemo) { + throw std::runtime_error("listdemo command not found"); + } - auto listdemo = reinterpret_cast(this->FindCommandBase(this->g_pCVar->ThisPtr(), "listdemo")); - if (listdemo) { - this->ConCommand_VTable = listdemo->ConCommandBase_VTable; + this->ConCommand_VTable = listdemo->ConCommandBase_VTable; + auto callback = (uintptr_t)listdemo->m_fnCompletionCallback + Offsets::AutoCompletionFunc; + this->AutoCompletionFunc = Memory::Read<_AutoCompletionFunc>(callback); - if (listdemo->m_fnCompletionCallback) { - auto callback = (uintptr_t)listdemo->m_fnCompletionCallback + Offsets::AutoCompletionFunc; - this->AutoCompletionFunc = Memory::Read<_AutoCompletionFunc>(callback); - } - } + auto sv_lan = reinterpret_cast(this->FindCommandBase(this->g_pCVar->ThisPtr(), "sv_lan")); + if (!sv_lan) { + throw std::runtime_error("sv_lan convar not found"); + } - auto sv_lan = reinterpret_cast(this->FindCommandBase(this->g_pCVar->ThisPtr(), "sv_lan")); - if (sv_lan) { - this->ConVar_VTable = sv_lan->ConCommandBase_VTable; - this->ConVar_VTable2 = sv_lan->ConVar_VTable; + this->ConVar_VTable = sv_lan->ConCommandBase_VTable; + this->ConVar_VTable2 = sv_lan->ConVar_VTable; - auto vtable = + auto vtable = #ifdef _WIN32 - sar.game->Is(SourceGame_HalfLife2Engine) - ? &this->ConVar_VTable - : &this->ConVar_VTable2; + sar.game->Is(SourceGame_HalfLife2Engine) + ? &this->ConVar_VTable + : &this->ConVar_VTable2; #else - &this->ConVar_VTable; + &this->ConVar_VTable; #endif - this->Dtor = Memory::VMT<_Dtor>(vtable, Offsets::Dtor); - this->Create = Memory::VMT<_Create>(vtable, Offsets::Create); - } + this->Dtor = Memory::VMT<_Dtor>(vtable, Offsets::Dtor); + this->Create = Memory::VMT<_Create>(vtable, Offsets::Create); - if (sar.game->Is(SourceGame_Portal2 | SourceGame_ApertureTag)) { - this->InstallGlobalChangeCallback = this->g_pCVar->Original<_InstallGlobalChangeCallback>(Offsets::InstallGlobalChangeCallback); - this->RemoveGlobalChangeCallback = this->g_pCVar->Original<_RemoveGlobalChangeCallback>(Offsets::RemoveGlobalChangeCallback); - } + if (sar.game->Is(SourceGame_Portal2 | SourceGame_ApertureTag)) { + this->InstallGlobalChangeCallback = this->g_pCVar->Original<_InstallGlobalChangeCallback>(Offsets::InstallGlobalChangeCallback); + this->RemoveGlobalChangeCallback = this->g_pCVar->Original<_RemoveGlobalChangeCallback>(Offsets::RemoveGlobalChangeCallback); } - - return this->hasLoaded = this->g_pCVar - && this->ConCommand_VTable - && this->ConVar_VTable - && this->ConVar_VTable2 - && this->AutoCompletionFunc; } void Tier1::Shutdown() { - Interface::Delete(this->g_pCVar); + Interface::Destroy(this->g_pCVar); } Tier1* tier1; diff --git a/src/Modules/Tier1.hpp b/src/Modules/Tier1.hpp index 27038954..4c0cf158 100644 --- a/src/Modules/Tier1.hpp +++ b/src/Modules/Tier1.hpp @@ -39,9 +39,13 @@ class Tier1 : public Module { _Create Create = nullptr; public: - bool Init() override; + Tier1() + : Module(MODULE(TIER1)) + { + } + + void Init() override; void Shutdown() override; - const char* Name() override { return MODULE(TIER1); } }; extern Tier1* tier1; diff --git a/src/Modules/VGui.cpp b/src/Modules/VGui.cpp index c59dc9cf..c22d719c 100644 --- a/src/Modules/VGui.cpp +++ b/src/Modules/VGui.cpp @@ -1,5 +1,7 @@ #include "VGui.hpp" +#include + #include "Features/Hud/Hud.hpp" #include "Features/Session.hpp" #include "Features/Timer/PauseTimer.hpp" @@ -9,8 +11,6 @@ #include "SAR.hpp" -REDECL(VGui::Paint); - void VGui::Draw(Hud* const& hud) { if (hud->ShouldDraw()) { @@ -25,9 +25,9 @@ void VGui::Draw(HudElement* const& element) } // CEngineVGui::Paint -DETOUR(VGui::Paint, PaintMode_t mode) +DETOUR(Paint, PaintMode_t mode) { - auto result = VGui::Paint(thisptr, mode); + auto result = Paint(thisptr, mode); surface->StartDrawing(surface->matsurface->ThisPtr()); @@ -64,37 +64,34 @@ DETOUR(VGui::Paint, PaintMode_t mode) return result; } -bool VGui::Init() +void VGui::Init() { - this->enginevgui = Interface::Create(this->Name(), "VEngineVGui0"); - if (this->enginevgui) { - this->enginevgui->Hook(VGui::Paint_Hook, VGui::Paint, Offsets::Paint); + this->enginevgui = Interface::Hookable(this, "VEngineVGui0"); + this->enginevgui->Hook(&hkPaint, Offsets::Paint); - for (auto& hud : Hud::GetList()) { - if (hud->version == SourceGame_Unknown || sar.game->Is(hud->version)) { - this->huds.push_back(hud); - } + for (auto& hud : Hud::GetList()) { + if (hud->version == SourceGame_Unknown || sar.game->Is(hud->version)) { + this->huds.push_back(hud); } + } - HudElement::IndexAll(); + HudElement::IndexAll(); - for (auto const& element : HudElement::GetList()) { - if (element->version == SourceGame_Unknown || sar.game->Is(element->version)) { - this->elements.push_back(element); - } + for (auto const& element : HudElement::GetList()) { + if (element->version == SourceGame_Unknown || sar.game->Is(element->version)) { + this->elements.push_back(element); } - - std::sort(this->elements.begin(), this->elements.end(), [](const HudElement* a, const HudElement* b) { - return a->orderIndex < b->orderIndex; - }); } - return this->hasLoaded = this->enginevgui; + std::sort(this->elements.begin(), this->elements.end(), [](const HudElement* a, const HudElement* b) { + return a->orderIndex < b->orderIndex; + }); } void VGui::Shutdown() { - Interface::Delete(this->enginevgui); + Interface::Destroy(this->enginevgui); this->huds.clear(); + this->elements.clear(); } VGui* vgui; diff --git a/src/Modules/VGui.hpp b/src/Modules/VGui.hpp index 6342c00e..9cc3c78f 100644 --- a/src/Modules/VGui.hpp +++ b/src/Modules/VGui.hpp @@ -12,24 +12,22 @@ class VGui : public Module { public: Interface* enginevgui = nullptr; -private: HudContext context = HudContext(); std::vector huds = std::vector(); - -public: std::vector elements = std::vector(); -private: +public: void Draw(Hud* const& hud); void Draw(HudElement* const& element); -public: - // CEngineVGui::Paint - DECL_DETOUR(Paint, PaintMode_t mode); + VGui() + : Module(MODULE("engine")) + { + this->isHookable = true; + } - bool Init() override; + void Init() override; void Shutdown() override; - const char* Name() override { return MODULE("engine"); } }; extern VGui* vgui; diff --git a/src/Offsets.cpp b/src/Offsets.cpp index fb583fc0..cbcb061b 100644 --- a/src/Offsets.cpp +++ b/src/Offsets.cpp @@ -158,9 +158,6 @@ int IsRunningSimulation; // CIVDebugOverlay int ScreenPosition; -// CCommandBuffer -int m_bWaitEnabled; - // CServerTools int GetIServerEntity; diff --git a/src/Offsets.hpp b/src/Offsets.hpp index fc84558d..41c2c8d6 100644 --- a/src/Offsets.hpp +++ b/src/Offsets.hpp @@ -158,9 +158,6 @@ extern int IsRunningSimulation; // CIVDebugOverlay extern int ScreenPosition; -// CCommandBuffer -extern int m_bWaitEnabled; - // CServerTools extern int GetIServerEntity; diff --git a/src/SAR.cpp b/src/SAR.cpp index cb3e40c0..f21f986d 100644 --- a/src/SAR.cpp +++ b/src/SAR.cpp @@ -12,126 +12,158 @@ #include "Variable.hpp" SAR sar; -EXPOSE_SINGLE_INTERFACE_GLOBALVAR(SAR, IServerPluginCallbacks, INTERFACEVERSION_ISERVERPLUGINCALLBACKS, sar); +InterfaceReg __sar([]() -> void* { return &sar; }, INTERFACEVERSION_ISERVERPLUGINCALLBACKS); SAR::SAR() - : modules(new Modules()) + : vtable(pluginVtable) + , modules(new Modules()) , features(new Features()) , cheats(new Cheats()) , plugin(new Plugin()) , game(Game::CreateNew()) { } - -bool SAR::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) +bool SAR::Init() { console = new Console(); - if (!console->Init()) + if (!console->Load()) { return false; + } + + if (!this->game) { + console->Warning("SAR: Game not supported!\n"); + return false; + } + + if (game->Is(SourceGame_Portal2Engine)) { + this->vtable = pluginVtable2; + } - if (this->game) { - this->game->LoadOffsets(); + this->game->LoadOffsets(); + try { tier1 = new Tier1(); - if (tier1->Init()) { - this->features->AddFeature(&config); - this->features->AddFeature(&cvars); - this->features->AddFeature(&rebinder); - this->game->Is(SourceGame_INFRA) - ? this->features->AddFeature(reinterpret_cast(&session)) - : this->features->AddFeature(&session); - this->features->AddFeature(&stepCounter); - this->features->AddFeature(&summary); - this->features->AddFeature(&teleporter); - this->features->AddFeature(&tracer); - this->features->AddFeature(&speedrun); - this->features->AddFeature(&stats); - this->features->AddFeature(&cmdQueuer); - this->features->AddFeature(&replayRecorder1); - this->features->AddFeature(&replayRecorder2); - this->features->AddFeature(&replayPlayer1); - this->features->AddFeature(&replayPlayer2); - this->features->AddFeature(&replayProvider); - this->features->AddFeature(&timer); - this->features->AddFeature(&inspector); - this->features->AddFeature(&classDumper); - this->features->AddFeature(&entityList); - this->features->AddFeature(&offsetFinder); - this->features->AddFeature(&autoStrafer); - this->features->AddFeature(&pauseTimer); - this->features->AddFeature(&dataMapDumper); - this->features->AddFeature(&fovChanger); - - this->modules->AddModule(&inputSystem); - this->modules->AddModule(&scheme); - this->modules->AddModule(&surface); - this->modules->AddModule(&vgui); - this->modules->AddModule(&engine); - this->modules->AddModule(&client); - this->modules->AddModule(&server); - this->modules->InitAll(); - - if (engine && engine->hasLoaded) { - engine->demoplayer->Init(); - engine->demorecorder->Init(); - - this->cheats->Init(); - - this->features->AddFeature(&tasTools); - - if (this->game->Is(SourceGame_Portal2 | SourceGame_ApertureTag)) { - this->features->AddFeature(&listener); - this->features->AddFeature(&workshop); - this->features->AddFeature(&imitator); - } - - if (listener) { - listener->Init(); - } - - speedrun->LoadRules(this->game); - - config->Load(); - - this->SearchPlugin(); - - console->PrintActive("Loaded SourceAutoRecord, Version %s\n", SAR_VERSION); - return true; - } else { - console->Warning("SAR: Failed to load engine module!\n"); - } - } else { - console->Warning("SAR: Failed to load tier1 module!\n"); + tier1->Load(); + + this->features->AddFeature<>(&config); + this->features->AddFeature<>(&cvars); + this->features->AddFeature<>(&rebinder); + this->game->Is(SourceGame_INFRA) + ? this->features->AddFeature<>(reinterpret_cast(&session)) + : this->features->AddFeature<>(&session); + this->features->AddFeature<>(&stepCounter); + this->features->AddFeature<>(&summary); + this->features->AddFeature<>(&teleporter); + this->features->AddFeature<>(&tracer); + this->features->AddFeature<>(&speedrun); + this->features->AddFeature<>(&stats); + this->features->AddFeature<>(&cmdQueuer); + this->features->AddFeature<>(&replayRecorder1); + this->features->AddFeature<>(&replayRecorder2); + this->features->AddFeature<>(&replayPlayer1); + this->features->AddFeature<>(&replayPlayer2); + this->features->AddFeature<>(&replayProvider); + this->features->AddFeature<>(&timer); + this->features->AddFeature<>(&inspector); + this->features->AddFeature<>(&classDumper); + this->features->AddFeature<>(&entityList); + this->features->AddFeature<>(&offsetFinder); + this->features->AddFeature<>(&autoStrafer); + this->features->AddFeature<>(&pauseTimer); + this->features->AddFeature<>(&dataMapDumper); + this->features->AddFeature<>(&fovChanger); + + this->modules->AddModule<>(&inputSystem); + this->modules->AddModule<>(&scheme); + this->modules->AddModule<>(&surface); + this->modules->AddModule<>(&vgui); + this->modules->AddModule<>(&engine); + this->modules->AddModule<>(&demoplayer); + this->modules->AddModule<>(&demorecorder); + this->modules->AddModule<>(&client); + this->modules->AddModule<>(&server); + + this->modules->LoadAll(); + + this->cheats->Init(); + + this->features->AddFeature<>(&tasTools); + + if (this->game->Is(SourceGame_Portal2 | SourceGame_ApertureTag)) { + this->features->AddFeature<>(&listener); + this->features->AddFeature<>(&workshop); + this->features->AddFeature<>(&imitator); + } + + if (listener) { + listener->Init(); } - } else { - console->Warning("SAR: Game not supported!\n"); - } - console->Warning("SAR: Failed to load SourceAutoRecord!\n"); + speedrun->LoadRules(this->game); - if (sar.cheats) { - sar.cheats->Shutdown(); - } - if (sar.features) { - sar.features->DeleteAll(); + config->Load(); + + this->HookAll(); + + console->PrintActive("Loaded SourceAutoRecord, Version %s\n", SAR_VERSION); + } catch (std::exception& ex) { + console->Warning("SAR: %s\n", ex.what()); + return false; } - if (sar.modules) { - sar.modules->ShutdownAll(); + return true; +} +void SAR::HookAll() +{ + for (auto& mod : this->modules->list) { + if (mod->CanHook()) { + for (auto& interfaceHook : mod->interfaces) { + interfaceHook->EnableHooks(); + } + + for (auto& cmdHook : mod->cmdHooks) { + cmdHook->Hook(); + } + } else if (!mod->interfaces.empty()) { + console->Warning("SAR: Unable to hook functions in non-hookable module %s\n", mod->filename); + } } +} +void SAR::UnhookAll() +{ + for (auto& mod : this->modules->list) { + for (auto& interfaceHook : mod->interfaces) { + interfaceHook->DisableHooks(); + } - SAFE_DELETE(sar.features) - SAFE_DELETE(sar.cheats) - SAFE_DELETE(sar.modules) - SAFE_DELETE(sar.plugin) - SAFE_DELETE(sar.game) - SAFE_DELETE(tier1) - SAFE_DELETE(console) - return false; + for (auto& cmdHook : mod->cmdHooks) { + cmdHook->Unhook(); + } + } } +void SAR::Cleanup() +{ + if (this->modules) { + this->UnhookAll(); + } + if (this->cheats) { + this->cheats->Shutdown(); + } + if (this->features) { + this->features->DeleteAll(); + } + if (this->modules) { + this->modules->UnloadAll(); + } -// SAR has to disable itself in the plugin list or the game might crash because of missing callbacks -// This is a race condition though + sdelete(this->features); + sdelete(this->cheats); + sdelete(this->modules); + sdelete(this->plugin); + sdelete(this->game); + sdelete(tier1); + sdelete(console); +} bool SAR::GetPlugin() { auto s_ServerPlugin = reinterpret_cast(engine->s_ServerPlugin->ThisPtr()); @@ -149,29 +181,17 @@ bool SAR::GetPlugin() } return false; } -void SAR::SearchPlugin() -{ - this->findPluginThread = std::thread([this]() { - GO_THE_FUCK_TO_SLEEP(1000); - if (this->GetPlugin()) { - this->plugin->ptr->m_bDisable = true; - } else { - console->DevWarning("SAR: Failed to find SAR in the plugin list!\nTry again with \"plugin_load\".\n"); - } - }); - this->findPluginThread.detach(); -} CON_COMMAND(sar_session, "Prints the current tick of the server since it has loaded.\n") { auto tick = session->GetTick(); console->Print("Session Tick: %i (%.3f)\n", tick, engine->ToTime(tick)); - if (*engine->demorecorder->m_bRecording) { - tick = engine->demorecorder->GetTick(); + if (*demorecorder->m_bRecording) { + tick = demorecorder->GetTick(); console->Print("Demo Recorder Tick: %i (%.3f)\n", tick, engine->ToTime(tick)); } - if (engine->demoplayer->IsPlaying()) { - tick = engine->demoplayer->GetTick(); + if (demoplayer->IsPlaying()) { + tick = demoplayer->GetTick(); console->Print("Demo Player Tick: %i (%.3f)\n", tick, engine->ToTime(tick)); } } @@ -240,6 +260,8 @@ CON_COMMAND(sar_rename, "Changes your name. Usage: sar_rename \n") } CON_COMMAND(sar_exit, "Removes all function hooks, registered commands and unloads the module.\n") { + sar.UnhookAll(); + if (sar.cheats) { sar.cheats->Shutdown(); } @@ -254,84 +276,134 @@ CON_COMMAND(sar_exit, "Removes all function hooks, registered commands and unloa } if (sar.modules) { - sar.modules->ShutdownAll(); - } + sar.modules->UnloadAll(); + } - SAFE_DELETE(sar.features) - SAFE_DELETE(sar.cheats) - SAFE_DELETE(sar.modules) - SAFE_DELETE(sar.plugin) - SAFE_DELETE(sar.game) + sdelete(sar.features); + sdelete(sar.cheats); + sdelete(sar.modules); + sdelete(sar.plugin); + sdelete(sar.game); console->Print("Cya :)\n"); - SAFE_DELETE(tier1) - SAFE_DELETE(console) + sdelete(tier1); + sdelete(console); } -#pragma region Unused callbacks -void SAR::Unload() +VFUNC(bool, Load, CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) { + return sar.Init(); } -void SAR::Pause() +VFUNC(void, Unload) { + sar.Cleanup(); } -void SAR::UnPause() +VFUNC(void, Pause) { } -const char* SAR::GetPluginDescription() +VFUNC(void, UnPause) { - return SAR_PLUGIN_SIGNATURE; } -void SAR::LevelInit(char const* pMapName) +VFUNC(const char*, GetPluginDescription) { + return SAR_PLUGIN_SIGNATURE; } -void SAR::ServerActivate(void* pEdictList, int edictCount, int clientMax) +VFUNC(void, LevelInit, char const* pMapName) { } -void SAR::GameFrame(bool simulating) +VFUNC(void, ServerActivate, void* pEdictList, int edictCount, int clientMax) { } -void SAR::LevelShutdown() +VFUNC(void, GameFrame, bool simulating) { } -void SAR::ClientFullyConnect(void* pEdict) +VFUNC(void, LevelShutdown) { } -void SAR::ClientActive(void* pEntity) +VFUNC(void, ClientFullyConnect, void* pEdict) { } -void SAR::ClientDisconnect(void* pEntity) +VFUNC(void, ClientActive, void* pEntity) { } -void SAR::ClientPutInServer(void* pEntity, char const* playername) +VFUNC(void, ClientDisconnect, void* pEntity) { } -void SAR::SetCommandClient(int index) +VFUNC(void, ClientPutInServer, void* pEntity, char const* playername) { } -void SAR::ClientSettingsChanged(void* pEdict) +VFUNC(void, SetCommandClient, int index) { } -int SAR::ClientConnect(bool* bAllowConnect, void* pEntity, const char* pszName, const char* pszAddress, char* reject, int maxrejectlen) +VFUNC(void, ClientSettingsChanged, void* pEdict) { - return 0; } -int SAR::ClientCommand(void* pEntity, const void*& args) +VFUNC(int, ClientConnect, bool* bAllowConnect, void* pEntity, const char* pszName, const char* pszAddress, char* reject, int maxrejectlen) { return 0; } -int SAR::NetworkIDValidated(const char* pszUserName, const char* pszNetworkID) +VFUNC(int, ClientCommand, void* pEntity, const void*& args) { return 0; } -void SAR::OnQueryCvarValueFinished(int iCookie, void* pPlayerEntity, int eStatus, const char* pCvarName, const char* pCvarValue) -{ -} -void SAR::OnEdictAllocated(void* edict) -{ -} -void SAR::OnEdictFreed(const void* edict) +VFUNC(int, NetworkIDValidated, const char* pszUserName, const char* pszNetworkID) { + return 0; } -#pragma endregion +VFUNC(void, OnQueryCvarValueFinished, int iCookie, void* pPlayerEntity, int eStatus, const char* pCvarName, const char* pCvarValue) +{ +} +VFUNC(void, OnEdictAllocated, void* edict) +{ +} +VFUNC(void, OnEdictFreed, const void* edict) +{ +} + +void* SAR::pluginVtable[20] = { + (void*)Load, + (void*)Unload, + (void*)Pause, + (void*)UnPause, + (void*)GetPluginDescription, + (void*)LevelInit, + (void*)ServerActivate, + (void*)GameFrame, + (void*)LevelShutdown, + (void*)ClientActive, + (void*)ClientDisconnect, + (void*)ClientPutInServer, + (void*)SetCommandClient, + (void*)ClientSettingsChanged, + (void*)ClientConnect, + (void*)ClientCommand, + (void*)NetworkIDValidated, + (void*)OnQueryCvarValueFinished, + (void*)OnEdictAllocated, + (void*)OnEdictFreed, +}; + +void* SAR::pluginVtable2[21] = { + (void*)Load, + (void*)Unload, + (void*)Pause, + (void*)UnPause, + (void*)GetPluginDescription, + (void*)LevelInit, + (void*)ServerActivate, + (void*)GameFrame, + (void*)LevelShutdown, + (void*)ClientFullyConnect, + (void*)ClientActive, + (void*)ClientDisconnect, + (void*)ClientPutInServer, + (void*)SetCommandClient, + (void*)ClientSettingsChanged, + (void*)ClientConnect, + (void*)ClientCommand, + (void*)NetworkIDValidated, + (void*)OnQueryCvarValueFinished, + (void*)OnEdictAllocated, + (void*)OnEdictFreed, +}; diff --git a/src/SAR.hpp b/src/SAR.hpp index e98af8db..fb5ef161 100644 --- a/src/SAR.hpp +++ b/src/SAR.hpp @@ -19,7 +19,10 @@ #define SAFE_UNLOAD_TICK_DELAY 33 -class SAR : public IServerPluginCallbacks { +class SAR { +private: + void* vtable; + public: Modules* modules; Features* features; @@ -27,40 +30,21 @@ class SAR : public IServerPluginCallbacks { Plugin* plugin; Game* game; -private: - std::thread findPluginThread; - public: SAR(); - virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory); - virtual void Unload(); - virtual void Pause(); - virtual void UnPause(); - virtual const char* GetPluginDescription(); - virtual void LevelInit(char const* pMapName); - virtual void ServerActivate(void* pEdictList, int edictCount, int clientMax); - virtual void GameFrame(bool simulating); - virtual void LevelShutdown(); - virtual void ClientFullyConnect(void* pEdict); - virtual void ClientActive(void* pEntity); - virtual void ClientDisconnect(void* pEntity); - virtual void ClientPutInServer(void* pEntity, char const* playername); - virtual void SetCommandClient(int index); - virtual void ClientSettingsChanged(void* pEdict); - virtual int ClientConnect(bool* bAllowConnect, void* pEntity, const char* pszName, const char* pszAddress, char* reject, int maxrejectlen); - virtual int ClientCommand(void* pEntity, const void*& args); - virtual int NetworkIDValidated(const char* pszUserName, const char* pszNetworkID); - virtual void OnQueryCvarValueFinished(int iCookie, void* pPlayerEntity, int eStatus, const char* pCvarName, const char* pCvarValue); - virtual void OnEdictAllocated(void* edict); - virtual void OnEdictFreed(const void* edict); - inline const char* Version() { return SAR_VERSION; } inline const char* Build() { return SAR_BUILD; } inline const char* Website() { return SAR_WEB; } + bool Init(); + void HookAll(); + void UnhookAll(); + void Cleanup(); bool GetPlugin(); - void SearchPlugin(); + + static void* pluginVtable[20]; + static void* pluginVtable2[21]; }; extern SAR sar; diff --git a/src/SourceAutoRecord.vcxproj b/src/SourceAutoRecord.vcxproj index f6944ec0..c15386ec 100644 --- a/src/SourceAutoRecord.vcxproj +++ b/src/SourceAutoRecord.vcxproj @@ -20,7 +20,7 @@ DynamicLibrary false - v141 + v142 MultiByte false @@ -113,11 +113,6 @@ - - - - - @@ -250,14 +245,6 @@ - - - - - - - - @@ -396,9 +383,6 @@ - - - diff --git a/src/SourceAutoRecord.vcxproj.filters b/src/SourceAutoRecord.vcxproj.filters index 8099f56d..ab5ef2ea 100644 --- a/src/SourceAutoRecord.vcxproj.filters +++ b/src/SourceAutoRecord.vcxproj.filters @@ -1,21 +1,6 @@  - - lib\minhook - - - lib\minhook - - - lib\minhook - - - lib\minhook - - - lib\minhook - SourceAutoRecord\Features\Hud @@ -321,30 +306,6 @@ - - lib\minhook - - - lib\minhook - - - lib\minhook - - - lib\minhook - - - lib\minhook - - - lib\minhook - - - lib\minhook - - - lib\minhook - SourceAutoRecord\Utils @@ -683,12 +644,6 @@ {56b78df4-db1c-44a5-9243-10415ba45a25} - - {432c6e31-fbb9-4852-9bfd-74b0cc6d7a57} - - - {df38f6d3-7501-4e2a-ba0c-e8de7ad26787} - {9e7c58b4-0f87-483c-92ab-77f4d6757512} @@ -723,9 +678,4 @@ {6d5adac2-903e-463f-8055-8677eaca4662} - - - lib\minhook - - \ No newline at end of file diff --git a/src/Utils.hpp b/src/Utils.hpp index f9911bf0..4d7bfe04 100644 --- a/src/Utils.hpp +++ b/src/Utils.hpp @@ -18,13 +18,10 @@ bool StartsWith(const char* str, const char* subStr); bool ICompare(const std::string& a, const std::string& b); } -#define REDECL(name) \ - decltype(name) name - -#define SAFE_DELETE(ptr) \ - if (ptr) { \ - delete ptr; \ - ptr = nullptr; \ +#define sdelete(ptr) \ + if (ptr) { \ + delete ptr; \ + ptr = nullptr; \ } #if _WIN32 diff --git a/src/Utils/Math.hpp b/src/Utils/Math.hpp index 87f2bfe3..37f8c9c6 100644 --- a/src/Utils/Math.hpp +++ b/src/Utils/Math.hpp @@ -61,4 +61,4 @@ inline void Math::VectorCopy(const Vector& src, Vector& dst) dst.x = src.x; dst.y = src.y; dst.z = src.z; -} \ No newline at end of file +} diff --git a/src/Utils/Memory.cpp b/src/Utils/Memory.cpp index 1bb3ece9..91bd0e55 100644 --- a/src/Utils/Memory.cpp +++ b/src/Utils/Memory.cpp @@ -21,11 +21,11 @@ #define getBits(x) (INRANGE((x & (~0x20)), 'A', 'F') ? ((x & (~0x20)) - 'A' + 0xA) : (INRANGE(x, '0', '9') ? x - '0' : 0)) #define getByte(x) (getBits(x[0]) << 4 | getBits(x[1])) -std::vector Memory::moduleList; - bool Memory::TryGetModule(const char* moduleName, Memory::ModuleInfo* info) { - if (Memory::moduleList.empty()) { + static auto moduleList = std::vector(); + + if (moduleList.empty()) { #ifdef _WIN32 HMODULE hMods[1024]; HANDLE pHandle = GetCurrentProcess(); @@ -42,42 +42,42 @@ bool Memory::TryGetModule(const char* moduleName, Memory::ModuleInfo* info) continue; } - auto module = ModuleInfo(); + auto mod = ModuleInfo(); auto temp = std::string(buffer); auto index = temp.find_last_of("\\/"); temp = temp.substr(index + 1, temp.length() - index); - std::snprintf(module.name, sizeof(module.name), "%s", temp.c_str()); - module.base = (uintptr_t)modinfo.lpBaseOfDll; - module.size = (uintptr_t)modinfo.SizeOfImage; - std::snprintf(module.path, sizeof(module.path), "%s", buffer); + std::snprintf(mod.name, sizeof(mod.name), "%s", temp.c_str()); + mod.base = (uintptr_t)modinfo.lpBaseOfDll; + mod.size = (uintptr_t)modinfo.SizeOfImage; + std::snprintf(mod.path, sizeof(mod.path), "%s", buffer); - Memory::moduleList.push_back(module); + moduleList.push_back(mod); } } #else dl_iterate_phdr([](struct dl_phdr_info* info, size_t, void*) { - auto module = Memory::ModuleInfo(); + auto mod = Memory::ModuleInfo(); auto temp = std::string(info->dlpi_name); auto index = temp.find_last_of("\\/"); temp = temp.substr(index + 1, temp.length() - index); - std::snprintf(module.name, sizeof(module.name), "%s", temp.c_str()); + std::snprintf(mod.name, sizeof(mod.name), "%s", temp.c_str()); - module.base = info->dlpi_addr + info->dlpi_phdr[0].p_paddr; - module.size = info->dlpi_phdr[0].p_memsz; - std::strncpy(module.path, info->dlpi_name, sizeof(module.path)); + mod.base = info->dlpi_addr + info->dlpi_phdr[0].p_paddr; + mod.size = info->dlpi_phdr[0].p_memsz; + std::strncpy(mod.path, info->dlpi_name, sizeof(mod.path)); - Memory::moduleList.push_back(module); + moduleList.push_back(mod); return 0; }, nullptr); #endif } - for (Memory::ModuleInfo& item : Memory::moduleList) { + for (Memory::ModuleInfo& item : moduleList) { if (!std::strcmp(item.name, moduleName)) { if (info) { *info = item; @@ -180,7 +180,7 @@ std::vector Memory::MultiScan(const char* moduleName, const char* pat auto end = start + info.size; auto addr = uintptr_t(); while (true) { - auto addr = Memory::FindAddress(start, end, pattern); + addr = Memory::FindAddress(start, end, pattern); if (addr) { result.push_back(addr + offset); start = addr + length; @@ -239,57 +239,3 @@ std::vector> Memory::MultiScan(const char* moduleName, co } return results; } - -#ifdef _WIN32 -Memory::Patch::~Patch() -{ - if (this->original) { - this->Restore(); - delete this->original; - this->original = nullptr; - } -} -bool Memory::Patch::Execute(uintptr_t location, unsigned char* bytes) -{ - this->location = location; - this->size = sizeof(bytes) / sizeof(bytes[0]) - 1; - this->original = new unsigned char[this->size]; - - for (size_t i = 0; i < this->size; ++i) { - if (!ReadProcessMemory(GetCurrentProcess(), - reinterpret_cast(this->location + i), - &this->original[i], - 1, - 0)) { - return false; - } - } - - for (size_t i = 0; i < this->size; ++i) { - if (!WriteProcessMemory(GetCurrentProcess(), - reinterpret_cast(this->location + i), - &bytes[i], - 1, - 0)) { - return false; - } - } - 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; - } - } - return true; - } - return false; -} -#endif diff --git a/src/Utils/Memory.hpp b/src/Utils/Memory.hpp index b51f5667..bddc29c8 100644 --- a/src/Utils/Memory.hpp +++ b/src/Utils/Memory.hpp @@ -19,8 +19,6 @@ struct ModuleInfo { char path[MAX_PATH]; }; -extern std::vector moduleList; - bool TryGetModule(const char* moduleName, ModuleInfo* info); const char* GetModulePath(const char* moduleName); void* GetModuleHandleByName(const char* moduleName); @@ -31,20 +29,6 @@ uintptr_t FindAddress(const uintptr_t start, const uintptr_t end, const char* ta 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; - size_t size; - -public: - ~Patch(); - bool Execute(uintptr_t location, unsigned char* bytes); - bool Restore(); -}; -#endif - struct Pattern { const char* signature; std::vector offsets; @@ -53,18 +37,21 @@ struct Pattern { typedef std::vector Offset; typedef std::vector Patterns; -#define PATTERN(name, sig, ...) Memory::Pattern name { sig, Memory::Offset({ __VA_ARGS__ }) } +#define PATTERN(name, sig, ...) \ + Memory::Pattern name { sig, Memory::Offset({ __VA_ARGS__ }) } #define PATTERNS(name, ...) Memory::Patterns name({ __VA_ARGS__ }) std::vector Scan(const char* moduleName, const Pattern* pattern); std::vector> MultiScan(const char* moduleName, const Patterns* patterns); +#ifdef _DEBUG template T Absolute(const char* moduleName, int relative) { auto info = Memory::ModuleInfo(); return (Memory::TryGetModule(moduleName, &info)) ? (T)(info.base + relative) : (T)0; } +#endif template T GetSymbolAddress(void* moduleHandle, const char* symbolName) { diff --git a/src/Utils/Platform.hpp b/src/Utils/Platform.hpp index 7e314dbe..e4a3861f 100644 --- a/src/Utils/Platform.hpp +++ b/src/Utils/Platform.hpp @@ -1,7 +1,4 @@ #pragma once -#ifdef _WIN32 -#include "minhook/MinHook.h" -#endif #define _GAME_PATH(x) #x @@ -12,66 +9,35 @@ // clang-format on #define __rescall __thiscall #define DLL_EXPORT extern "C" __declspec(dllexport) +#define SEEK_DIR_CUR std::ios_base::_Seekdir::_Seekcur +#define VFUNC(type, name, ...) type __fastcall name(void* thisptr, int edx, ##__VA_ARGS__) -#define DECL_DETOUR(name, ...) \ - using _##name = int(__rescall*)(void* thisptr, ##__VA_ARGS__); \ - static _##name name; \ - static int __fastcall name##_Hook(void* thisptr, int edx, ##__VA_ARGS__) -#define DECL_DETOUR_T(type, name, ...) \ - using _##name = type(__rescall*)(void* thisptr, ##__VA_ARGS__); \ - static _##name name; \ - static type __fastcall name##_Hook(void* thisptr, int edx, ##__VA_ARGS__) -#define DECL_DETOUR_B(name, ...) \ - using _##name = int(__rescall*)(void* thisptr, ##__VA_ARGS__); \ - static _##name name; \ - static _##name name##Base; \ - static int __fastcall name##_Hook(void* thisptr, int edx, ##__VA_ARGS__) - -#define DETOUR(name, ...) \ +#define DETOUR(name, ...) \ + using _##name = int(__thiscall*)(void* thisptr, ##__VA_ARGS__); \ + _##name name; \ + int __fastcall name##_Hook(void* thisptr, int edx, ##__VA_ARGS__); \ + VHook hk##name(reinterpret_cast(&name), reinterpret_cast(name##_Hook)); \ int __fastcall name##_Hook(void* thisptr, int edx, ##__VA_ARGS__) -#define DETOUR_T(type, name, ...) \ +#define DETOUR_T(type, name, ...) \ + using _##name = type(__thiscall*)(void* thisptr, ##__VA_ARGS__); \ + _##name name; \ + type __fastcall name##_Hook(void* thisptr, int edx, ##__VA_ARGS__); \ + VHook hk##name(reinterpret_cast(&name), reinterpret_cast(name##_Hook)); \ type __fastcall name##_Hook(void* thisptr, int edx, ##__VA_ARGS__) -#define DETOUR_B(name, ...) \ +#define DETOUR_B(name, ...) \ + using _##name = int(__thiscall*)(void* thisptr, ##__VA_ARGS__); \ + _##name name; \ + _##name name##Base; \ + int __fastcall name##_Hook(void* thisptr, int edx, ##__VA_ARGS__); \ + VHook hk##name(reinterpret_cast(&name), reinterpret_cast(name##_Hook)); \ int __fastcall name##_Hook(void* thisptr, int edx, ##__VA_ARGS__) - -namespace { -bool mhInitialized = false; -} -#define MH_HOOK(name, target) \ - if (!mhInitialized) { \ - MH_Initialize(); \ - mhInitialized = true; \ - } \ - name = reinterpret_cast(target); \ - MH_CreateHook(reinterpret_cast(target), name##_Hook, reinterpret_cast(&name##_Trampoline)); \ - MH_EnableHook(reinterpret_cast(target)); -#define MH_HOOK_MID(name, target) \ - if (!mhInitialized) { \ - MH_Initialize(); \ - mhInitialized = true; \ - } \ - name = target; \ - MH_CreateHook(reinterpret_cast(name), name##_Hook, reinterpret_cast(&name##_Trampoline)); \ - MH_EnableHook(reinterpret_cast(name)); -#define MH_UNHOOK(name) \ - if (name) { \ - MH_DisableHook(reinterpret_cast(name)); \ - MH_RemoveHook(reinterpret_cast(name)); \ - } -#define DECL_DETOUR_MID_MH(name) \ - static uintptr_t name; \ - static uintptr_t name##_Trampoline; \ - static void name##_Hook() -#define DECL_DETOUR_MH(name, ...) \ - using _##name = int(__thiscall*)(void* thisptr, __VA_ARGS__); \ - static _##name name; \ - static _##name name##_Trampoline; \ - static int __fastcall name##_Hook(void* thisptr, int edx, __VA_ARGS__) - -#define DETOUR_MID_MH(name) \ - __declspec(naked) void name##_Hook() -#define DETOUR_MH(name, ...) \ - int __fastcall name##_Hook(void* thisptr, int edx, __VA_ARGS__) +#define DETOUR_BT(type, name, ...) \ + using _##name = type(__thiscall*)(void* thisptr, ##__VA_ARGS__); \ + _##name name; \ + _##name name##Base; \ + type __fastcall name##_Hook(void* thisptr, int edx, ##__VA_ARGS__); \ + VHook hk##name(reinterpret_cast(&name), reinterpret_cast(name##_Hook)); \ + type __fastcall name##_Hook(void* thisptr, int edx, ##__VA_ARGS__) #else #define MODULE_EXTENSION ".so" // clang-format off @@ -82,32 +48,51 @@ bool mhInitialized = false; #define __stdcall __attribute__((__stdcall__)) #define __fastcall __attribute__((__fastcall__)) #define DLL_EXPORT extern "C" __attribute__((visibility("default"))) +#define SEEK_DIR_CUR std::ios_base::seekdir::_S_cur +#define VFUNC(type, name, ...) type __cdecl name(void* thisptr, ##__VA_ARGS__) -#define DECL_DETOUR(name, ...) \ - using _##name = int(__rescall*)(void* thisptr, ##__VA_ARGS__); \ - static _##name name; \ - static int __rescall name##_Hook(void* thisptr, ##__VA_ARGS__) -#define DECL_DETOUR_T(type, name, ...) \ - using _##name = type(__rescall*)(void* thisptr, ##__VA_ARGS__); \ - static _##name name; \ - static type __rescall name##_Hook(void* thisptr, ##__VA_ARGS__) -#define DECL_DETOUR_B(name, ...) \ - using _##name = int(__rescall*)(void* thisptr, ##__VA_ARGS__); \ - static _##name name; \ - static _##name name##Base; \ - static int __rescall name##_Hook(void* thisptr, ##__VA_ARGS__) - -#define DETOUR(name, ...) \ - int __rescall name##_Hook(void* thisptr, ##__VA_ARGS__) -#define DETOUR_T(type, name, ...) \ - type __rescall name##_Hook(void* thisptr, ##__VA_ARGS__) -#define DETOUR_B(name, ...) \ - int __rescall name##_Hook(void* thisptr, ##__VA_ARGS__) +#define DETOUR(name, ...) \ + using _##name = int(__cdecl*)(void* thisptr, ##__VA_ARGS__); \ + _##name name; \ + int __cdecl name##_Hook(void* thisptr, ##__VA_ARGS__); \ + VHook hk##name(reinterpret_cast(&name), reinterpret_cast(name##_Hook)); \ + int __cdecl name##_Hook(void* thisptr, ##__VA_ARGS__) +#define DETOUR_T(type, name, ...) \ + using _##name = type(__cdecl*)(void* thisptr, ##__VA_ARGS__); \ + _##name name; \ + type __cdecl name##_Hook(void* thisptr, ##__VA_ARGS__); \ + VHook hk##name(reinterpret_cast(&name), reinterpret_cast(name##_Hook)); \ + type __cdecl name##_Hook(void* thisptr, ##__VA_ARGS__) +#define DETOUR_B(name, ...) \ + using _##name = int(__cdecl*)(void* thisptr, ##__VA_ARGS__); \ + _##name name; \ + _##name name##Base; \ + int __cdecl name##_Hook(void* thisptr, ##__VA_ARGS__); \ + VHook hk##name(reinterpret_cast(&name), reinterpret_cast(name##_Hook)); \ + int __cdecl name##_Hook(void* thisptr, ##__VA_ARGS__) +#define DETOUR_BT(type, name, ...) \ + using _##name = type(__cdecl*)(void* thisptr, ##__VA_ARGS__); \ + _##name name; \ + _##name name##Base; \ + type __cdecl name##_Hook(void* thisptr, ##__VA_ARGS__); \ + VHook hk##name(reinterpret_cast(&name), reinterpret_cast(name##_Hook)); \ + type __cdecl name##_Hook(void* thisptr, ##__VA_ARGS__) #endif -#define DECL_DETOUR_STD(type, name, ...) \ - using _##name = type(__stdcall*)(##__VA_ARGS__); \ - static _##name name; \ - static type __stdcall name##_Hook(##__VA_ARGS__) -#define DETOUR_STD(type, name, ...) \ +#define DETOUR_STD(type, name, ...) \ + using _##name = type(__stdcall*)(##__VA_ARGS__); \ + _##name name; \ + type __stdcall name##_Hook(##__VA_ARGS__); \ + VHook hk##name(reinterpret_cast(&name), reinterpret_cast(name##_Hook)); \ type __stdcall name##_Hook(##__VA_ARGS__) + +struct VHook { + uintptr_t* original; + uintptr_t detour; + + VHook(uintptr_t* original, uintptr_t detour) + : original(original) + , detour(detour) + { + } +}; diff --git a/src/Utils/SDK.cpp b/src/Utils/SDK.cpp index d08a188a..84df95e4 100644 --- a/src/Utils/SDK.cpp +++ b/src/Utils/SDK.cpp @@ -2,8 +2,8 @@ #include -#include "Modules/Server.hpp" #include "Modules/Engine.hpp" +#include "Modules/Server.hpp" #include "Platform.hpp" @@ -41,7 +41,7 @@ kbutton_t::Split_t& kbutton_t::GetPerUser(int nSlot) return m_PerUser[nSlot]; } -inline int ENTINDEX(edict_t *pEdict) +inline int ENTINDEX(edict_t* pEdict) { return (pEdict) ? pEdict - server->gpGlobals->pEdicts : 0; } diff --git a/src/Utils/SDK.hpp b/src/Utils/SDK.hpp index b5d84bda..43c99e93 100644 --- a/src/Utils/SDK.hpp +++ b/src/Utils/SDK.hpp @@ -2,6 +2,7 @@ #pragma warning(suppress : 26495) #include #include +#include #ifdef _WIN32 #define __rescalll __thiscall @@ -47,9 +48,9 @@ struct Vector { { return ((float*)this)[i]; } - static inline float DotProduct(const Vector& a, const Vector& b) + static inline float DotProduct(const Vector& a, const Vector& b) { - return a.x*b.x + a.y*b.y + a.z*b.z; + return a.x * b.x + a.y * b.y + a.z * b.z; } }; @@ -84,6 +85,854 @@ struct Color { unsigned char _color[4] = { 0, 0, 0, 0 }; }; +#pragma region CUTL_VEC +#define Q_ARRAYSIZE(p) (sizeof(p) / sizeof(p[0])) + +#define Assert(a) ((void)0) +#define UTLMEMORY_TRACK_ALLOC() ((void)0) +#define UTLMEMORY_TRACK_FREE() ((void)0) +#define MEM_ALLOC_CREDIT_CLASS() ((void)0) + +template +inline void Construct(T* pMemory) +{ + ::new (pMemory) T; +} +template +inline void CopyConstruct(T* pMemory, T const& src) +{ + ::new (pMemory) T(src); +} +template +inline void Destruct(T* pMemory) +{ + pMemory->~T(); +} + +template +class CUtlMemory { +public: + CUtlMemory(int nGrowSize = 0, int nInitSize = 0); + CUtlMemory(T* pMemory, int numElements); + CUtlMemory(const T* pMemory, int numElements); + ~CUtlMemory(); + void Init(int nGrowSize = 0, int nInitSize = 0); + + class Iterator_t { + public: + Iterator_t(I i) + : index(i) + { + } + I index; + + bool operator==(const Iterator_t it) const { return index == it.index; } + bool operator!=(const Iterator_t it) const { return index != it.index; } + }; + + Iterator_t First() const { return Iterator_t(IsIdxValid(0) ? 0 : InvalidIndex()); } + Iterator_t Next(const Iterator_t& it) const { return Iterator_t(IsIdxValid(it.index + 1) ? it.index + 1 : InvalidIndex()); } + I GetIndex(const Iterator_t& it) const { return it.index; } + bool IsIdxAfter(I i, const Iterator_t& it) const { return i > it.index; } + bool IsValidIterator(const Iterator_t& it) const { return IsIdxValid(it.index); } + Iterator_t InvalidIterator() const { return Iterator_t(InvalidIndex()); } + T& operator[](I i); + const T& operator[](I i) const; + T& Element(I i); + const T& Element(I i) const; + bool IsIdxValid(I i) const; + static I InvalidIndex() { return (I)-1; } + T* Base(); + const T* Base() const; + void SetExternalBuffer(T* pMemory, int numElements); + void SetExternalBuffer(const T* pMemory, int numElements); + void AssumeMemory(T* pMemory, int nSize); + void Swap(CUtlMemory& mem); + void ConvertToGrowableMemory(int nGrowSize); + int NumAllocated() const; + int Count() const; + void Grow(int num = 1); + void EnsureCapacity(int num); + void Purge(); + void Purge(int numElements); + bool IsExternallyAllocated() const; + bool IsReadOnly() const; + void SetGrowSize(int size); + +public: + void ValidateGrowSize() + { + } + + enum { + EXTERNAL_BUFFER_MARKER = -1, + EXTERNAL_CONST_BUFFER_MARKER = -2, + }; + + T* m_pMemory; + int m_nAllocationCount; + int m_nGrowSize; +}; + +template > +class CUtlVector { + typedef A CAllocator; + +public: + typedef T ElemType_t; + + CUtlVector(int growSize = 0, int initSize = 0); + CUtlVector(T* pMemory, int allocationCount, int numElements = 0); + ~CUtlVector(); + CUtlVector& operator=(const CUtlVector& other); + T& operator[](int i); + const T& operator[](int i) const; + T& Element(int i); + const T& Element(int i) const; + T& Head(); + const T& Head() const; + T& Tail(); + const T& Tail() const; + T* Base() { return m_Memory.Base(); } + const T* Base() const { return m_Memory.Base(); } + int Count() const; + int Size() const; + bool IsValidIndex(int i) const; + static int InvalidIndex(); + int AddToHead(); + int AddToTail(); + int InsertBefore(int elem); + int InsertAfter(int elem); + int AddToHead(const T& src); + int AddToTail(const T& src); + int InsertBefore(int elem, const T& src); + int InsertAfter(int elem, const T& src); + int AddMultipleToHead(int num); + int AddMultipleToTail(int num, const T* pToCopy = NULL); + int InsertMultipleBefore(int elem, int num, const T* pToCopy = NULL); + int InsertMultipleAfter(int elem, int num); + void SetSize(int size); + void SetCount(int count); + void CopyArray(const T* pArray, int size); + void Swap(CUtlVector& vec); + int AddVectorToTail(CUtlVector const& src); + int Find(const T& src) const; + bool HasElement(const T& src) const; + void EnsureCapacity(int num); + void EnsureCount(int num); + void FastRemove(int elem); + void Remove(int elem); + bool FindAndRemove(const T& src); + void RemoveMultiple(int elem, int num); + void RemoveAll(); + void Purge(); + void PurgeAndDeleteElements(); + void Compact(); + void SetGrowSize(int size) { m_Memory.SetGrowSize(size); } + int NumAllocated() const; + void Sort(int(__rescalll* pfnCompare)(const T*, const T*)); + +public: + //CUtlVector(CUtlVector const& vec) { Assert(0); } + void GrowVector(int num = 1); + void ShiftElementsRight(int elem, int num = 1); + void ShiftElementsLeft(int elem, int num = 1); + + CAllocator m_Memory; + int m_Size; + T* m_pElements; + + inline void ResetDbgInfo() { m_pElements = Base(); } +}; + +template +inline CUtlVector::CUtlVector(int growSize, int initSize) + : m_Memory(growSize, initSize) + , m_Size(0) +{ + ResetDbgInfo(); +} +template +inline CUtlVector::CUtlVector(T* pMemory, int allocationCount, int numElements) + : m_Memory(pMemory, allocationCount) + , m_Size(numElements) +{ + ResetDbgInfo(); +} +template +inline CUtlVector::~CUtlVector() +{ + Purge(); +} +template +inline CUtlVector& CUtlVector::operator=(const CUtlVector& other) +{ + int nCount = other.Count(); + SetSize(nCount); + for (int i = 0; i < nCount; i++) { + (*this)[i] = other[i]; + } + return *this; +} +template +inline T& CUtlVector::operator[](int i) +{ + return m_Memory[i]; +} +template +inline const T& CUtlVector::operator[](int i) const +{ + return m_Memory[i]; +} +template +inline T& CUtlVector::Element(int i) +{ + return m_Memory[i]; +} +template +inline const T& CUtlVector::Element(int i) const +{ + return m_Memory[i]; +} +template +inline T& CUtlVector::Head() +{ + Assert(m_Size > 0); + return m_Memory[0]; +} +template +inline const T& CUtlVector::Head() const +{ + Assert(m_Size > 0); + return m_Memory[0]; +} +template +inline T& CUtlVector::Tail() +{ + Assert(m_Size > 0); + return m_Memory[m_Size - 1]; +} +template +inline const T& CUtlVector::Tail() const +{ + Assert(m_Size > 0); + return m_Memory[m_Size - 1]; +} +template +inline int CUtlVector::Size() const +{ + return m_Size; +} +template +inline int CUtlVector::Count() const +{ + return m_Size; +} +template +inline bool CUtlVector::IsValidIndex(int i) const +{ + return (i >= 0) && (i < m_Size); +} +template +inline int CUtlVector::InvalidIndex() +{ + return -1; +} +template +void CUtlVector::GrowVector(int num) +{ + if (m_Size + num > m_Memory.NumAllocated()) { + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.Grow(m_Size + num - m_Memory.NumAllocated()); + } + + m_Size += num; + ResetDbgInfo(); +} +template +void CUtlVector::Sort(int(__rescalll* pfnCompare)(const T*, const T*)) +{ + typedef int(__rescalll * QSortCompareFunc_t)(const void*, const void*); + if (Count() <= 1) + return; + + if (Base()) { + qsort(Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare)); + } else { + Assert(0); + + for (int i = m_Size - 1; i >= 0; --i) { + for (int j = 1; j <= i; ++j) { + if (pfnCompare(&Element(j - 1), &Element(j)) < 0) { + std::swap(Element(j - 1), Element(j)); + } + } + } + } +} +template +void CUtlVector::EnsureCapacity(int num) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} +template +void CUtlVector::EnsureCount(int num) +{ + if (Count() < num) + AddMultipleToTail(num - Count()); +} +template +void CUtlVector::ShiftElementsRight(int elem, int num) +{ + Assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + memmove(&Element(elem + num), &Element(elem), numToMove * sizeof(T)); +} +template +void CUtlVector::ShiftElementsLeft(int elem, int num) +{ + Assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) { + memmove(&Element(elem), &Element(elem + num), numToMove * sizeof(T)); + } +} +template +inline int CUtlVector::AddToHead() +{ + return InsertBefore(0); +} +template +inline int CUtlVector::AddToTail() +{ + return InsertBefore(m_Size); +} +template +inline int CUtlVector::InsertAfter(int elem) +{ + return InsertBefore(elem + 1); +} +template +int CUtlVector::InsertBefore(int elem) +{ + Assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(); + ShiftElementsRight(elem); + Construct(&Element(elem)); + return elem; +} +template +inline int CUtlVector::AddToHead(const T& src) +{ + Assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + return InsertBefore(0, src); +} +template +inline int CUtlVector::AddToTail(const T& src) +{ + Assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + return InsertBefore(m_Size, src); +} +template +inline int CUtlVector::InsertAfter(int elem, const T& src) +{ + Assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + return InsertBefore(elem + 1, src); +} +template +int CUtlVector::InsertBefore(int elem, const T& src) +{ + Assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + + Assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(); + ShiftElementsRight(elem); + CopyConstruct(&Element(elem), src); + return elem; +} +template +inline int CUtlVector::AddMultipleToHead(int num) +{ + return InsertMultipleBefore(0, num); +} +template +inline int CUtlVector::AddMultipleToTail(int num, const T* pToCopy) +{ + Assert((Base() == NULL) || !pToCopy || (pToCopy + num < Base()) || (pToCopy >= (Base() + Count()))); + + return InsertMultipleBefore(m_Size, num, pToCopy); +} +template +int CUtlVector::InsertMultipleAfter(int elem, int num) +{ + return InsertMultipleBefore(elem + 1, num); +} +template +void CUtlVector::SetCount(int count) +{ + RemoveAll(); + AddMultipleToTail(count); +} +template +inline void CUtlVector::SetSize(int size) +{ + SetCount(size); +} +template +void CUtlVector::CopyArray(const T* pArray, int size) +{ + Assert((Base() == NULL) || !pArray || (Base() >= (pArray + size)) || (pArray >= (Base() + Count()))); + + SetSize(size); + for (int i = 0; i < size; i++) { + (*this)[i] = pArray[i]; + } +} +template +void CUtlVector::Swap(CUtlVector& vec) +{ + m_Memory.Swap(vec.m_Memory); + std::swap(m_Size, vec.m_Size); + std::swap(m_pElements, vec.m_pElements); +} +template +int CUtlVector::AddVectorToTail(CUtlVector const& src) +{ + Assert(&src != this); + + int base = Count(); + + AddMultipleToTail(src.Count()); + + for (int i = 0; i < src.Count(); i++) { + (*this)[base + i] = src[i]; + } + + return base; +} +template +inline int CUtlVector::InsertMultipleBefore(int elem, int num, const T* pToInsert) +{ + if (num == 0) + return elem; + + Assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(num); + ShiftElementsRight(elem, num); + + for (int i = 0; i < num; ++i) + Construct(&Element(elem + i)); + + if (pToInsert) { + for (int i = 0; i < num; i++) { + Element(elem + i) = pToInsert[i]; + } + } + + return elem; +} +template +int CUtlVector::Find(const T& src) const +{ + for (int i = 0; i < Count(); ++i) { + if (Element(i) == src) + return i; + } + return -1; +} +template +bool CUtlVector::HasElement(const T& src) const +{ + return (Find(src) >= 0); +} +template +void CUtlVector::FastRemove(int elem) +{ + Assert(IsValidIndex(elem)); + + Destruct(&Element(elem)); + if (m_Size > 0) { + memcpy(&Element(elem), &Element(m_Size - 1), sizeof(T)); + --m_Size; + } +} +template +void CUtlVector::Remove(int elem) +{ + Destruct(&Element(elem)); + ShiftElementsLeft(elem); + --m_Size; +} +template +bool CUtlVector::FindAndRemove(const T& src) +{ + int elem = Find(src); + if (elem != -1) { + Remove(elem); + return true; + } + return false; +} +template +void CUtlVector::RemoveMultiple(int elem, int num) +{ + Assert(elem >= 0); + Assert(elem + num <= Count()); + + for (int i = elem + num; --i >= elem;) + Destruct(&Element(i)); + + ShiftElementsLeft(elem, num); + m_Size -= num; +} +template +void CUtlVector::RemoveAll() +{ + for (int i = m_Size; --i >= 0;) { + Destruct(&Element(i)); + } + + m_Size = 0; +} +template +inline void CUtlVector::Purge() +{ + RemoveAll(); + m_Memory.Purge(); + ResetDbgInfo(); +} +template +inline void CUtlVector::PurgeAndDeleteElements() +{ + for (int i = 0; i < m_Size; i++) { + delete Element(i); + } + Purge(); +} +template +inline void CUtlVector::Compact() +{ + m_Memory.Purge(m_Size); +} +template +inline int CUtlVector::NumAllocated() const +{ + return m_Memory.NumAllocated(); +} + +template +CUtlMemory::CUtlMemory(int nGrowSize, int nInitAllocationCount) + : m_pMemory(0) + , m_nAllocationCount(nInitAllocationCount) + , m_nGrowSize(nGrowSize) +{ + ValidateGrowSize(); + Assert(nGrowSize >= 0); + if (m_nAllocationCount) { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} +template +CUtlMemory::CUtlMemory(T* pMemory, int numElements) + : m_pMemory(pMemory) + , m_nAllocationCount(numElements) +{ + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} +template +CUtlMemory::CUtlMemory(const T* pMemory, int numElements) + : m_pMemory((T*)pMemory) + , m_nAllocationCount(numElements) +{ + m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; +} +template +CUtlMemory::~CUtlMemory() +{ + Purge(); +} +template +void CUtlMemory::Init(int nGrowSize /*= 0*/, int nInitSize /*= 0*/) +{ + Purge(); + + m_nGrowSize = nGrowSize; + m_nAllocationCount = nInitSize; + ValidateGrowSize(); + Assert(nGrowSize >= 0); + if (m_nAllocationCount) { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} +template +void CUtlMemory::Swap(CUtlMemory& mem) +{ + std::swap(m_nGrowSize, mem.m_nGrowSize); + std::swap(m_pMemory, mem.m_pMemory); + std::swap(m_nAllocationCount, mem.m_nAllocationCount); +} +template +void CUtlMemory::ConvertToGrowableMemory(int nGrowSize) +{ + if (!IsExternallyAllocated()) + return; + + m_nGrowSize = nGrowSize; + if (m_nAllocationCount) { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + + int nNumBytes = m_nAllocationCount * sizeof(T); + T* pMemory = (T*)malloc(nNumBytes); + memcpy(pMemory, m_pMemory, nNumBytes); + m_pMemory = pMemory; + } else { + m_pMemory = NULL; + } +} +template +void CUtlMemory::SetExternalBuffer(T* pMemory, int numElements) +{ + Purge(); + + m_pMemory = pMemory; + m_nAllocationCount = numElements; + + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template +void CUtlMemory::SetExternalBuffer(const T* pMemory, int numElements) +{ + Purge(); + + m_pMemory = const_cast(pMemory); + m_nAllocationCount = numElements; + + m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; +} +template +void CUtlMemory::AssumeMemory(T* pMemory, int numElements) +{ + Purge(); + + m_pMemory = pMemory; + m_nAllocationCount = numElements; +} +template +inline T& CUtlMemory::operator[](I i) +{ + Assert(!IsReadOnly()); + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} +template +inline const T& CUtlMemory::operator[](I i) const +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} +template +inline T& CUtlMemory::Element(I i) +{ + Assert(!IsReadOnly()); + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} +template +inline const T& CUtlMemory::Element(I i) const +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} +template +bool CUtlMemory::IsExternallyAllocated() const +{ + return (m_nGrowSize < 0); +} +template +bool CUtlMemory::IsReadOnly() const +{ + return (m_nGrowSize == EXTERNAL_CONST_BUFFER_MARKER); +} +template +void CUtlMemory::SetGrowSize(int nSize) +{ + Assert(!IsExternallyAllocated()); + Assert(nSize >= 0); + m_nGrowSize = nSize; + ValidateGrowSize(); +} +template +inline T* CUtlMemory::Base() +{ + Assert(!IsReadOnly()); + return m_pMemory; +} +template +inline const T* CUtlMemory::Base() const +{ + return m_pMemory; +} +template +inline int CUtlMemory::NumAllocated() const +{ + return m_nAllocationCount; +} +template +inline int CUtlMemory::Count() const +{ + return m_nAllocationCount; +} +template +inline bool CUtlMemory::IsIdxValid(I i) const +{ + return (((int)i) >= 0) && (((int)i) < m_nAllocationCount); +} +inline int UtlMemory_CalcNewAllocationCount(int nAllocationCount, int nGrowSize, int nNewSize, int nBytesItem) +{ + if (nGrowSize) { + nAllocationCount = ((1 + ((nNewSize - 1) / nGrowSize)) * nGrowSize); + } else { + if (!nAllocationCount) { + nAllocationCount = (31 + nBytesItem) / nBytesItem; + } + + while (nAllocationCount < nNewSize) { + nAllocationCount *= 2; + } + } + + return nAllocationCount; +} +template +void CUtlMemory::Grow(int num) +{ + Assert(num > 0); + + if (IsExternallyAllocated()) { + Assert(0); + return; + } + + int nAllocationRequested = m_nAllocationCount + num; + + UTLMEMORY_TRACK_FREE(); + + m_nAllocationCount = UtlMemory_CalcNewAllocationCount(m_nAllocationCount, m_nGrowSize, nAllocationRequested, sizeof(T)); + + if ((int)(I)m_nAllocationCount < nAllocationRequested) { + if ((int)(I)m_nAllocationCount == 0 && (int)(I)(m_nAllocationCount - 1) >= nAllocationRequested) { + --m_nAllocationCount; + } else { + if ((int)(I)nAllocationRequested != nAllocationRequested) { + Assert(0); + return; + } + while ((int)(I)m_nAllocationCount < nAllocationRequested) { + m_nAllocationCount = (m_nAllocationCount + nAllocationRequested) / 2; + } + } + } + + UTLMEMORY_TRACK_ALLOC(); + + if (m_pMemory) { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); + Assert(m_pMemory); + } else { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + Assert(m_pMemory); + } +} +template +inline void CUtlMemory::EnsureCapacity(int num) +{ + if (m_nAllocationCount >= num) + return; + + if (IsExternallyAllocated()) { + Assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + m_nAllocationCount = num; + + UTLMEMORY_TRACK_ALLOC(); + + if (m_pMemory) { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); + } else { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} +template +void CUtlMemory::Purge() +{ + if (!IsExternallyAllocated()) { + if (m_pMemory) { + UTLMEMORY_TRACK_FREE(); + free((void*)m_pMemory); + m_pMemory = 0; + } + m_nAllocationCount = 0; + } +} +template +void CUtlMemory::Purge(int numElements) +{ + Assert(numElements >= 0); + + if (numElements > m_nAllocationCount) { + Assert(numElements <= m_nAllocationCount); + return; + } + + if (numElements == 0) { + Purge(); + return; + } + + if (IsExternallyAllocated()) { + return; + } + + if (numElements == m_nAllocationCount) { + return; + } + + if (!m_pMemory) { + Assert(m_pMemory); + return; + } + + UTLMEMORY_TRACK_FREE(); + + m_nAllocationCount = numElements; + + UTLMEMORY_TRACK_ALLOC(); + + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); +} +#pragma endregion + #define FCVAR_DEVELOPMENTONLY (1 << 1) #define FCVAR_HIDDEN (1 << 4) #define FCVAR_NEVER_AS_STRING (1 << 12) @@ -104,7 +953,7 @@ using _InternalSetFloatValue = void(__rescalll*)(void* thisptr, float value); using _InternalSetIntValue = void(__rescalll*)(void* thisptr, int value); using _RegisterConCommand = void(__rescalll*)(void* thisptr, ConCommandBase* pCommandBase); using _UnregisterConCommand = void(__rescalll*)(void* thisptr, ConCommandBase* pCommandBase); -using _FindCommandBase = void*(__rescalll*)(void* thisptr, const char* name); +using _FindCommandBase = ConCommandBase*(__rescalll*)(void* thisptr, const char* name); using _InstallGlobalChangeCallback = void(__rescalll*)(void* thisptr, FnChangeCallback_t callback); using _RemoveGlobalChangeCallback = void(__rescalll*)(void* thisptr, FnChangeCallback_t callback); using _AutoCompletionFunc = int(__rescalll*)(void* thisptr, char const* partial, char commands[COMMAND_COMPLETION_MAXITEMS][COMMAND_COMPLETION_ITEM_LENGTH]); @@ -212,6 +1061,7 @@ struct ConVar : ConCommandBase { , m_pParent(nullptr) , m_pszDefaultValue(value) , m_pszString(nullptr) + , m_StringLength(0) , m_fValue(0.0f) , m_nValue(0) , m_bHasMin(hasmin) @@ -223,20 +1073,6 @@ struct ConVar : ConCommandBase { } }; -template -struct CUtlMemory { - T* m_pMemory; - int m_nAllocationCount; - int m_nGrowSize; -}; - -template > -struct CUtlVector { - A m_Memory; - int m_Size; - T* m_pElements; -}; - struct ConVar2 : ConCommandBase { void* ConVar_VTable; // 24 ConVar2* m_pParent; // 28 @@ -257,6 +1093,7 @@ struct ConVar2 : ConCommandBase { , m_pParent(nullptr) , m_pszDefaultValue(value) , m_pszString(nullptr) + , m_StringLength(0) , m_fValue(0.0f) , m_nValue(0) , m_bHasMin(hasmin) @@ -409,54 +1246,14 @@ struct InterfaceReg { } }; -class IServerPluginCallbacks { -public: - virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) = 0; - virtual void Unload() = 0; - virtual void Pause() = 0; - virtual void UnPause() = 0; - virtual const char* GetPluginDescription() = 0; - virtual void LevelInit(char const* pMapName) = 0; - virtual void ServerActivate(void* pEdictList, int edictCount, int clientMax) = 0; - virtual void GameFrame(bool simulating) = 0; - virtual void LevelShutdown() = 0; - virtual void ClientFullyConnect(void* pEdict) = 0; - virtual void ClientActive(void* pEntity) = 0; - virtual void ClientDisconnect(void* pEntity) = 0; - virtual void ClientPutInServer(void* pEntity, char const* playername) = 0; - virtual void SetCommandClient(int index) = 0; - virtual void ClientSettingsChanged(void* pEdict) = 0; - virtual int ClientConnect(bool* bAllowConnect, void* pEntity, const char* pszName, const char* pszAddress, char* reject, int maxrejectlen) = 0; - virtual int ClientCommand(void* pEntity, const void*& args) = 0; - virtual int NetworkIDValidated(const char* pszUserName, const char* pszNetworkID) = 0; - virtual void OnQueryCvarValueFinished(int iCookie, void* pPlayerEntity, int eStatus, const char* pCvarName, const char* pCvarValue) = 0; - virtual void OnEdictAllocated(void* edict) = 0; - virtual void OnEdictFreed(const void* edict) = 0; -}; - struct CPlugin { char m_szName[128]; // 0 bool m_bDisable; // 128 - IServerPluginCallbacks* m_pPlugin; // 132 + void* m_pPlugin; // 132 int m_iPluginInterfaceVersion; // 136 void* m_pPluginModule; // 140 }; -#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ - static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); - -#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ - static void* __Create##className##_interface() { return static_cast(new className); } \ - static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName); - -#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ - static void* __Create##className##interfaceName##_interface() { return static_cast(&globalVarName); } \ - static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); - -#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ - static className __g_##className##_singleton; \ - EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) - struct CEventAction { const char* m_iTarget; // 0 const char* m_iTargetInput; // 4 diff --git a/src/Variable.cpp b/src/Variable.cpp index d486b674..9b8fa716 100644 --- a/src/Variable.cpp +++ b/src/Variable.cpp @@ -8,127 +8,82 @@ #include "Offsets.hpp" #include "SAR.hpp" -std::vector& Variable::GetList() +Variable::Variable() + : Variable(SourceGame_Unknown) { - static std::vector list; - return list; } - -Variable::Variable() - : ptr(nullptr) +Variable::Variable(int version) + : CommandBase(version) , originalFlags(0) , originalFnChangeCallback(nullptr) - , version(SourceGame_Unknown) - , isRegistered(false) - , isReference(false) { } -Variable::~Variable() -{ - if (!this->isReference) { - SAFE_DELETE(this->ptr) - } -} Variable::Variable(const char* name) - : Variable() + : Variable(SourceGame_Unknown) { - this->ptr = reinterpret_cast(tier1->FindCommandBase(tier1->g_pCVar->ThisPtr(), name)); + this->ptr = tier1->FindCommandBase(tier1->g_pCVar->ThisPtr(), name); this->isReference = true; } // Boolean or String -Variable::Variable(const char* name, const char* value, const char* helpstr, int flags) - : Variable() +Variable::Variable(const char* name, const char* value, const char* helpstr, int version, int flags) + : Variable(version) { if (flags != 0) - Create(name, value, flags, helpstr, true, 0, true, 1); + this->Create(name, value, flags, helpstr, true, 0, true, 1); else - Create(name, value, flags, helpstr); + this->Create(name, value, flags, helpstr); } // Float -Variable::Variable(const char* name, const char* value, float min, const char* helpstr, int flags) - : Variable() +Variable::Variable(const char* name, const char* value, float min, const char* helpstr, int version, int flags) + : Variable(version) { - Create(name, value, flags, helpstr, true, min); + this->Create(name, value, flags, helpstr, true, min); } // Float -Variable::Variable(const char* name, const char* value, float min, float max, const char* helpstr, int flags) - : Variable() +Variable::Variable(const char* name, const char* value, float min, float max, const char* helpstr, int version, int flags) + : Variable(version) { - Create(name, value, flags, helpstr, true, min, true, max); + this->Create(name, value, flags, helpstr, true, min, true, max); } void Variable::Create(const char* name, const char* value, int flags, const char* helpstr, bool hasmin, float min, bool hasmax, float max) { - this->ptr = new ConVar(name, value, flags, helpstr, hasmin, min, hasmax, max); + this->ptr = new ConVar2(name, value, flags, helpstr, hasmin, min, hasmax, max); - Variable::GetList().push_back(this); -} -void Variable::Realloc() -{ - if (sar.game->Is(SourceGame_Portal2Engine)) { - auto newptr = new ConVar2( - this->ptr->m_pszName, - this->ptr->m_pszDefaultValue, - this->ptr->m_nFlags, - this->ptr->m_pszHelpString, - this->ptr->m_bHasMin, - this->ptr->m_fMinVal, - this->ptr->m_bHasMax, - this->ptr->m_fMaxVal); - delete this->ptr; - this->ptr = reinterpret_cast(newptr); - } -} -ConVar* Variable::ThisPtr() -{ - return this->ptr; -} -ConVar2* Variable::ThisPtr2() -{ - return reinterpret_cast(this->ptr); -} -bool Variable::GetBool() -{ - return !!GetInt(); -} -int Variable::GetInt() -{ - return this->ptr->m_nValue; -} -float Variable::GetFloat() -{ - return this->ptr->m_fValue; + CommandBase::GetList().push_back(this); } -const char* Variable::GetString() -{ - return this->ptr->m_pszString; -} -const int Variable::GetFlags() -{ - return this->ptr->m_nFlags; -} -void Variable::SetValue(const char* value) -{ - Memory::VMT<_InternalSetValue>(this->ptr, Offsets::InternalSetValue)(this->ptr, value); -} -void Variable::SetValue(float value) -{ - Memory::VMT<_InternalSetFloatValue>(this->ptr, Offsets::InternalSetFloatValue)(this->ptr, value); -} -void Variable::SetValue(int value) -{ - Memory::VMT<_InternalSetIntValue>(this->ptr, Offsets::InternalSetIntValue)(this->ptr, value); -} -void Variable::SetFlags(int value) -{ - this->ptr->m_nFlags = value; -} -void Variable::AddFlag(int value) +void Variable::Register() { - this->SetFlags(this->GetFlags() | value); + if (!this->isRegistered && !this->isReference && this->ptr) { + this->isRegistered = true; + + auto ptr = this->ThisPtr(); + ptr->ConCommandBase_VTable = tier1->ConVar_VTable; + ptr->ConVar_VTable = tier1->ConVar_VTable2; + + tier1->Create(ptr, + ptr->m_pszName, + ptr->m_pszDefaultValue, + ptr->m_nFlags, + ptr->m_pszHelpString, + ptr->m_bHasMin, + ptr->m_fMinVal, + ptr->m_bHasMax, + ptr->m_fMaxVal, + nullptr); + } } -void Variable::RemoveFlag(int value) +void Variable::Unregister() { - this->SetFlags(this->GetFlags() & ~(value)); + if (this->isRegistered && !this->isReference && this->ptr) { + this->isRegistered = false; + tier1->UnregisterConCommand(tier1->g_pCVar->ThisPtr(), this->ptr); +#ifdef _WIN32 + tier1->Dtor(this->ThisPtr(), 0); +#else + tier1->Dtor(this->ThisPtr()); +#endif + sdelete(this->ptr) + } } void Variable::Unlock(bool asCheat) { @@ -148,18 +103,20 @@ void Variable::Lock() { if (this->ptr) { this->SetFlags(this->originalFlags); - this->SetValue(this->ptr->m_pszDefaultValue); + this->SetValue(this->ThisPtr()->m_pszDefaultValue); } } void Variable::DisableChange() { if (this->ptr) { if (sar.game->Is(SourceGame_Portal2Engine)) { - this->originalSize = ((ConVar2*)this->ptr)->m_fnChangeCallback.m_Size; - ((ConVar2*)this->ptr)->m_fnChangeCallback.m_Size = 0; + auto ptr = this->ThisPtr2(); + this->originalSize = ptr->m_fnChangeCallback.m_Size; + ptr->m_fnChangeCallback.m_Size = 0; } else if (sar.game->Is(SourceGame_HalfLife2Engine)) { - this->originalFnChangeCallback = this->ptr->m_fnChangeCallback; - this->ptr->m_fnChangeCallback = nullptr; + auto ptr = ThisPtr(); + this->originalFnChangeCallback = ptr->m_fnChangeCallback; + ptr->m_fnChangeCallback = nullptr; } } } @@ -167,76 +124,25 @@ void Variable::EnableChange() { if (this->ptr) { if (sar.game->Is(SourceGame_Portal2Engine)) { - ((ConVar2*)this->ptr)->m_fnChangeCallback.m_Size = this->originalSize; + this->ThisPtr2()->m_fnChangeCallback.m_Size = this->originalSize; } else if (sar.game->Is(SourceGame_HalfLife2Engine)) { - this->ptr->m_fnChangeCallback = this->originalFnChangeCallback; + this->ThisPtr()->m_fnChangeCallback = this->originalFnChangeCallback; } } } -void Variable::UniqueFor(int version) -{ - this->version = version; -} -void Variable::Register() -{ - if (!this->isRegistered && !this->isReference && this->ptr) { - this->isRegistered = true; - this->Realloc(); - this->ptr->ConCommandBase_VTable = tier1->ConVar_VTable; - this->ptr->ConVar_VTable = tier1->ConVar_VTable2; - tier1->Create(this->ptr, - this->ptr->m_pszName, - this->ptr->m_pszDefaultValue, - this->ptr->m_nFlags, - this->ptr->m_pszHelpString, - this->ptr->m_bHasMin, - this->ptr->m_fMinVal, - this->ptr->m_bHasMax, - this->ptr->m_fMaxVal, - nullptr); - } -} -void Variable::Unregister() +Variable Variable::FromString(const char* name, const char* value, const char* helpstr, int version) { - if (this->isRegistered && !this->isReference && this->ptr) { - this->isRegistered = false; - tier1->UnregisterConCommand(tier1->g_pCVar->ThisPtr(), this->ptr); -#ifdef _WIN32 - tier1->Dtor(this->ptr, 0); -#else - tier1->Dtor(this->ptr); -#endif - SAFE_DELETE(this->ptr) - } -} -bool Variable::operator!() -{ - return this->ptr == nullptr; + return Variable(name, value, helpstr, 0, version); } -int Variable::RegisterAll() +Variable Variable::FromBoolean(const char* name, const char* value, const char* helpstr, int version) { - auto result = 0; - for (const auto& var : Variable::GetList()) { - if (var->version != SourceGame_Unknown && !sar.game->Is(var->version)) { - continue; - } - var->Register(); - ++result; - } - return result; + return Variable(name, value, helpstr, FCVAR_NEVER_AS_STRING, version); } -void Variable::UnregisterAll() +Variable Variable::FromFloat(const char* name, const char* value, float min, const char* helpstr, int version) { - for (const auto& var : Variable::GetList()) { - var->Unregister(); - } + return Variable(name, value, min, helpstr, FCVAR_NEVER_AS_STRING, version); } -Variable* Variable::Find(const char* name) +Variable Variable::FromFloatRange(const char* name, const char* value, float min, float max, const char* helpstr, int version) { - for (const auto& var : Variable::GetList()) { - if (!std::strcmp(var->ThisPtr()->m_pszName, name)) { - return var; - } - } - return nullptr; + return Variable(name, value, min, max, helpstr, FCVAR_NEVER_AS_STRING, version); } diff --git a/src/Variable.hpp b/src/Variable.hpp index bda153fe..735ab4e6 100644 --- a/src/Variable.hpp +++ b/src/Variable.hpp @@ -3,10 +3,12 @@ #include "Utils/SDK.hpp" -class Variable { -private: - ConVar* ptr; +#include "Command.hpp" +#include "Game.hpp" +#include "Offsets.hpp" +class Variable : public CommandBase { +private: int originalFlags; union { @@ -14,42 +16,51 @@ class Variable { int originalSize; }; -public: - int version; - bool isRegistered; - bool isReference; - -public: - static std::vector& GetList(); - public: Variable(); - ~Variable(); + Variable(int version); Variable(const char* name); - Variable(const char* name, const char* value, const char* helpstr, int flags = FCVAR_NEVER_AS_STRING); - Variable(const char* name, const char* value, float min, const char* helpstr, int flags = FCVAR_NEVER_AS_STRING); - Variable(const char* name, const char* value, float min, float max, const char* helpstr, int flags = FCVAR_NEVER_AS_STRING); + Variable(const char* name, const char* value, const char* helpstr, int version = SourceGame_Unknown, + int flags = FCVAR_NEVER_AS_STRING); + Variable(const char* name, const char* value, float min, const char* helpstr, int version = SourceGame_Unknown, + int flags = FCVAR_NEVER_AS_STRING); + Variable(const char* name, const char* value, float min, float max, const char* helpstr, int version = SourceGame_Unknown, + int flags = FCVAR_NEVER_AS_STRING); +private: void Create(const char* name, const char* value, int flags = 0, const char* helpstr = "", bool hasmin = false, float min = 0, bool hasmax = false, float max = 0); - void Realloc(); - ConVar* ThisPtr(); - ConVar2* ThisPtr2(); - - bool GetBool(); - int GetInt(); - float GetFloat(); - const char* GetString(); - const int GetFlags(); - - void SetValue(const char* value); - void SetValue(float value); - void SetValue(int value); - - void SetFlags(int value); - void AddFlag(int value); - void RemoveFlag(int value); +public: + inline bool IsCommand() override { return false; } + void Register() override; + void Unregister() override; + + inline ConVar* ThisPtr() { return reinterpret_cast(this->ptr); } + inline ConVar2* ThisPtr2() { return reinterpret_cast(this->ptr); } + + inline bool GetBool() { return !!GetInt(); } + inline int GetInt() { return this->ThisPtr()->m_nValue; } + inline float GetFloat() { return this->ThisPtr()->m_fValue; } + inline const char* GetString() { return this->ThisPtr()->m_pszString; } + inline const int GetFlags() { return this->ThisPtr()->m_nFlags; } + + inline void SetValue(const char* value) + { + Memory::VMT<_InternalSetValue>(this->ptr, Offsets::InternalSetValue)(this->ptr, value); + } + inline void SetValue(float value) + { + Memory::VMT<_InternalSetFloatValue>(this->ptr, Offsets::InternalSetFloatValue)(this->ptr, value); + } + inline void SetValue(int value) + { + Memory::VMT<_InternalSetIntValue>(this->ptr, Offsets::InternalSetIntValue)(this->ptr, value); + } + + inline void SetFlags(int value) { this->ptr->m_nFlags = value; } + inline void AddFlag(int value) { this->SetFlags(this->GetFlags() | value); } + inline void RemoveFlag(int value) { this->SetFlags(this->GetFlags() & ~(value)); } void Unlock(bool asCheat = true); void Lock(); @@ -57,13 +68,12 @@ class Variable { void DisableChange(); void EnableChange(); - void UniqueFor(int version); - void Register(); - void Unregister(); - - bool operator!(); - - static int RegisterAll(); - static void UnregisterAll(); - static Variable* Find(const char* name); + static Variable FromString(const char* name, const char* value, const char* helpstr, + int version = SourceGame_Unknown); + static Variable FromBoolean(const char* name, const char* value, const char* helpstr, + int version = SourceGame_Unknown); + static Variable FromFloat(const char* name, const char* value, float min, const char* helpstr, + int version = SourceGame_Unknown); + static Variable FromFloatRange(const char* name, const char* value, float min, float max, const char* helpstr, + int version = SourceGame_Unknown); };