├── .gitattributes ├── .gitignore ├── README.md ├── generate.bat ├── premake5.lua ├── src ├── Components │ ├── Loader.cpp │ ├── Loader.hpp │ └── Modules │ │ ├── Bots.cpp │ │ ├── Bots.hpp │ │ ├── Flags.cpp │ │ ├── Flags.hpp │ │ ├── HelloWorld.cpp │ │ ├── HelloWorld.hpp │ │ ├── Logger.cpp │ │ ├── Logger.hpp │ │ ├── Player.cpp │ │ ├── Player.hpp │ │ ├── Scheduler.cpp │ │ ├── Scheduler.hpp │ │ ├── Script.cpp │ │ └── Script.hpp ├── Game │ ├── Game.cpp │ ├── Game.hpp │ └── Structs.hpp ├── Main.cpp ├── Resource.rc ├── SDLLP.cpp ├── STDInclude.cpp ├── STDInclude.hpp └── Utils │ ├── Hooking.cpp │ ├── Hooking.hpp │ ├── Memory.cpp │ ├── Memory.hpp │ ├── String.cpp │ ├── String.hpp │ ├── Time.cpp │ ├── Time.hpp │ ├── Utils.cpp │ └── Utils.hpp └── tools ├── premake5.exe └── protoc.exe /.gitattributes: -------------------------------------------------------------------------------- 1 | *.hpp eol=crlf 2 | *.cpp eol=crlf 3 | *.lua eol=crlf 4 | *.proto eol=crlf 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Windows 2 | 3 | # Windows image file caches 4 | Thumbs.db 5 | ehthumbs.db 6 | 7 | # Folder config file 8 | Desktop.ini 9 | 10 | # Recycle Bin used on file shares 11 | $RECYCLE.BIN/ 12 | 13 | # Windows Installer files 14 | *.cab 15 | *.msi 16 | *.msm 17 | *.msp 18 | 19 | # Shortcuts 20 | *.lnk 21 | 22 | ### OSX 23 | 24 | .DS_Store 25 | .AppleDouble 26 | .LSOverride 27 | 28 | # Icon must end with two \r 29 | Icon 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | 45 | ### Visual Studio 46 | 47 | # User-specific files 48 | *.suo 49 | *.user 50 | *.userosscache 51 | *.sln.docstates 52 | 53 | # User-specific files (MonoDevelop/Xamarin Studio) 54 | *.userprefs 55 | 56 | # Build results 57 | build 58 | 59 | # Visual Studio 2015 cache/options directory 60 | .vs/ 61 | 62 | # MSTest test Results 63 | [Tt]est[Rr]esult*/ 64 | [Bb]uild[Ll]og.* 65 | 66 | *_i.c 67 | *_p.c 68 | *_i.h 69 | *.ilk 70 | *.meta 71 | *.obj 72 | *.pch 73 | *.pdb 74 | *.pgc 75 | *.pgd 76 | *.rsp 77 | *.sbr 78 | *.tlb 79 | *.tli 80 | *.tlh 81 | *.tmp 82 | *.tmp_proj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | 100 | # Visual Studio profiler 101 | *.psess 102 | *.vsp 103 | *.vspx 104 | *.sap 105 | 106 | # TFS 2012 Local Workspace 107 | $tf/ 108 | 109 | # Guidance Automation Toolkit 110 | *.gpState 111 | 112 | # Visual Studio cache files 113 | # files ending in .cache can be ignored 114 | *.[Cc]ache 115 | # but keep track of directories ending in .cache 116 | !*.[Cc]ache/ 117 | 118 | # Others 119 | ~$* 120 | *~ 121 | *.dbmdl 122 | *.dbproj.schemaview 123 | *.pfx 124 | *.publishsettings 125 | 126 | # Backup & report files from converting an old project file 127 | # to a newer Visual Studio version. Backup files are not needed, 128 | # because we have git ;-) 129 | _UpgradeReport_Files/ 130 | Backup*/ 131 | UpgradeLog*.XML 132 | UpgradeLog*.htm 133 | 134 | # SQL Server files 135 | *.mdf 136 | *.ldf 137 | 138 | ### IDA 139 | *.id0 140 | *.id1 141 | *.id2 142 | *.nam 143 | *.til 144 | *.idb 145 | *.i64 146 | ida/* 147 | 148 | ### Custom user files 149 | # User scripts 150 | user*.bat 151 | 152 | # Premake binary 153 | #premake5.exe 154 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Credits 2 | - libcod Team - https://github.com/M-itch/libcod 3 | - T4M Team - https://github.com/iAmThatMichael/T4M 4 | - IW4x Team - https://github.com/XLabsProject/iw4x-client 5 | - CoD4x Team - https://github.com/callofduty4x/CoD4x_Server 6 | -------------------------------------------------------------------------------- /generate.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Updating submodules... 3 | call git submodule update --init --recursive 4 | call tools\premake5 %* vs2019 --copy-to="G:\SteamLibrary\steamapps\common\Call of Duty 2" 5 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | gitVersioningCommand = "git describe --tags --dirty --always" 2 | gitCurrentBranchCommand = "git symbolic-ref -q --short HEAD" 3 | 4 | -- Quote the given string input as a C string 5 | function cstrquote(value) 6 | result = value:gsub("\\", "\\\\") 7 | result = result:gsub("\"", "\\\"") 8 | result = result:gsub("\n", "\\n") 9 | result = result:gsub("\t", "\\t") 10 | result = result:gsub("\r", "\\r") 11 | result = result:gsub("\a", "\\a") 12 | result = result:gsub("\b", "\\b") 13 | result = "\"" .. result .. "\"" 14 | return result 15 | end 16 | 17 | -- Converts tags in "vX.X.X" format to an array of numbers {X,X,X}. 18 | -- In the case where the format does not work fall back to old {4,2,REVISION}. 19 | function vertonumarr(value, vernumber) 20 | vernum = {} 21 | for num in string.gmatch(value, "%d+") do 22 | table.insert(vernum, tonumber(num)) 23 | end 24 | if #vernum < 3 then 25 | return {4,2,tonumber(vernumber)} 26 | end 27 | return vernum 28 | end 29 | 30 | -- Option to allow copying the DLL file to a custom folder after build 31 | newoption { 32 | trigger = "copy-to", 33 | description = "Optional, copy the DLL to a custom folder after build, define the path here if wanted.", 34 | value = "PATH" 35 | } 36 | 37 | newoption { 38 | trigger = "no-new-structure", 39 | description = "Do not use new virtual path structure (separating headers and source files)." 40 | } 41 | 42 | newoption { 43 | trigger = "copy-pdb", 44 | description = "Copy debug information for binaries as well to the path given via --copy-to." 45 | } 46 | 47 | newaction { 48 | trigger = "version", 49 | description = "Returns the version string for the current commit of the source code.", 50 | onWorkspace = function(wks) 51 | -- get current version via git 52 | local proc = assert(io.popen(gitVersioningCommand, "r")) 53 | local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "") 54 | proc:close() 55 | local version = gitDescribeOutput 56 | 57 | proc = assert(io.popen(gitCurrentBranchCommand, "r")) 58 | local gitCurrentBranchOutput = assert(proc:read('*a')):gsub("%s+", "") 59 | local gitCurrentBranchSuccess = proc:close() 60 | if gitCurrentBranchSuccess then 61 | -- We got a branch name, check if it is a feature branch 62 | if gitCurrentBranchOutput ~= "develop" and gitCurrentBranchOutput ~= "master" then 63 | version = version .. "-" .. gitCurrentBranchOutput 64 | end 65 | end 66 | 67 | print(version) 68 | os.exit(0) 69 | end 70 | } 71 | 72 | newaction { 73 | trigger = "generate-buildinfo", 74 | description = "Sets up build information file like version.h.", 75 | onWorkspace = function(wks) 76 | -- get revision number via git 77 | local proc = assert(io.popen("git rev-list --count HEAD", "r")) 78 | local revNumber = assert(proc:read('*a')):gsub("%s+", "") 79 | 80 | -- get current version via git 81 | local proc = assert(io.popen(gitVersioningCommand, "r")) 82 | local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "") 83 | proc:close() 84 | 85 | -- get whether this is a clean revision (no uncommitted changes) 86 | proc = assert(io.popen("git status --porcelain", "r")) 87 | local revDirty = (assert(proc:read('*a')) ~= "") 88 | if revDirty then revDirty = 1 else revDirty = 0 end 89 | proc:close() 90 | 91 | -- get current tag name 92 | proc = assert(io.popen("git describe --tags --abbrev=0")) 93 | local tagName = assert(proc:read('*l')) 94 | 95 | -- get old version number from version.hpp if any 96 | local oldVersion = "(none)" 97 | local oldVersionHeader = io.open(wks.location .. "/src/version.h", "r") 98 | if oldVersionHeader ~= nil then 99 | local oldVersionHeaderContent = assert(oldVersionHeader:read('*l')) 100 | while oldVersionHeaderContent do 101 | m = string.match(oldVersionHeaderContent, "#define GIT_DESCRIBE (.+)%s*$") 102 | if m ~= nil then 103 | oldVersion = m 104 | end 105 | 106 | oldVersionHeaderContent = oldVersionHeader:read('*l') 107 | end 108 | end 109 | 110 | -- generate version.hpp with a revision number if not equal 111 | gitDescribeOutputQuoted = cstrquote(gitDescribeOutput) 112 | if oldVersion ~= gitDescribeOutputQuoted then 113 | print ("Update " .. oldVersion .. " -> " .. gitDescribeOutputQuoted) 114 | local versionHeader = assert(io.open(wks.location .. "/src/version.h", "w")) 115 | versionHeader:write("/*\n") 116 | versionHeader:write(" * Automatically generated by premake5.\n") 117 | versionHeader:write(" * Do not touch, you fucking moron!\n") 118 | versionHeader:write(" */\n") 119 | versionHeader:write("\n") 120 | versionHeader:write("#define GIT_DESCRIBE " .. gitDescribeOutputQuoted .. "\n") 121 | versionHeader:write("#define GIT_DIRTY " .. revDirty .. "\n") 122 | versionHeader:write("#define GIT_TAG " .. cstrquote(tagName) .. "\n") 123 | versionHeader:write("\n") 124 | versionHeader:write("// Legacy definitions (needed for update check)\n") 125 | versionHeader:write("#define REVISION " .. revNumber .. "\n") 126 | versionHeader:write("\n") 127 | versionHeader:write("// Version transformed for RC files\n") 128 | versionHeader:write("#define VERSION_RC " .. table.concat(vertonumarr(tagName, revNumber), ",") .. "\n") 129 | versionHeader:write("\n") 130 | versionHeader:write("// Alias definitions\n") 131 | versionHeader:write("#define VERSION GIT_DESCRIBE\n") 132 | versionHeader:write("#define SHORTVERSION " .. cstrquote(table.concat(vertonumarr(tagName, revNumber), ".")) .. "\n") 133 | versionHeader:close() 134 | local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w")) 135 | versionHeader:write("/*\n") 136 | versionHeader:write(" * Automatically generated by premake5.\n") 137 | versionHeader:write(" * Do not touch, you fucking moron!\n") 138 | versionHeader:write(" *\n") 139 | versionHeader:write(" * This file exists for reasons of complying with our coding standards.\n") 140 | versionHeader:write(" *\n") 141 | versionHeader:write(" * The Resource Compiler will ignore any content from C++ header files if they're not from STDInclude.hpp.\n") 142 | versionHeader:write(" * That's the reason why we now place all version info in version.h instead.\n") 143 | versionHeader:write(" */\n") 144 | versionHeader:write("\n") 145 | versionHeader:write("#include \".\\version.h\"\n") 146 | versionHeader:close() 147 | end 148 | end 149 | } 150 | 151 | workspace "cod2m" 152 | startproject "cod2m" 153 | location "./build" 154 | objdir "%{wks.location}/obj" 155 | targetdir "%{wks.location}/bin/%{cfg.buildcfg}" 156 | buildlog "%{wks.location}/obj/%{cfg.architecture}/%{cfg.buildcfg}/%{prj.name}/%{prj.name}.log" 157 | configurations { "Debug", "Release" } 158 | architecture "x86" 159 | platforms "x86" 160 | --exceptionhandling ("SEH") 161 | 162 | staticruntime "On" 163 | 164 | configuration "windows" 165 | defines { "_WINDOWS", "WIN32" } 166 | 167 | configuration "Release*" 168 | defines { "NDEBUG" } 169 | flags { "MultiProcessorCompile", "LinkTimeOptimization", "No64BitChecks" } 170 | optimize "On" 171 | rtti ("Off") 172 | 173 | configuration "Debug*" 174 | defines { "DEBUG", "_DEBUG" } 175 | flags { "MultiProcessorCompile", "No64BitChecks" } 176 | optimize "Debug" 177 | if symbols ~= nil then 178 | symbols "On" 179 | else 180 | flags { "Symbols" } 181 | end 182 | 183 | project "d3d9" 184 | kind "SharedLib" 185 | language "C++" 186 | files { 187 | "./src/**.rc", 188 | "./src/**.hpp", 189 | "./src/**.cpp", 190 | --"./src/**.proto", 191 | } 192 | includedirs { 193 | "%{prj.location}/src", 194 | "./src", 195 | "./lib/include", 196 | } 197 | syslibdirs { 198 | "./lib/bin", 199 | } 200 | resincludedirs { 201 | "$(ProjectDir)src" -- fix for VS IDE 202 | } 203 | 204 | 205 | -- Pre-compiled header 206 | pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives 207 | pchsource "src/STDInclude.cpp" -- real path 208 | buildoptions { "/Zm200" } 209 | 210 | -- fix vpaths for protobuf sources 211 | vpaths 212 | { 213 | ["*"] = { "./src/**" }, 214 | --["Proto/Generated"] = { "**.pb.*" }, -- meh. 215 | } 216 | 217 | -- Virtual paths 218 | if not _OPTIONS["no-new-structure"] then 219 | vpaths 220 | { 221 | ["Headers/*"] = { "./src/**.hpp" }, 222 | ["Sources/*"] = { "./src/**.cpp" }, 223 | ["Resource/*"] = { "./src/**.rc" }, 224 | --["Proto/Definitions/*"] = { "./src/Proto/**.proto" }, 225 | --["Proto/Generated/*"] = { "**.pb.*" }, -- meh. 226 | } 227 | end 228 | 229 | vpaths 230 | { 231 | ["Docs/*"] = { "**.txt","**.md" }, 232 | } 233 | 234 | -- Pre-build 235 | prebuildcommands 236 | { 237 | "pushd %{_MAIN_SCRIPT_DIR}", 238 | "tools\\premake5 generate-buildinfo", 239 | "popd", 240 | } 241 | 242 | -- Post-build 243 | if _OPTIONS["copy-to"] then 244 | saneCopyToPath = string.gsub(_OPTIONS["copy-to"] .. "\\", "\\\\", "\\") 245 | postbuildcommands { 246 | "if not exist \"" .. saneCopyToPath .. "\" mkdir \"" .. saneCopyToPath .. "\"", 247 | } 248 | 249 | if _OPTIONS["copy-pdb"] then 250 | postbuildcommands { 251 | "copy /y \"$(TargetDir)*.pdb\" \"" .. saneCopyToPath .. "\"", 252 | } 253 | end 254 | 255 | -- This has to be the last one, as otherwise VisualStudio will succeed building even if copying fails 256 | postbuildcommands { 257 | "copy /y \"$(TargetDir)*.dll\" \"" .. saneCopyToPath .. "\"", 258 | } 259 | end 260 | 261 | -- Specific configurations 262 | flags { "UndefinedIdentifiers" } 263 | warnings "Extra" 264 | 265 | if symbols ~= nil then 266 | symbols "On" 267 | else 268 | flags { "Symbols" } 269 | end 270 | 271 | configuration "Release*" 272 | flags { 273 | "FatalCompileWarnings", 274 | "FatalLinkWarnings", 275 | } 276 | configuration {} 277 | 278 | --[[ 279 | -- Generate source code from protobuf definitions 280 | rules { "ProtobufCompiler" } 281 | 282 | -- Workaround: Consume protobuf generated source files 283 | matches = os.matchfiles(path.join("src/Proto/**.proto")) 284 | for i, srcPath in ipairs(matches) do 285 | basename = path.getbasename(srcPath) 286 | files 287 | { 288 | string.format("%%{prj.location}/src/proto/%s.pb.h", basename), 289 | string.format("%%{prj.location}/src/proto/%s.pb.cc", basename), 290 | } 291 | end 292 | includedirs 293 | { 294 | "%{prj.location}/src/proto", 295 | } 296 | filter "files:**.pb.*" 297 | flags { 298 | "NoPCH", 299 | } 300 | buildoptions { 301 | "/wd4100", -- "Unused formal parameter" 302 | "/wd4389", -- "Signed/Unsigned mismatch" 303 | "/wd6011", -- "Dereferencing NULL pointer" 304 | "/wd4125", -- "Decimal digit terminates octal escape sequence" 305 | } 306 | defines { 307 | "_SCL_SECURE_NO_WARNINGS", 308 | } 309 | filter {} 310 | ]] 311 | 312 | workspace "*" 313 | buildoptions { 314 | "/std:c++latest" 315 | } 316 | systemversion "latest" 317 | defines { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS" } 318 | -------------------------------------------------------------------------------- /src/Components/Loader.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | 3 | #include "Modules/Bots.hpp" 4 | #include "Modules/Flags.hpp" 5 | #include "Modules/HelloWorld.hpp" 6 | #include "Modules/Logger.hpp" 7 | #include "Modules/Script.hpp" 8 | #include "Modules/Player.hpp" 9 | #include "Modules/Scheduler.hpp" 10 | 11 | namespace Components 12 | { 13 | bool Loader::Pregame = true; 14 | bool Loader::Postgame = false; 15 | bool Loader::Uninitializing = false; 16 | std::vector Loader::Components; 17 | 18 | bool Loader::IsPregame() 19 | { 20 | return Loader::Pregame; 21 | } 22 | 23 | bool Loader::IsPostgame() 24 | { 25 | return Loader::Postgame; 26 | } 27 | 28 | bool Loader::IsUninitializing() 29 | { 30 | return Loader::Uninitializing; 31 | } 32 | 33 | void Loader::Initialize(GAMEEXE GameType) 34 | { 35 | Loader::Pregame = true; 36 | Loader::Postgame = false; 37 | Loader::Uninitializing = false; 38 | Utils::Memory::GetAllocator()->clear(); 39 | 40 | Game::Init(GameType); 41 | Loader::Register(new Flags()); 42 | Loader::Register(new HelloWorld()); 43 | Loader::Register(new Logger()); 44 | Loader::Register(new Bots()); 45 | Loader::Register(new Script()); 46 | Loader::Register(new Player()); 47 | Loader::Register(new Scheduler()); 48 | 49 | Loader::Pregame = false; 50 | 51 | // Make sure preDestroy is called when the game shuts down 52 | Scheduler::OnShutdown(Loader::PreDestroy); 53 | } 54 | 55 | void Loader::Uninitialize() 56 | { 57 | Loader::Uninitializing = true; 58 | Loader::PreDestroyNoPostGame(); 59 | 60 | std::reverse(Loader::Components.begin(), Loader::Components.end()); 61 | for (auto component : Loader::Components) 62 | { 63 | #ifdef DEBUG 64 | if (!Loader::IsPerformingUnitTests()) 65 | { 66 | Logger::Print("Unregistering component: %s\n", component->getName().data()); 67 | } 68 | #endif 69 | delete component; 70 | } 71 | 72 | Loader::Components.clear(); 73 | Utils::Memory::GetAllocator()->clear(); 74 | Loader::Uninitializing = false; 75 | } 76 | 77 | void Loader::PreDestroy() 78 | { 79 | if (!Loader::Postgame) 80 | { 81 | Loader::Postgame = true; 82 | 83 | auto components = Loader::Components; 84 | 85 | std::reverse(components.begin(), components.end()); 86 | for (auto component : components) 87 | { 88 | component->preDestroy(); 89 | } 90 | } 91 | } 92 | 93 | void Loader::PreDestroyNoPostGame() 94 | { 95 | if (!Loader::Postgame) 96 | { 97 | auto components = Loader::Components; 98 | 99 | std::reverse(components.begin(), components.end()); 100 | for (auto component : components) 101 | { 102 | component->preDestroy(); 103 | } 104 | 105 | Loader::Postgame = true; 106 | } 107 | } 108 | 109 | bool Loader::PerformUnitTests() 110 | { 111 | bool result = true; 112 | 113 | Logger::Print("Performing unit tests for components:\n"); 114 | 115 | for (auto component : Loader::Components) 116 | { 117 | #if defined(DEBUG) || defined(FORCE_UNIT_TESTS) 118 | Logger::Print("Testing '%s'...\n", component->getName().data()); 119 | #endif 120 | auto startTime = std::chrono::high_resolution_clock::now(); 121 | bool testRes = component->unitTest(); 122 | auto duration = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime).count(); 123 | Logger::Print("Test done (%llims): %s\n\n", duration, (testRes ? "Success" : "Error")); 124 | result &= testRes; 125 | } 126 | 127 | return result; 128 | } 129 | 130 | bool Loader::IsPerformingUnitTests() 131 | { 132 | #if defined(DEBUG) || defined(FORCE_UNIT_TESTS) 133 | return Flags::HasFlag("tests"); 134 | #else 135 | return false; 136 | #endif 137 | } 138 | 139 | void Loader::Register(Component* component) 140 | { 141 | if (component) 142 | { 143 | #if defined(DEBUG) || defined(FORCE_UNIT_TESTS) 144 | if (!Loader::IsPerformingUnitTests()) 145 | { 146 | Logger::Print("Component registered: %s\n", component->getName().data()); 147 | } 148 | #endif 149 | Loader::Components.push_back(component); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/Components/Loader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Components 4 | { 5 | class Component 6 | { 7 | public: 8 | Component() {}; 9 | virtual ~Component() {}; 10 | 11 | #if defined(DEBUG) || defined(FORCE_UNIT_TESTS) 12 | virtual std::string getName() 13 | { 14 | std::string name = typeid(*this).name(); 15 | Utils::String::Replace(name, "class Components::", ""); 16 | return name; 17 | }; 18 | #endif 19 | 20 | // It's illegal to spawn threads in DLLMain, and apparently it causes problems if they are destroyed there as well. 21 | // This method is called before DLLMain (if possible) and should to destroy threads. 22 | // It's not 100% guaranteed that it's called outside DLLMain, as it depends on the game, but it's 100% guaranteed, that it is called at all. 23 | virtual void preDestroy() {}; 24 | virtual bool unitTest() { return true; }; // Unit testing entry 25 | }; 26 | 27 | class Loader 28 | { 29 | public: 30 | static void Initialize(GAMEEXE); 31 | static void Uninitialize(); 32 | static void PreDestroy(); 33 | static void PreDestroyNoPostGame(); 34 | static bool PerformUnitTests(); 35 | static bool IsPerformingUnitTests(); 36 | static void Register(Component* component); 37 | 38 | static bool IsPregame(); 39 | static bool IsPostgame(); 40 | static bool IsUninitializing(); 41 | 42 | template 43 | static T* GetInstance() 44 | { 45 | for (auto& component : Loader::Components) 46 | { 47 | if (typeid(*component) == typeid(T)) 48 | { 49 | return reinterpret_cast(component); 50 | } 51 | } 52 | 53 | return nullptr; 54 | } 55 | 56 | private: 57 | static bool Pregame; 58 | static bool Postgame; 59 | static bool Uninitializing; 60 | static std::vector Components; 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /src/Components/Modules/Bots.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | #include "Bots.hpp" 3 | #include "Script.hpp" 4 | 5 | namespace Components 6 | { 7 | Bots::botMovements Bots::g_botai[MAX_G_BOTAI_ENTRIES]; 8 | 9 | const Bots::BotAction_t Bots::bot_actions[] = 10 | { 11 | { "fire", KEY_FIRE }, 12 | { "attack", KEY_FIRE }, 13 | { "melee", KEY_MELEE }, 14 | { "activate", KEY_USE }, 15 | { "use", KEY_USE | KEY_USERELOAD }, 16 | { "usereload", KEY_USERELOAD }, 17 | { "reload", KEY_RELOAD }, 18 | { "leanleft", KEY_LEANLEFT }, 19 | { "leanright", KEY_LEANRIGHT }, 20 | { "goprone", KEY_PRONE }, 21 | { "gocrouch", KEY_CROUCH }, 22 | { "gostand", KEY_GOSTAND }, 23 | { "ads", KEY_ADSMODE | KEY_ADS }, 24 | { "toggleads_throw", KEY_ADSMODE }, 25 | { "speed_throw", KEY_ADS }, 26 | { "holdbreath", KEY_HOLDBREATH }, 27 | { "frag", KEY_FRAG }, 28 | { "smoke", KEY_SMOKE }, 29 | { "unk", KEY_UNK }, 30 | { "unk2", KEY_UNK2 }, 31 | { "unk3", KEY_UNK3 }, 32 | { "unk4", KEY_UNK4 }, 33 | { "menu", KEY_MENU }, 34 | { "unk5", KEY_UNK5 }, 35 | { "unk6", KEY_UNK6 }, 36 | { "unk7", KEY_UNK7 }, 37 | { "unk8", KEY_UNK8 }, 38 | { "unk9", KEY_UNK9 }, 39 | { "unk10", KEY_UNK10 }, 40 | { "unk11", KEY_UNK11 }, 41 | { "unk12", KEY_UNK12 }, 42 | { "unk13", KEY_UNK13 }, 43 | { "unk14", KEY_UNK14 }, 44 | { "unk15", KEY_UNK15 }, 45 | { "unk16", KEY_UNK16 }, 46 | { "unk17", KEY_UNK17 } 47 | }; 48 | 49 | std::vector Bots::bot_names; 50 | 51 | const char* Bots::ConnectString = "connect \"\\cg_predictItems\\1\\cl_punkbuster\\0\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\" 52 | "rate\\5000\\name\\%s\\protocol\\%d\""; 53 | 54 | int Bots::BuildConnectString(char* buffer, const char*, [[maybe_unused]] int num, int protocol) 55 | { 56 | const char* botName = Utils::String::VA("bota%d", num); 57 | return sprintf(buffer, ConnectString, botName, protocol); 58 | } 59 | 60 | void Bots::SV_BotUserMove_Func(Game::client_t* cl) 61 | { 62 | int cl_num = cl - Game::svs->clients; 63 | 64 | if (cl->state < Game::CS_ACTIVE) 65 | { 66 | Game::SV_DropClient(cl, "EXE_DISCONNECTED"); 67 | cl->state = Game::CS_FREE; 68 | return; 69 | } 70 | 71 | Game::usercmd_t cmd = {}; 72 | cmd.serverTime = Game::svs->time; 73 | cmd.weapon = g_botai[cl_num].weapon; 74 | cmd.forwardmove = g_botai[cl_num].forward; 75 | cmd.rightmove = g_botai[cl_num].right; 76 | cmd.buttons = g_botai[cl_num].buttons; 77 | 78 | cl->deltaMessage = cl->netchan.outgoingSequence - 1; 79 | cl->ping = g_botai[cl_num].ping; 80 | Game::SV_ClientThink(&cmd, cl); 81 | } 82 | 83 | __declspec(naked) void Bots::SV_BotUserMove_Stub() 84 | { 85 | __asm 86 | { 87 | push esi; 88 | call SV_BotUserMove_Func; 89 | add esp, 4; 90 | retn; 91 | } 92 | } 93 | 94 | void Bots::G_SelectWeaponIndex_Func(int wpIdx, int clNum) 95 | { 96 | g_botai[clNum].weapon = static_cast(wpIdx); 97 | 98 | Game::G_SelectWeaponIndex(wpIdx, clNum); 99 | } 100 | 101 | __declspec(naked) void Bots::G_SelectWeaponIndex_Stub() 102 | { 103 | __asm 104 | { 105 | push esi; 106 | push eax; 107 | call G_SelectWeaponIndex_Func; 108 | add esp, 8; 109 | retn; 110 | } 111 | } 112 | 113 | void __cdecl Bots::PlayerCmd_setSpawnWeapon_Func(Game::gentity_t* ent, int wpIdx) 114 | { 115 | g_botai[ent->s.number].weapon = static_cast(wpIdx); 116 | } 117 | 118 | __declspec(naked) void Bots::PlayerCmd_setSpawnWeapon_Stub() 119 | { 120 | __asm 121 | { 122 | push edx; 123 | push esi; 124 | call PlayerCmd_setSpawnWeapon_Func; 125 | add esp, 4; 126 | pop edx; // __cdecl reqires edx be caller saved 127 | 128 | // go back 129 | mov eax, [esi + 0x158]; 130 | push 0x52B16C; 131 | retn; 132 | } 133 | } 134 | 135 | Bots::Bots() 136 | { 137 | // init the bot commands 138 | for (int i = 0; i < MAX_G_BOTAI_ENTRIES; i++) 139 | { 140 | g_botai[i] = { 0 }; 141 | g_botai[i].weapon = 1; 142 | } 143 | 144 | // intercept the sprintf when creating the bot connect string 145 | Utils::Hook(0x45655B, BuildConnectString, HOOK_CALL).install()->quick(); 146 | 147 | // hook bot movement 148 | Utils::Hook(0x45C210, SV_BotUserMove_Stub, HOOK_JUMP).install()->quick(); 149 | 150 | // stop the ping spam 151 | Utils::Hook::Nop(0x45BF59, 5); 152 | 153 | 154 | // fix bots switching weapons 155 | Utils::Hook(0x52A1C2, G_SelectWeaponIndex_Stub, HOOK_CALL).install()->quick(); 156 | Utils::Hook(0x51E2DC, G_SelectWeaponIndex_Stub, HOOK_CALL).install()->quick(); 157 | Utils::Hook(0x501E0D, G_SelectWeaponIndex_Stub, HOOK_CALL).install()->quick(); 158 | Utils::Hook(0x52B166, PlayerCmd_setSpawnWeapon_Stub, HOOK_JUMP).install()->quick(); 159 | 160 | Script::AddMethod("isbot", [](Game::scr_entref_t ent) 161 | { 162 | Game::Scr_AddInt(Game::svs->clients[ent].bot); 163 | }); 164 | 165 | Script::AddMethod("botaction", [](Game::scr_entref_t ent) 166 | { 167 | const char* action = Game::Scr_GetString(0); 168 | 169 | for (size_t i = 0; i < sizeof(bot_actions) / sizeof(BotAction_t); ++i) 170 | { 171 | if (strcmp(&action[1], bot_actions[i].action)) 172 | { 173 | continue; 174 | } 175 | 176 | if (action[0] == '+') 177 | { 178 | g_botai[ent].buttons |= bot_actions[i].key; 179 | } 180 | else 181 | { 182 | g_botai[ent].buttons &= ~(bot_actions[i].key); 183 | } 184 | 185 | return; 186 | } 187 | }); 188 | 189 | Script::AddMethod("botmovement", [](Game::scr_entref_t ent) 190 | { 191 | int forward = Game::Scr_GetInt(0); 192 | int right = Game::Scr_GetInt(1); 193 | 194 | forward = std::clamp(forward, -128, 127); 195 | right = std::clamp(right, -128, 127); 196 | 197 | g_botai[ent].forward = static_cast(forward); 198 | g_botai[ent].right = static_cast(right); 199 | }); 200 | 201 | Script::AddMethod("botstop", [](Game::scr_entref_t ent) 202 | { 203 | g_botai[ent].buttons = 0; 204 | g_botai[ent].forward = 0; 205 | g_botai[ent].right = 0; 206 | g_botai[ent].weapon = 1; 207 | }); 208 | } 209 | 210 | Bots::~Bots() 211 | { 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/Components/Modules/Bots.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define MAX_G_BOTAI_ENTRIES 64 3 | 4 | namespace Components 5 | { 6 | class Bots : public Component 7 | { 8 | public: 9 | Bots(); 10 | ~Bots(); 11 | private: 12 | typedef enum button_mask : unsigned int 13 | { 14 | KEY_FIRE = 1 << 0, 15 | KEY_UNK = 1 << 1, 16 | KEY_MELEE = 1 << 2, 17 | KEY_USE = 1 << 3, 18 | KEY_RELOAD = 1 << 4, 19 | KEY_USERELOAD = 1 << 5, 20 | KEY_LEANLEFT = 1 << 6, 21 | KEY_LEANRIGHT = 1 << 7, 22 | KEY_PRONE = 1 << 8, 23 | KEY_CROUCH = 1 << 9, 24 | KEY_GOSTAND = 1 << 10, 25 | KEY_UNK2 = 1 << 11, 26 | KEY_ADSMODE = 1 << 12, 27 | KEY_UNK3 = 1 << 13, 28 | KEY_UNK4 = 1 << 14, 29 | KEY_HOLDBREATH = 1 << 15, 30 | KEY_FRAG = 1 << 16, 31 | KEY_SMOKE = 1 << 17, 32 | KEY_UNK5 = 1 << 18, 33 | KEY_ADS = 1 << 19, 34 | KEY_UNK7 = 1 << 20, 35 | KEY_UNK8 = 1 << 21, 36 | KEY_MENU = 1 << 22, 37 | KEY_UNK10 = 1 << 23, 38 | KEY_UNK11 = 1 << 24, 39 | KEY_UNK12 = 1 << 25, 40 | KEY_UNK13 = 1 << 25, 41 | KEY_UNK14 = 1 << 26, 42 | KEY_UNK15 = 1 << 27, 43 | KEY_UNK16 = 1 << 28, 44 | KEY_UNK17 = 1 << 29, 45 | KEY_UNK9 = 1 << 30, 46 | KEY_UNK6 = 2147483648 47 | } button_mask; 48 | 49 | struct BotAction_t 50 | { 51 | const char* action; 52 | unsigned int key; 53 | }; 54 | 55 | struct botMovements 56 | { 57 | unsigned int buttons; 58 | int ping; 59 | char weapon; 60 | char forward; 61 | char right; 62 | }; 63 | 64 | static botMovements g_botai[]; 65 | static const BotAction_t bot_actions[]; 66 | 67 | static std::vector bot_names; 68 | 69 | static const char* ConnectString; 70 | 71 | static int BuildConnectString(char*, const char*, int, int); 72 | static void SV_BotUserMove_Func(Game::client_t*); 73 | static void SV_BotUserMove_Stub(); 74 | 75 | static void G_SelectWeaponIndex_Func(int, int); 76 | static void G_SelectWeaponIndex_Stub(); 77 | 78 | static void PlayerCmd_setSpawnWeapon_Func(Game::gentity_t*, int); 79 | static void PlayerCmd_setSpawnWeapon_Stub(); 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /src/Components/Modules/Flags.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | #include "Flags.hpp" 3 | 4 | namespace Components 5 | { 6 | std::vector Flags::EnabledFlags; 7 | 8 | bool Flags::HasFlag(const std::string& flag) 9 | { 10 | Flags::ParseFlags(); 11 | 12 | for (auto entry : Flags::EnabledFlags) 13 | { 14 | if (Utils::String::ToLower(entry) == Utils::String::ToLower(flag)) 15 | { 16 | return true; 17 | } 18 | } 19 | 20 | return false; 21 | } 22 | 23 | void Flags::ParseFlags() 24 | { 25 | static bool flagsParsed = false; 26 | if (flagsParsed) return; 27 | flagsParsed = true; 28 | 29 | int numArgs; 30 | LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &numArgs); 31 | 32 | if (argv) 33 | { 34 | for (int i = 0; i < numArgs; ++i) 35 | { 36 | std::wstring wFlag(argv[i]); 37 | if (wFlag[0] == L'-') 38 | { 39 | Flags::EnabledFlags.push_back(std::string(++wFlag.begin(), wFlag.end())); 40 | } 41 | } 42 | 43 | LocalFree(argv); 44 | } 45 | } 46 | 47 | Flags::Flags() 48 | { 49 | Flags::ParseFlags(); 50 | } 51 | 52 | Flags::~Flags() 53 | { 54 | Flags::EnabledFlags.clear(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Components/Modules/Flags.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Components 4 | { 5 | class Flags : public Component 6 | { 7 | public: 8 | Flags(); 9 | ~Flags(); 10 | 11 | static bool HasFlag(const std::string& flag); 12 | 13 | private: 14 | static std::vector EnabledFlags; 15 | 16 | static void ParseFlags(); 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/Components/Modules/HelloWorld.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | #include "HelloWorld.hpp" 3 | 4 | namespace Components 5 | { 6 | HelloWorld::HelloWorld() 7 | { 8 | //MessageBoxA(nullptr, Utils::String::VA("%d", Game::svs), "DEBUG", 0); 9 | } 10 | 11 | HelloWorld::~HelloWorld() 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Components/Modules/HelloWorld.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Components 4 | { 5 | class HelloWorld : public Component 6 | { 7 | public: 8 | HelloWorld(); 9 | ~HelloWorld(); 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/Components/Modules/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | #include "Logger.hpp" 3 | #include "Flags.hpp" 4 | 5 | namespace Components 6 | { 7 | bool Logger::IsConsoleReady() 8 | { 9 | return true; 10 | } 11 | 12 | void Logger::PrintStub(int channel, const char* message, ...) 13 | { 14 | return Logger::MessagePrint(channel, Logger::Format(&message)); 15 | } 16 | 17 | void Logger::Print(const char* message, ...) 18 | { 19 | return Logger::MessagePrint(0, Logger::Format(&message)); 20 | } 21 | 22 | void Logger::Print(int channel, const char* message, ...) 23 | { 24 | return Logger::MessagePrint(channel, Logger::Format(&message)); 25 | } 26 | 27 | void Logger::MessagePrint([[maybe_unused]] int channel, [[maybe_unused]] const std::string& message) 28 | { 29 | if (Flags::HasFlag("stdout") || Loader::IsPerformingUnitTests()) 30 | { 31 | printf("%s", message.data()); 32 | fflush(stdout); 33 | return; 34 | } 35 | 36 | /*if (!Logger::IsConsoleReady()) 37 | { 38 | OutputDebugStringA(message.data()); 39 | } 40 | 41 | if (!Game::Sys_IsMainThread()) 42 | { 43 | Logger::EnqueueMessage(message); 44 | } 45 | else 46 | { 47 | Game::Com_PrintMessage(channel, message.data(), 0); 48 | }*/ 49 | } 50 | 51 | void Logger::ErrorPrint([[maybe_unused]] int error, [[maybe_unused]] const std::string& message) 52 | { 53 | #ifdef DEBUG 54 | if (IsDebuggerPresent()) __debugbreak(); 55 | #endif 56 | 57 | //Game::Com_Error(error, "%s", message.data()); 58 | } 59 | 60 | void Logger::Error(int error, const char* message, ...) 61 | { 62 | return Logger::ErrorPrint(error, Logger::Format(&message)); 63 | } 64 | 65 | void Logger::Error(const char* message, ...) 66 | { 67 | return Logger::ErrorPrint(0, Logger::Format(&message)); 68 | } 69 | 70 | void Logger::SoftError(const char* message, ...) 71 | { 72 | return Logger::ErrorPrint(2, Logger::Format(&message)); 73 | } 74 | 75 | std::string Logger::Format(const char** message) 76 | { 77 | const size_t bufferSize = 0x10000; 78 | Utils::Memory::Allocator allocator; 79 | char* buffer = allocator.allocateArray(bufferSize); 80 | 81 | va_list ap = reinterpret_cast(const_cast(&message[1])); 82 | //va_start(ap, *message); 83 | _vsnprintf_s(buffer, bufferSize, bufferSize, *message, ap); 84 | va_end(ap); 85 | 86 | return buffer; 87 | } 88 | 89 | Logger::Logger() 90 | { 91 | } 92 | 93 | Logger::~Logger() 94 | { 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Components/Modules/Logger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Components 4 | { 5 | class Logger : public Component 6 | { 7 | public: 8 | Logger(); 9 | ~Logger(); 10 | 11 | static void MessagePrint(int channel, const std::string& message); 12 | static void Print(int channel, const char* message, ...); 13 | static void Print(const char* message, ...); 14 | static void ErrorPrint(int error, const std::string& message); 15 | static void Error(const char* message, ...); 16 | static void Error(int error, const char* message, ...); 17 | static void SoftError(const char* message, ...); 18 | static bool IsConsoleReady(); 19 | 20 | static void PrintStub(int channel, const char* message, ...); 21 | 22 | private: 23 | 24 | static std::string Format(const char** message); 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /src/Components/Modules/Player.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | #include "Player.hpp" 3 | #include "Scheduler.hpp" 4 | 5 | namespace Components 6 | { 7 | Game::cvar_t* Player::g_playerEjection; 8 | Game::cvar_t* Player::g_playerCollision; 9 | 10 | int Player::StuckInClient_Func(Game::gentity_t* ent) 11 | { 12 | if (!g_playerEjection->current.boolean) 13 | return 0; 14 | 15 | return Game::StuckInClient(ent); 16 | } 17 | 18 | __declspec(naked) void Player::StuckInClient_Stub() 19 | { 20 | __asm 21 | { 22 | push eax; 23 | call StuckInClient_Func; 24 | add esp, 4; 25 | retn; 26 | } 27 | } 28 | 29 | void Player::CM_Trace_Func(float* a1, float* a2, float* a3, int a4, float* a5, int a6, int contentmask) 30 | { 31 | if (!g_playerCollision->current.boolean) 32 | contentmask &= ~0x2000000; // remove the CONTENT_BODY bit 33 | 34 | Game::CM_Trace(a1, a2, a3, a4, a5, a6, contentmask); 35 | } 36 | 37 | __declspec(naked) void Player::CM_Trace_Stub() 38 | { 39 | __asm 40 | { 41 | push ecx; 42 | push edx; 43 | push eax; 44 | call CM_Trace_Func; 45 | add esp, 0xC; 46 | 47 | push 0x41D93E; 48 | retn; 49 | } 50 | } 51 | 52 | Player::Player() 53 | { 54 | Scheduler::OnReady([]() 55 | { 56 | g_playerEjection = Game::Dvar_RegisterBool("g_playerEjection", true, Game::CVAR_FLAG_ARCHIVE); 57 | g_playerCollision = Game::Dvar_RegisterBool("g_playerCollision", true, Game::CVAR_FLAG_ARCHIVE); 58 | }); 59 | 60 | Utils::Hook(0x5011D3, StuckInClient_Stub, HOOK_CALL).install()->quick(); 61 | 62 | Utils::Hook(0x41D939, CM_Trace_Stub, HOOK_JUMP).install()->quick(); 63 | } 64 | 65 | Player::~Player() 66 | { 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Components/Modules/Player.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Components 4 | { 5 | class Player : public Component 6 | { 7 | public: 8 | Player(); 9 | ~Player(); 10 | 11 | static Game::cvar_t* g_playerEjection; 12 | static Game::cvar_t* g_playerCollision; 13 | private: 14 | static int StuckInClient_Func(Game::gentity_t* ent); 15 | static void StuckInClient_Stub(); 16 | static void CM_Trace_Func(float*, float*, float*, int, float*, int, int); 17 | static void CM_Trace_Stub(); 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/Components/Modules/Scheduler.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | #include "Scheduler.hpp" 3 | 4 | namespace Components 5 | { 6 | bool Scheduler::AsyncTerminate; 7 | std::thread Scheduler::AsyncThread; 8 | 9 | bool Scheduler::ReadyPassed = false; 10 | Utils::Signal Scheduler::ReadySignal; 11 | Utils::Signal Scheduler::ShutdownSignal; 12 | 13 | Utils::Signal Scheduler::FrameSignal; 14 | Utils::Signal Scheduler::FrameOnceSignal; 15 | std::vector Scheduler::DelayedSlots; 16 | 17 | Utils::Signal Scheduler::AsyncFrameSignal; 18 | Utils::Signal Scheduler::AsyncFrameOnceSignal; 19 | 20 | void Scheduler::Once(Utils::Slot callback, bool clientOnly) 21 | { 22 | if (clientOnly && Game::IsDedicated()) return; 23 | Scheduler::FrameOnceSignal.connect(callback); 24 | } 25 | 26 | void Scheduler::OnShutdown(Utils::Slot callback) 27 | { 28 | Scheduler::ShutdownSignal.connect(callback); 29 | } 30 | 31 | void Scheduler::OnFrame(Utils::Slot callback, bool clientOnly) 32 | { 33 | if (clientOnly && Game::IsDedicated()) return; 34 | Scheduler::FrameSignal.connect(callback); 35 | } 36 | 37 | void Scheduler::OnReady(Utils::Slot callback, bool clientOnly) 38 | { 39 | if (clientOnly && Game::IsDedicated()) return; 40 | if (Scheduler::ReadyPassed) Scheduler::Once(callback); 41 | else Scheduler::ReadySignal.connect(callback); 42 | } 43 | 44 | void Scheduler::ReadyHandler() 45 | { 46 | if (!*Game::isDvarSystemActive) 47 | { 48 | Scheduler::Once(Scheduler::ReadyHandler); 49 | } 50 | else 51 | { 52 | Scheduler::ReadyPassed = true; 53 | Scheduler::ReadySignal(); 54 | Scheduler::ReadySignal.clear(); 55 | } 56 | } 57 | 58 | void Scheduler::FrameHandler([[maybe_unused]]bool isRenderer) 59 | { 60 | Scheduler::DelaySignal(); 61 | Scheduler::FrameSignal(); 62 | 63 | Utils::Signal copy(Scheduler::FrameOnceSignal); 64 | Scheduler::FrameOnceSignal.clear(); 65 | copy(); 66 | } 67 | 68 | void Scheduler::OnDelay(Utils::Slot callback, std::chrono::nanoseconds delay, bool clientOnly) 69 | { 70 | if (clientOnly && Game::IsDedicated()) return; 71 | 72 | Scheduler::DelayedSlot slot; 73 | slot.callback = callback; 74 | slot.delay = delay; 75 | 76 | Scheduler::DelayedSlots.push_back(slot); 77 | } 78 | 79 | void Scheduler::DelaySignal() 80 | { 81 | Utils::Signal signal; 82 | 83 | for (auto i = Scheduler::DelayedSlots.begin(); i != Scheduler::DelayedSlots.end();) 84 | { 85 | if (i->interval.elapsed(i->delay)) 86 | { 87 | signal.connect(i->callback); 88 | i = Scheduler::DelayedSlots.erase(i); 89 | continue; 90 | } 91 | 92 | ++i; 93 | } 94 | 95 | signal(); 96 | } 97 | 98 | void Scheduler::ShutdownStub(const char* str) 99 | { 100 | Scheduler::ShutdownSignal(); 101 | 102 | Game::Com_Printf(str); 103 | } 104 | 105 | void Scheduler::OnFrameAsync(Utils::Slot callback) 106 | { 107 | Scheduler::AsyncFrameSignal.connect(callback); 108 | } 109 | 110 | void Scheduler::OnceAsync(Utils::Slot callback) 111 | { 112 | Scheduler::AsyncFrameOnceSignal.connect(callback); 113 | } 114 | 115 | void Scheduler::GameFrameStub() 116 | { 117 | FrameHandler(); 118 | 119 | Game::Com_DedicatedModified(); 120 | } 121 | 122 | Scheduler::Scheduler() 123 | { 124 | Scheduler::ReadyPassed = false; 125 | Scheduler::Once(Scheduler::ReadyHandler); 126 | 127 | Utils::Hook(0x4326C5, Scheduler::ShutdownStub, HOOK_CALL).install()->quick(); 128 | Utils::Hook(0x43503D, Scheduler::GameFrameStub, HOOK_CALL).install()->quick(); 129 | 130 | if (!Loader::IsPerformingUnitTests()) 131 | { 132 | Scheduler::AsyncTerminate = false; 133 | Scheduler::AsyncThread = std::thread([]() 134 | { 135 | while (!Scheduler::AsyncTerminate) 136 | { 137 | Scheduler::AsyncFrameSignal(); 138 | 139 | Utils::Signal copy(Scheduler::AsyncFrameOnceSignal); 140 | Scheduler::AsyncFrameOnceSignal.clear(); 141 | copy(); 142 | 143 | std::this_thread::sleep_for(16ms); 144 | } 145 | }); 146 | } 147 | } 148 | 149 | Scheduler::~Scheduler() 150 | { 151 | Scheduler::ReadySignal.clear(); 152 | Scheduler::ShutdownSignal.clear(); 153 | 154 | Scheduler::FrameSignal.clear(); 155 | Scheduler::FrameOnceSignal.clear(); 156 | Scheduler::DelayedSlots.clear(); 157 | 158 | Scheduler::AsyncFrameSignal.clear(); 159 | Scheduler::AsyncFrameOnceSignal.clear(); 160 | 161 | Scheduler::ReadyPassed = false; 162 | } 163 | 164 | void Scheduler::preDestroy() 165 | { 166 | Scheduler::AsyncTerminate = true; 167 | if (Scheduler::AsyncThread.joinable()) 168 | { 169 | Scheduler::AsyncThread.join(); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/Components/Modules/Scheduler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Components 4 | { 5 | class Scheduler : public Component 6 | { 7 | public: 8 | typedef void(Callback)(); 9 | 10 | Scheduler(); 11 | ~Scheduler(); 12 | 13 | void preDestroy() override; 14 | 15 | static void OnShutdown(Utils::Slot callback); 16 | static void OnFrame(Utils::Slot callback, bool clientOnly = false); 17 | static void OnReady(Utils::Slot callback, bool clientOnly = false); 18 | static void Once(Utils::Slot callback, bool clientOnly = false); 19 | static void OnDelay(Utils::Slot callback, std::chrono::nanoseconds delay, bool clientOnly = false); 20 | 21 | static void OnFrameAsync(Utils::Slot callback); 22 | static void OnceAsync(Utils::Slot callback); 23 | 24 | private: 25 | class DelayedSlot 26 | { 27 | public: 28 | std::chrono::nanoseconds delay; 29 | Utils::Time::Interval interval; 30 | Utils::Slot callback; 31 | }; 32 | 33 | static bool AsyncTerminate; 34 | static std::thread AsyncThread; 35 | 36 | static Utils::Signal FrameSignal; 37 | static Utils::Signal FrameOnceSignal; 38 | static std::vector DelayedSlots; 39 | 40 | static bool ReadyPassed; 41 | static Utils::Signal ReadySignal; 42 | static Utils::Signal ShutdownSignal; 43 | 44 | static Utils::Signal AsyncFrameSignal; 45 | static Utils::Signal AsyncFrameOnceSignal; 46 | 47 | static void ReadyHandler(); 48 | static void DelaySignal(); 49 | 50 | static void ShutdownStub(const char*); 51 | 52 | static void GameFrameStub(); 53 | 54 | static void FrameHandler(bool = 0); 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /src/Components/Modules/Script.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | #include "Script.hpp" 3 | 4 | namespace Components 5 | { 6 | std::unordered_map Script::CustomScrFunctions; 7 | std::unordered_map Script::CustomScrMethods; 8 | std::vector Script::CustomScrHandles; 9 | 10 | void Script::AddFunction(const char* name, Game::xfunction_t func, int type) 11 | { 12 | Game::scr_function_t toAdd; 13 | toAdd.call = func; 14 | toAdd.developer = type; 15 | 16 | CustomScrFunctions.insert_or_assign(Utils::String::ToLower(name), toAdd); 17 | } 18 | 19 | void Script::AddMethod(const char* name, Game::xmethod_t func, int type) 20 | { 21 | Game::scr_method_t toAdd; 22 | toAdd.call = func; 23 | toAdd.developer = type; 24 | 25 | CustomScrMethods.insert_or_assign(Utils::String::ToLower(name), toAdd); 26 | } 27 | 28 | Game::xmethod_t Script::Player_GetMethod_Hook(const char** name) 29 | { 30 | auto got = CustomScrMethods.find(*name); 31 | 32 | if (got == CustomScrMethods.end()) 33 | return Game::Player_GetMethod(name); 34 | 35 | return got->second.call; 36 | } 37 | 38 | Game::xfunction_t Script::Scr_GetFunction_Hook(const char** name, int* isDev) 39 | { 40 | auto got = CustomScrFunctions.find(*name); 41 | 42 | if (got == CustomScrFunctions.end()) 43 | return Game::Scr_GetFunction(name, isDev); 44 | 45 | *isDev = got->second.developer; 46 | return got->second.call; 47 | } 48 | 49 | void Script::GScr_LoadGameTypeScript_Hook() 50 | { 51 | CustomScrHandles.clear(); 52 | 53 | Game::FS_ForEachFile("scripts", "gsc", [](char* filename) 54 | { 55 | std::string file = filename; 56 | std::string label = "init"; 57 | 58 | file = "scripts/" + file; 59 | 60 | if (Utils::String::EndsWith(file, ".gsc")) 61 | file = file.substr(0, file.size() - 4); 62 | 63 | Game::Com_Printf("Loading script %s.gsc...\n", file.data()); 64 | 65 | if (!Game::Scr_LoadScript(file.data())) 66 | { 67 | Game::Com_Printf("Script %s encountered an error while loading. (doesn't exist?)", file.data()); 68 | return; 69 | } 70 | 71 | Game::Com_Printf("Script %s.gsc loaded successfully.\n", file.data()); 72 | Game::Com_Printf("Finding script handle %s::%s...\n", file.data(), label.data()); 73 | 74 | unsigned int handle = Game::Scr_GetFunctionHandle(file.data(), label.data()); 75 | if (!handle) 76 | { 77 | Game::Com_Printf("Script handle %s::%s couldn't be loaded. (file with no entry point?)\n", file.data(), label.data()); 78 | return; 79 | } 80 | 81 | CustomScrHandles.push_back(handle); 82 | Game::Com_Printf("Script handle %s::%s loaded successfully.\n", file.data(), label.data()); 83 | }); 84 | 85 | Game::GScr_LoadGameTypeScript(); 86 | } 87 | 88 | void Script::G_LoadStructs_Hook() 89 | { 90 | for (auto handle : CustomScrHandles) 91 | { 92 | Game::RemoveRefToObject(Game::Scr_ExecThread(handle, 0)); 93 | } 94 | 95 | Game::G_LoadStructs(); 96 | } 97 | 98 | Script::Script() 99 | { 100 | // custom gsc calls 101 | Utils::Hook(0x46E9CB, Player_GetMethod_Hook, HOOK_CALL).install()->quick(); 102 | Utils::Hook(0x46E7BF, Scr_GetFunction_Hook, HOOK_CALL).install()->quick(); 103 | 104 | // load custom scripts 105 | Utils::Hook(0x4FC75F, G_LoadStructs_Hook, HOOK_CALL).install()->quick(); 106 | Utils::Hook(0x5043FA, GScr_LoadGameTypeScript_Hook, HOOK_CALL).install()->quick(); 107 | } 108 | 109 | Script::~Script() 110 | { 111 | CustomScrFunctions.clear(); 112 | CustomScrMethods.clear(); 113 | CustomScrHandles.clear(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Components/Modules/Script.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Components 4 | { 5 | class Script : public Component 6 | { 7 | public: 8 | static void AddFunction(const char*, Game::xfunction_t, int = 0); 9 | static void AddMethod(const char*, Game::xmethod_t, int = 0); 10 | Script(); 11 | ~Script(); 12 | private: 13 | static std::unordered_map CustomScrFunctions; 14 | static std::unordered_map CustomScrMethods; 15 | static std::vector CustomScrHandles; 16 | 17 | static Game::xmethod_t Player_GetMethod_Hook(const char**); 18 | static Game::xfunction_t Scr_GetFunction_Hook(const char**, int*); 19 | 20 | static void GScr_LoadGameTypeScript_Hook(); 21 | static void G_LoadStructs_Hook(); 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/Game/Game.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | 3 | namespace Game 4 | { 5 | clientStatic_t* cls; 6 | serverStatic_t* svs; 7 | server_t* sv; 8 | 9 | scrCompilePub_t* gScrCompilePub; 10 | scrVarPub_t* scrVarPub; 11 | scrVmPub_t* scrVmPub; 12 | 13 | cgs_t* cgsArray; 14 | cg_t* cgArray; 15 | 16 | centity_s* cg_entitiesArray; 17 | 18 | WeaponDef_t** BG_WeaponNames; 19 | 20 | gentity_t* g_entities; 21 | gclient_t* g_clients; 22 | 23 | bgs_s* level_bgs; 24 | 25 | level_locals_t* level; 26 | 27 | stringIndex_t* scr_const; 28 | 29 | bgs_s** bgs_ptr; 30 | 31 | Scr_LoadScript_t* Scr_LoadScript; 32 | Scr_GetFunction_t* Scr_GetFunction; 33 | Player_GetMethod_t* Player_GetMethod; 34 | GScr_LoadGameTypeScript_t* GScr_LoadGameTypeScript; 35 | G_LoadStructs_t* G_LoadStructs; 36 | Sys_Milliseconds_t* Sys_Milliseconds; 37 | Com_Printf_t* Com_Printf; 38 | Com_DedicatedModified_t* Com_DedicatedModified; 39 | Dvar_RegisterBool_t* Dvar_RegisterBool; 40 | Cmd_AddCommand_t* Cmd_AddCommand; 41 | Cmd_FindCommand_t* Cmd_FindCommand; 42 | 43 | 44 | char* isDvarSystemActive; 45 | 46 | bool IsDedicated() 47 | { 48 | return false; 49 | } 50 | 51 | void Init(GAMEEXE) 52 | { 53 | Player_GetMethod = ASSIGN(Player_GetMethod_t*, 0x52E050); 54 | Scr_GetFunction = ASSIGN(Scr_GetFunction_t*, 0x50D280); 55 | Scr_LoadScript = ASSIGN(Scr_LoadScript_t*, 0x474D80); 56 | GScr_LoadGameTypeScript = ASSIGN(GScr_LoadGameTypeScript_t*, 0x503F90); 57 | G_LoadStructs = ASSIGN(G_LoadStructs_t*, 0x5118A0); 58 | Sys_Milliseconds = ASSIGN(Sys_Milliseconds_t*, 0x435200); 59 | Com_Printf = ASSIGN(Com_Printf_t*, 0x431EE0); 60 | Com_DedicatedModified = ASSIGN(Com_DedicatedModified_t*, 0x434DC0); 61 | Dvar_RegisterBool = ASSIGN(Dvar_RegisterBool_t*, 0x438040); 62 | Cmd_AddCommand = ASSIGN(Cmd_AddCommand_t*, 0x4212F0); 63 | Cmd_FindCommand = ASSIGN(Cmd_FindCommand_t*, 0x421290); 64 | 65 | 66 | isDvarSystemActive = ASSIGN(char*, 0xC5C5C8); 67 | 68 | cls = ASSIGN(clientStatic_t*, 0x68A408); 69 | svs = ASSIGN(serverStatic_t*, 0xD35700); 70 | sv = ASSIGN(server_t*, 0xCD6180); 71 | 72 | gScrCompilePub = ASSIGN(scrCompilePub_t*, 0xD77790); 73 | scrVarPub = ASSIGN(scrVarPub_t*, 0xF08F88); 74 | scrVmPub = ASSIGN(scrVmPub_t*, 0xF4B900); 75 | 76 | cgsArray = ASSIGN(cgs_t*, 0x14C3700); 77 | cgArray = ASSIGN(cg_t*, 0x14EE080); 78 | 79 | cg_entitiesArray = ASSIGN(centity_s*, 0x15E2A80); 80 | 81 | BG_WeaponNames = ASSIGN(WeaponDef_t**, 0x1728200); 82 | 83 | g_entities = ASSIGN(gentity_t*, 0x1744380); 84 | g_clients = ASSIGN(gclient_t*, 0x1897E80); 85 | 86 | level_bgs = ASSIGN(bgs_s*, 0x17D03D0); 87 | 88 | level = ASSIGN(level_locals_t*, 0x193A780); 89 | 90 | scr_const = ASSIGN(stringIndex_t*, 0x1943920); 91 | 92 | bgs_ptr = ASSIGN(bgs_s**, 0x19A1C78); 93 | } 94 | 95 | unsigned int Scr_GetFunctionHandle(const char* filename, const char* funcHandle) 96 | { 97 | int func_loc = 0x474950; 98 | unsigned int answer; 99 | 100 | __asm 101 | { 102 | push funcHandle; 103 | mov eax, filename; 104 | call func_loc; 105 | add esp, 4; 106 | mov answer, eax; 107 | } 108 | 109 | return answer; 110 | } 111 | 112 | __int16 Scr_ExecThread(int handle, int numParam) 113 | { 114 | int func_loc = 0x482080; 115 | __int16 answer; 116 | 117 | __asm 118 | { 119 | push numParam; 120 | mov eax, handle; 121 | call func_loc; 122 | add esp, 4; 123 | mov answer, ax; 124 | } 125 | 126 | return answer; 127 | } 128 | 129 | void RemoveRefToObject(int obj) 130 | { 131 | int func_loc = 0x479660; 132 | 133 | __asm 134 | { 135 | mov eax, obj; 136 | call func_loc; 137 | } 138 | } 139 | 140 | int FS_ForEachFile(const char* folder, const char* extention, void(callback)(char*)) 141 | { 142 | char buff[0x4000]; 143 | int numberFiles = FS_GetFileList(folder, extention, 1, buff, 0x4000); 144 | int cursor = 0; 145 | 146 | for (int i = 0; i < numberFiles; i++) 147 | { 148 | callback(buff + cursor); 149 | 150 | cursor += strlen(buff + cursor) + 1; 151 | } 152 | 153 | return numberFiles; 154 | } 155 | 156 | int FS_GetFileList(const char* folder, const char* ext, int flags, char* buff, size_t _size) 157 | { 158 | int func_loc = 0x424230; 159 | int answer; 160 | 161 | __asm 162 | { 163 | push _size; 164 | push buff; 165 | push flags; 166 | push ext; 167 | mov eax, folder; 168 | call func_loc; 169 | add esp, 0x10; 170 | mov answer, eax; 171 | } 172 | 173 | return answer; 174 | } 175 | 176 | const char* Scr_GetString(unsigned int slot) 177 | { 178 | int func_loc = 0x482FF0; 179 | const char* answer; 180 | 181 | __asm 182 | { 183 | mov eax, slot; 184 | call func_loc; 185 | mov answer, eax; 186 | } 187 | 188 | return answer; 189 | } 190 | 191 | int Scr_GetInt(unsigned int slot) 192 | { 193 | int func_loc = 0x482B80; 194 | int answer; 195 | 196 | __asm 197 | { 198 | mov eax, slot; 199 | call func_loc; 200 | mov answer, eax; 201 | } 202 | 203 | return answer; 204 | } 205 | 206 | void Scr_AddInt(int num) 207 | { 208 | int func_loc = 0x483580; 209 | 210 | __asm 211 | { 212 | push num; 213 | call func_loc; 214 | add esp, 4; 215 | } 216 | } 217 | 218 | void G_SelectWeaponIndex(int wpIdx, int clNum) 219 | { 220 | int func_loc = 0x5282E0; 221 | 222 | __asm 223 | { 224 | mov esi, clNum; 225 | mov eax, wpIdx; 226 | call func_loc; 227 | } 228 | } 229 | 230 | void SV_ClientThink(Game::usercmd_s* cmd, Game::client_t* client) 231 | { 232 | int func_loc = 0x456010; 233 | 234 | __asm 235 | { 236 | mov ecx, client; 237 | mov eax, cmd; 238 | call func_loc; 239 | } 240 | } 241 | 242 | void SV_DropClient(Game::client_t* client, const char* reason) 243 | { 244 | int func_loc = 0x454750; 245 | 246 | __asm 247 | { 248 | push reason; 249 | mov eax, client; 250 | call func_loc; 251 | add esp, 4; 252 | } 253 | } 254 | 255 | void CM_Trace(float* a1, float* a2, float* a3, int a4, float* a5, int a6, int a7) 256 | { 257 | int func_loc = 0x41D120; 258 | 259 | __asm 260 | { 261 | push a7; 262 | push a6; 263 | push a5; 264 | push a4; 265 | mov ecx, a3; 266 | mov edx, a2; 267 | mov eax, a1; 268 | call func_loc; 269 | add esp, 0x10; 270 | } 271 | } 272 | 273 | int StuckInClient(Game::gentity_t* ent) 274 | { 275 | int func_loc = 0x5009F0; 276 | int answer; 277 | 278 | __asm 279 | { 280 | mov eax, ent; 281 | call func_loc; 282 | mov answer, eax; 283 | } 284 | 285 | return answer; 286 | } 287 | } 288 | 289 | -------------------------------------------------------------------------------- /src/Game/Game.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SELECT(addr) (addr) 4 | #define ASSIGN(type, addr) reinterpret_cast(SELECT(addr)) 5 | 6 | namespace Game 7 | { 8 | void Init(GAMEEXE); 9 | bool IsDedicated(); 10 | 11 | extern char* isDvarSystemActive; 12 | 13 | extern clientStatic_t* cls; 14 | extern serverStatic_t* svs; 15 | extern server_t* sv; 16 | 17 | extern scrCompilePub_t* gScrCompilePub; 18 | extern scrVarPub_t* scrVarPub; 19 | extern scrVmPub_t* scrVmPub; 20 | 21 | extern cgs_t* cgsArray; 22 | extern cg_t* cgArray; 23 | 24 | extern centity_s* cg_entitiesArray; 25 | 26 | extern WeaponDef_t** BG_WeaponNames; 27 | 28 | extern gentity_t* g_entities; 29 | extern gclient_t* g_clients; 30 | 31 | extern bgs_s* level_bgs; 32 | 33 | extern level_locals_t* level; 34 | 35 | extern stringIndex_t* scr_const; 36 | 37 | extern bgs_s** bgs_ptr; 38 | 39 | typedef int (Scr_LoadScript_t)(char*); 40 | extern Scr_LoadScript_t* Scr_LoadScript; 41 | 42 | typedef void (GScr_LoadGameTypeScript_t)(); 43 | extern GScr_LoadGameTypeScript_t* GScr_LoadGameTypeScript; 44 | 45 | typedef void (G_LoadStructs_t)(); 46 | extern G_LoadStructs_t* G_LoadStructs; 47 | 48 | typedef int (Sys_Milliseconds_t)(); 49 | extern Sys_Milliseconds_t* Sys_Milliseconds; 50 | 51 | typedef void (Com_DedicatedModified_t)(); 52 | extern Com_DedicatedModified_t* Com_DedicatedModified; 53 | 54 | typedef void(Com_Printf_t)(const char *, ...); 55 | extern Com_Printf_t* Com_Printf; 56 | 57 | typedef cvar_t*(Dvar_RegisterBool_t)(const char *, int, int); 58 | extern Dvar_RegisterBool_t* Dvar_RegisterBool; 59 | 60 | extern unsigned int Scr_GetFunctionHandle(const char*, const char*); 61 | extern __int16 Scr_ExecThread(int, int); 62 | extern void RemoveRefToObject(int); 63 | 64 | typedef Game::xmethod_t (Player_GetMethod_t)(const char**); 65 | extern Player_GetMethod_t* Player_GetMethod; 66 | 67 | typedef Game::xfunction_t (Scr_GetFunction_t)(const char**, int*); 68 | extern Scr_GetFunction_t* Scr_GetFunction; 69 | 70 | typedef void (Cmd_AddCommand_t)(const char*, Game::xcommand_t); 71 | extern Cmd_AddCommand_t* Cmd_AddCommand; 72 | 73 | typedef void (Cmd_FindCommand_t)(const char*); 74 | extern Cmd_FindCommand_t* Cmd_FindCommand; 75 | 76 | //VariableValue *__cdecl sub_483580(union VariableUnion a1) addint 77 | //int __usercall sub_483770@(char *a2@) addstring 78 | //VariableValue *__cdecl sub_4835D0(float a1) addfloat 79 | //_DWORD *__usercall Scr_AddVector@(_DWORD *a2@) 4838B0 80 | 81 | //double __usercall sub_482DB0@(unsigned int a1@) getfloat 82 | //char __usercall sub_483160@(unsigned int a1@, _DWORD *a2@) get vector 83 | 84 | extern int FS_GetFileList(const char*, const char*, int, char*, size_t); 85 | extern int FS_ForEachFile(const char*, const char*, void(char*)); 86 | 87 | extern const char* Scr_GetString(unsigned int); 88 | extern int Scr_GetInt(unsigned int); 89 | extern void Scr_AddInt(int); 90 | extern void G_SelectWeaponIndex(int, int); 91 | extern void SV_ClientThink(Game::usercmd_s*, Game::client_t*); 92 | extern void SV_DropClient(Game::client_t*, const char*); 93 | extern void CM_Trace(float*, float*, float*, int, float*, int, int); 94 | 95 | extern int StuckInClient(Game::gentity_t*); 96 | } 97 | -------------------------------------------------------------------------------- /src/Game/Structs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Game 4 | { 5 | typedef float vec_t; 6 | typedef vec_t vec3_t[3]; 7 | typedef vec_t vec2_t[2]; 8 | typedef vec_t vec4_t[4]; 9 | typedef vec_t vec5_t[5]; 10 | typedef int scr_entref_t; 11 | 12 | struct turretInfo_s 13 | { 14 | int inuse; 15 | int flags; 16 | int fireTime; 17 | vec2_t arcmin; 18 | vec2_t arcmax; 19 | float dropPitch; 20 | int stance; 21 | int prevStance; 22 | int fireSndDelay; 23 | vec3_t userOrigin; 24 | float playerSpread; 25 | int triggerDown; 26 | char fireSnd; 27 | char fireSndPlayer; 28 | char stopSnd; 29 | char stopSndPlayer; 30 | }; 31 | 32 | typedef enum 33 | { 34 | PLAYERVIEWLOCK_NONE = 0x0, 35 | PLAYERVIEWLOCK_FULL = 0x1, 36 | PLAYERVIEWLOCK_WEAPONJITTER = 0x2, 37 | PLAYERVIEWLOCKCOUNT = 0x3, 38 | } ViewLockTypes_t; 39 | 40 | typedef struct 41 | { 42 | float yaw; 43 | int timer; 44 | int transIndex; 45 | int flags; 46 | } mantleState_t; 47 | 48 | typedef enum 49 | { 50 | OBJST_EMPTY = 0x0, 51 | OBJST_ACTIVE = 0x1, 52 | OBJST_INVISIBLE = 0x2, 53 | OBJST_DONE = 0x3, 54 | OBJST_CURRENT = 0x4, 55 | OBJST_FAILED = 0x5, 56 | OBJST_NUMSTATES = 0x6, 57 | } objectiveState_t; 58 | 59 | typedef struct objective_s 60 | { 61 | objectiveState_t state; 62 | vec3_t origin; 63 | int entNum; 64 | int teamNum; 65 | int icon; 66 | } objective_t; 67 | 68 | typedef enum 69 | { 70 | HE_TYPE_FREE = 0x0, 71 | HE_TYPE_TEXT = 0x1, 72 | HE_TYPE_VALUE = 0x2, 73 | HE_TYPE_PLAYERNAME = 0x3, 74 | HE_TYPE_MAPNAME = 0x4, 75 | HE_TYPE_GAMETYPE = 0x5, 76 | HE_TYPE_MATERIAL = 0x6, 77 | HE_TYPE_TIMER_DOWN = 0x7, 78 | HE_TYPE_TIMER_UP = 0x8, 79 | HE_TYPE_TENTHS_TIMER_DOWN = 0x9, 80 | HE_TYPE_TENTHS_TIMER_UP = 0xA, 81 | HE_TYPE_CLOCK_DOWN = 0xB, 82 | HE_TYPE_CLOCK_UP = 0xC, 83 | HE_TYPE_WAYPOINT = 0xD, 84 | HE_TYPE_COUNT = 0xE, 85 | } he_type_t; 86 | 87 | typedef struct 88 | { 89 | char r; 90 | char g; 91 | char b; 92 | char a; 93 | } hudelem_colorsplit_t; 94 | 95 | typedef union 96 | { 97 | hudelem_colorsplit_t split; 98 | int rgba; 99 | } hudelem_color_t; 100 | 101 | typedef struct hudelem_s 102 | { 103 | he_type_t type; 104 | float x; 105 | float y; 106 | float z; 107 | float fontScale; 108 | int font; 109 | int alignOrg; 110 | int alignScreen; 111 | hudelem_color_t color; 112 | hudelem_color_t fromColor; 113 | int fadeStartTime; 114 | int fadeTime; 115 | int label; 116 | int width; 117 | int height; 118 | int materialIndex; 119 | int fromWidth; 120 | int fromHeight; 121 | int scaleStartTime; 122 | int scaleTime; 123 | float fromX; 124 | float fromY; 125 | int fromAlignOrg; 126 | int fromAlignScreen; 127 | int moveStartTime; 128 | int moveTime; 129 | int time; 130 | int duration; 131 | float value; 132 | int text; 133 | float sort; 134 | hudelem_color_t glowColor; 135 | } hudelem_t; 136 | 137 | typedef struct hudElemState_s 138 | { 139 | hudelem_t current[31]; 140 | hudelem_t archival[31]; 141 | } hudElemState_t; 142 | 143 | typedef struct playerState_s 144 | { 145 | int commandTime; 146 | int pm_type; 147 | int bobCycle; 148 | int pm_flags; 149 | int pm_time; 150 | vec3_t origin; 151 | vec3_t velocity; 152 | vec2_t oldVelocity; 153 | int weaponTime; 154 | int weaponDelay; 155 | int grenadeTimeLeft; 156 | int throwBackGrenadeOwner; 157 | int throwBackGrenadeTimeLeft; 158 | int gravity; 159 | float leanf; 160 | int speed; 161 | vec3_t delta_angles; 162 | int groundEntityNum; 163 | vec3_t vLadderVec; 164 | int jumpTime; 165 | float jumpOriginZ; 166 | int legsTime; 167 | int legsAnim; 168 | int torsoTime; 169 | int torsoAnim; 170 | int legsAnimDuration; 171 | int torsoAnimDuration; 172 | int damageTimer; 173 | int damageDuration; 174 | int flinchYawAnim; 175 | int movementDir; 176 | int eFlags; 177 | int eventSequence; 178 | int events[4]; 179 | unsigned int eventParms[4]; 180 | int oldEventSequence; 181 | int clientNum; 182 | int offHandIndex; 183 | unsigned int weapon; 184 | int weaponstate; 185 | float fWeaponPosFrac; 186 | int adsDelayTime; 187 | int viewmodelIndex; 188 | vec3_t viewangles; 189 | int viewHeightTarget; 190 | float viewHeightCurrent; 191 | int viewHeightLerpTime; 192 | int viewHeightLerpTarget; 193 | int viewHeightLerpDown; 194 | int unknown[5]; 195 | int damageEvent; 196 | int damageYaw; 197 | int damagePitch; 198 | int damageCount; 199 | int stats[6]; 200 | int ammo[128]; 201 | int ammoclip[128]; 202 | int weapFlags; 203 | int weapFlags2; 204 | int unknown2[2]; 205 | byte slot_none; 206 | byte slot_primary; 207 | byte slot_primaryb; 208 | int unknown3[5]; 209 | vec3_t mins; 210 | vec3_t maxs; 211 | float proneDirection; 212 | float proneDirectionPitch; 213 | float proneTorsoPitch; 214 | ViewLockTypes_t viewlocked; 215 | int viewlocked_entNum; 216 | int cursorHint; 217 | int cursorHintString; 218 | int cursorHintEntIndex; 219 | int unknown1; 220 | vec3_t unkAngles; 221 | float holdBreathScale; 222 | int holdBreathTimer; 223 | mantleState_t mantleState; 224 | int entityEventSequence; 225 | int weapAnim; 226 | float aimSpreadScale; 227 | int shellshockIndex; 228 | int shellshockTime; 229 | int shellshockDuration; 230 | objective_t objective[16]; 231 | int archiveTime; 232 | hudElemState_t hud; 233 | } playerState_t; 234 | 235 | typedef enum 236 | { 237 | STATE_PLAYING = 0x0, 238 | STATE_DEAD = 0x1, 239 | STATE_SPECTATOR = 0x2, 240 | STATE_INTERMISSION = 0x3, 241 | } sessionState_t; 242 | 243 | typedef enum 244 | { 245 | CON_DISCONNECTED = 0x0, 246 | CON_CONNECTING = 0x1, 247 | CON_CONNECTED = 0x2, 248 | } clientConnected_t; 249 | 250 | typedef struct usercmd_s 251 | { 252 | int serverTime; 253 | int buttons; 254 | byte weapon; 255 | byte offHandIndex; 256 | int angles[3]; 257 | char forwardmove; 258 | char rightmove; 259 | } usercmd_t; 260 | 261 | typedef enum 262 | { 263 | TEAM_NONE = 0x0, 264 | TEAM_AXIS = 0x1, 265 | TEAM_ALLIES = 0x2, 266 | TEAM_SPECTATOR = 0x3, 267 | } sessionTeam_t; 268 | 269 | typedef struct 270 | { 271 | sessionState_t state; 272 | int forceSpectatorClient; 273 | int statusIcon; 274 | int archiveTime; 275 | int score; 276 | int deaths; 277 | unsigned __int16 scriptPersId; 278 | byte pad2; 279 | byte pad; 280 | clientConnected_t connected; 281 | usercmd_t cmd; 282 | usercmd_t oldcmd; 283 | int localClient; 284 | int predictItemPickup; 285 | char name[32]; 286 | int maxHealth; 287 | int enterTime; 288 | int voteCount; 289 | int teamVoteCount; 290 | float unknown; 291 | int viewmodelIndex; 292 | int noSpectate; 293 | int teamInfo; 294 | int clientId; 295 | sessionTeam_t team; 296 | int model; 297 | int attachedModels[6]; 298 | int attachedModelsTags[6]; 299 | char manualModeName[32]; 300 | int psOffsetTime; 301 | } clientSession_t; 302 | 303 | typedef enum 304 | { 305 | TR_STATIONARY = 0x0, 306 | TR_INTERPOLATE = 0x1, 307 | TR_LINEAR = 0x2, 308 | TR_LINEAR_STOP = 0x3, 309 | TR_SINE = 0x4, 310 | TR_GRAVITY = 0x5, 311 | TR_GRAVITY_PAUSED = 0x6, 312 | TR_ACCELERATE = 0x7, 313 | TR_DECCELERATE = 0x8, 314 | } trType_t; 315 | 316 | typedef struct 317 | { 318 | trType_t trType; 319 | int trTime; 320 | int trDuration; 321 | vec3_t trBase; 322 | vec3_t trDelta; 323 | } trajectory_t; 324 | 325 | typedef struct entityState_s 326 | { 327 | int number; 328 | int eType; 329 | int eFlags; 330 | trajectory_t pos; 331 | trajectory_t apos; 332 | int time; 333 | int time2; 334 | vec3_t origin; 335 | vec3_t angles; 336 | int otherEntityNum; 337 | int attackerEntityNum; 338 | int groundEntityNum; 339 | int constantLight; 340 | int loopSound; 341 | int surfaceFlags; 342 | int modelindex; 343 | int clientNum; 344 | int iHeadIcon; 345 | int iHeadIconTeam; 346 | int solid; 347 | int eventParm; 348 | int eventSequence; 349 | vec4_t events; 350 | vec4_t eventParms; 351 | int weapon; 352 | int legsAnim; 353 | int torsoAnim; 354 | int stage; 355 | int loopfxid; 356 | int hintstring; 357 | int animMovetype; 358 | vec3_t unkAngles; 359 | } entityState_t; 360 | 361 | typedef struct 362 | { 363 | byte linked; 364 | byte bmodel; 365 | byte svFlags; 366 | byte pad1; 367 | int clientMask[2]; 368 | byte inuse; 369 | byte pad2[3]; 370 | int broadcastTime; 371 | vec3_t mins; 372 | vec3_t maxs; 373 | int contents; 374 | vec3_t absmin; 375 | vec3_t absmax; 376 | vec3_t currentOrigin; 377 | vec3_t currentAngles; 378 | unsigned __int16 ownerNum; 379 | unsigned __int16 pad3; 380 | int eventTime; 381 | } entityShared_t; 382 | 383 | typedef struct gentity_s 384 | { 385 | entityState_t s; 386 | entityShared_t r; 387 | struct gclient_s *client; 388 | turretInfo_s *pTurretInfo; 389 | byte physicsObject; 390 | byte takedamage; 391 | byte active; 392 | byte nopickup; 393 | byte model; 394 | byte dobjbits; 395 | byte handler; 396 | byte team; 397 | unsigned __int16 classname; 398 | unsigned __int16 target; 399 | unsigned __int16 targetname; 400 | unsigned __int16 padding; 401 | int spawnflags; 402 | int flags; 403 | int eventTime; 404 | int freeAfterEvent; 405 | int unlinkAfterEvent; 406 | int clipmask; 407 | int framenum; 408 | struct gentity_s *parent; 409 | int nextthink; 410 | int healthPoints; 411 | int reservedHealth; 412 | int damage; 413 | int splashDamage; 414 | int splashRadius; 415 | float pfDecelTimeMove; 416 | float pfDecelTimeRotate; 417 | float pfSpeedMove; 418 | float pfSpeedRotate; 419 | float pfMidTimeMove; 420 | float pfMidTimeRotate; 421 | vec3_t vPos1Move; 422 | vec3_t vPos2Move; 423 | vec3_t vPos3Move; 424 | vec3_t vPos1Rotate; 425 | vec3_t vPos2Rotate; 426 | vec3_t vPos3Rotate; 427 | int moverState; 428 | struct gentity_s **linkedEntities; 429 | byte attachedModels[6]; 430 | unsigned __int16 attachedModelsIndexes; 431 | unsigned __int16 numAttachedModels; 432 | int animTree; 433 | vec4_t color; 434 | } gentity_t; 435 | 436 | typedef struct gclient_s 437 | { 438 | playerState_t ps; 439 | clientSession_t sess; 440 | int spectatorClient; 441 | int noclip; 442 | int ufo; 443 | int bFrozen; 444 | int lastCmdTime; 445 | int buttons; 446 | int oldbuttons; 447 | int latched_buttons; 448 | int buttonsSinceLastFrame; 449 | vec3_t oldOrigin; 450 | float fGunPitch; 451 | float fGunYaw; 452 | int damage_blood; 453 | vec3_t damage_from; 454 | int damage_fromWorld; 455 | int accurateCount; 456 | int accuracy_shots; 457 | int accuracy_hits; 458 | int inactivityTime; 459 | int inactivityWarning; 460 | int playerTalkTime; 461 | int rewardTime; 462 | float currentAimSpreadScale; 463 | int unknown_space[2]; 464 | int unknownClientEndFrameVar; 465 | int unknown_space2[3]; 466 | gentity_t *lookAtEntity; 467 | int activateEntNumber; 468 | int activateTime; 469 | int nonPVSFriendlyEntNum; 470 | int pingPlayerTime; 471 | int damageFeedBackTime; 472 | vec2_t damageFeedBackDir; 473 | vec3_t swayViewAngles; 474 | vec3_t swayOffset; 475 | vec3_t swayAngles; 476 | int unknown_space3[7]; 477 | float weaponRecoil; 478 | int unknown_space4[3]; 479 | int lastServerTime; 480 | int lastActivateTime; 481 | } gclient_t; 482 | 483 | typedef enum 484 | { 485 | MOD_UNKNOWN = 0x0, 486 | MOD_PISTOL_BULLET = 0x1, 487 | MOD_RIFLE_BULLET = 0x2, 488 | MOD_GRENADE = 0x3, 489 | MOD_GRENADE_SPLASH = 0x4, 490 | MOD_PROJECTILE = 0x5, 491 | MOD_PROJECTILE_SPLASH = 0x6, 492 | MOD_MELEE = 0x7, 493 | MOD_HEAD_SHOT = 0x8, 494 | MOD_CRUSH = 0x9, 495 | MOD_TELEFRAG = 0xA, 496 | MOD_FALLING = 0xB, 497 | MOD_SUICIDE = 0xC, 498 | MOD_TRIGGER_HURT = 0xD, 499 | MOD_EXPLOSIVE = 0xE, 500 | MOD_BAD = 0xF, 501 | } meansOfDeath_t; 502 | 503 | enum svc_ops_e 504 | { 505 | svc_nop = 0x0, 506 | svc_gamestate = 0x1, 507 | svc_configstring = 0x2, 508 | svc_baseline = 0x3, 509 | svc_serverCommand = 0x4, 510 | svc_download = 0x5, 511 | svc_snapshot = 0x6, 512 | svc_EOF = 0x7, 513 | }; 514 | 515 | typedef enum 516 | { 517 | ET_GENERAL = 0x0, 518 | ET_PLAYER = 0x1, 519 | ET_CORPSE = 0x2, 520 | ET_ITEM = 0x3, 521 | ET_MISSILE = 0x4, 522 | ET_INVISIBLE = 0x5, 523 | ET_SCRIPTMOVER = 0x6, 524 | } entityType_t; 525 | 526 | typedef enum 527 | { 528 | TEAM_FREE = 0x0, 529 | TEAM_RED = 0x1, 530 | TEAM_BLUE = 0x2, 531 | TEAM_SPEC = 0x3, 532 | TEAM_NUM_TEAMS = 0x4, 533 | } team_t; 534 | 535 | typedef enum 536 | { 537 | CS_FREE = 0x0, 538 | CS_ZOMBIE = 0x1, 539 | CS_CONNECTED = 0x2, 540 | CS_PRIMED = 0x3, 541 | CS_ACTIVE = 0x4, 542 | } clientState_t; 543 | 544 | typedef enum 545 | { 546 | NA_BOT = 0x0, 547 | NA_BAD = 0x0, 548 | NA_LOOPBACK = 0x2, 549 | NA_BROADCAST = 0x3, 550 | NA_IP = 0x4, 551 | NA_IPX = 0x5, 552 | NA_BROADCAST_IPX = 0x6, 553 | } netadrtype_t; 554 | 555 | typedef struct 556 | { 557 | netadrtype_t type; 558 | byte ip[4]; 559 | unsigned __int16 port; 560 | byte ipx[10]; 561 | } netadr_t; 562 | 563 | typedef enum 564 | { 565 | NS_CLIENT = 0x0, 566 | NS_SERVER = 0x1, 567 | } netsrc_t; 568 | 569 | typedef struct 570 | { 571 | int overflowed; 572 | byte *data; 573 | int maxsize; 574 | int cursize; 575 | int readcount; 576 | int bit; 577 | } msg_t; 578 | 579 | typedef union 580 | { 581 | int i; 582 | byte rgba[4]; 583 | } ucolor_t; 584 | 585 | typedef enum : unsigned __int16 586 | { 587 | CVAR_FLAG_ARCHIVE = 1 << 0, // 0x0001 588 | CVAR_FLAG_USERINFO = 1 << 1, // 0x0002 589 | CVAR_FLAG_SERVERINFO = 1 << 2, // 0x0004 590 | CVAR_FLAG_SYSTEMINFO = 1 << 3, // 0x0008 591 | CVAR_FLAG_INIT = 1 << 4, // 0x0010 592 | CVAR_FLAG_LATCH = 1 << 5, // 0x0020 593 | CVAR_FLAG_ROM = 1 << 6, // 0x0040 594 | CVAR_FLAG_CHEAT = 1 << 7, // 0x0080 595 | CVAR_FLAG_DEVELOPER = 1 << 8, // 0x0100 596 | CVAR_FLAG_SAVED = 1 << 9, // 0x0200 597 | CVAR_FLAG_NORESTART = 1 << 10, // 0x0400 598 | CVAR_FLAG_CHANGEABLE_RESET = 1 << 12, // 0x1000 599 | CVAR_FLAG_EXTERNAL = 1 << 14, // 0x4000 600 | CVAR_FLAG_AUTOEXEC = 1 << 15, // 0x8000 601 | } CvarFlags; 602 | 603 | enum cvarType_t : char 604 | { 605 | CVAR_TYPE_BOOL = 0x0, 606 | CVAR_TYPE_FLOAT = 0x1, 607 | CVAR_TYPE_FLOAT_2 = 0x2, 608 | CVAR_TYPE_FLOAT_3 = 0x3, 609 | CVAR_TYPE_FLOAT_4 = 0x4, 610 | CVAR_TYPE_INT = 0x5, 611 | CVAR_TYPE_ENUM = 0x6, 612 | CVAR_TYPE_STRING = 0x7, 613 | CVAR_TYPE_COLOR = 0x8, 614 | CVAR_TYPE_COUNT = 0x9, 615 | }; 616 | 617 | enum DvarSetSource 618 | { 619 | CVAR_SOURCE_INTERNAL = 0x0, 620 | CVAR_SOURCE_EXTERNAL = 0x1, 621 | CVAR_SOURCE_SCRIPT = 0x2, 622 | CVAR_SOURCE_DEVGUI = 0x3, 623 | }; 624 | 625 | union cvar_value_s 626 | { 627 | float floatval; 628 | int integer; 629 | char *string; 630 | byte boolean; 631 | vec2_t vec2; 632 | vec3_t vec3; 633 | vec4_t vec4; 634 | ucolor_t color; 635 | }; 636 | 637 | union cvar_bounds_s 638 | { 639 | int imin; 640 | float fmin; 641 | }; 642 | 643 | union cvar_bounds_enum_s 644 | { 645 | int imax; 646 | float fmax; 647 | const char **enumStr; 648 | }; 649 | 650 | typedef struct cvar_s 651 | { 652 | char *name; 653 | CvarFlags flags; 654 | cvarType_t type; 655 | byte modified; 656 | cvar_value_s current; 657 | cvar_value_s latched; 658 | cvar_value_s reset; 659 | cvar_bounds_s domain; 660 | cvar_bounds_enum_s domain_enum; 661 | struct cvar_s *next; 662 | struct cvar_s *hashNext; 663 | } cvar_t; 664 | 665 | struct VariableStackBuffer 666 | { 667 | const char *pos; 668 | unsigned __int16 size; 669 | unsigned __int16 bufLen; 670 | unsigned __int16 localId; 671 | char time; 672 | char buf[1]; 673 | }; 674 | 675 | union VariableUnion 676 | { 677 | int intValue; 678 | float floatValue; 679 | unsigned int stringValue; 680 | const float *vectorValue; 681 | const char *codePosValue; 682 | unsigned int pointerValue; 683 | struct VariableStackBuffer *stackValue; 684 | unsigned int entityOffset; 685 | }; 686 | 687 | union ObjectInfo_u 688 | { 689 | unsigned __int16 size; 690 | unsigned __int16 entnum; 691 | unsigned __int16 nextEntId; 692 | unsigned __int16 self; 693 | }; 694 | 695 | struct ObjectInfo 696 | { 697 | unsigned __int16 refCount; 698 | union ObjectInfo_u u; 699 | }; 700 | 701 | union VariableValueInternal_u 702 | { 703 | unsigned __int16 next; 704 | union VariableUnion u; 705 | struct ObjectInfo o; 706 | }; 707 | 708 | union VariableValueInternal_w 709 | { 710 | unsigned int status; 711 | unsigned int type; 712 | unsigned int name; 713 | unsigned int classnum; 714 | unsigned int notifyName; 715 | unsigned int waitTime; 716 | unsigned int parentLocalId; 717 | }; 718 | 719 | union VariableValueInternal_v 720 | { 721 | unsigned __int16 next; 722 | unsigned __int16 index; 723 | }; 724 | 725 | typedef struct 726 | { 727 | union VariableUnion u; 728 | int type; 729 | } VariableValue; 730 | 731 | union Variable_u 732 | { 733 | unsigned __int16 prev; 734 | unsigned __int16 prevSibling; 735 | }; 736 | 737 | struct Variable 738 | { 739 | unsigned __int16 id; 740 | union Variable_u u; 741 | }; 742 | 743 | typedef struct 744 | { 745 | struct Variable hash; 746 | union VariableValueInternal_u u; 747 | union VariableValueInternal_w w; 748 | union VariableValueInternal_v v; 749 | unsigned __int16 nextSibling; 750 | } VariableValueInternal; 751 | 752 | typedef struct 753 | { 754 | const char *fieldBuffer; 755 | struct HunkUser *programHunkUser; 756 | unsigned __int16 canonicalStrCount; 757 | byte developer; 758 | byte developer_script; 759 | byte evaluate; 760 | byte pad[3]; 761 | const char *error_message; 762 | int error_index; 763 | unsigned int time; 764 | unsigned int timeArrayId; 765 | unsigned int pauseArrayId; 766 | unsigned int levelId; 767 | unsigned int gameId; 768 | unsigned int animId; 769 | unsigned int freeEntList; 770 | unsigned int tempVariable; 771 | byte bInited; 772 | byte pad2; 773 | unsigned __int16 savecount; 774 | unsigned int checksum; 775 | unsigned int entId; 776 | unsigned int entFieldName; 777 | const char *programBuffer; 778 | const char *endScriptBuffer; 779 | } scrVarPub_t; 780 | 781 | struct function_stack_t 782 | { 783 | const char *pos; 784 | unsigned int localId; 785 | unsigned int localVarCount; 786 | VariableValue *top; 787 | VariableValue *startTop; 788 | }; 789 | 790 | struct function_frame_t 791 | { 792 | struct function_stack_t fs; 793 | int topType; 794 | }; 795 | 796 | typedef struct 797 | { 798 | unsigned int *localVars; 799 | VariableValue *maxstack; 800 | int function_count; 801 | struct function_frame_t *function_frame; 802 | VariableValue *top; 803 | byte debugCode; 804 | byte abort_on_error; 805 | byte terminal_error; 806 | byte pad; 807 | unsigned int inparamcount; 808 | unsigned int outparamcount; 809 | struct function_frame_t function_frame_start[32]; 810 | VariableValue stack[2048]; 811 | } scrVmPub_t; 812 | 813 | typedef int fileHandle_t; 814 | 815 | typedef void (__cdecl *xfunction_t)(); 816 | 817 | typedef void (__cdecl *xmethod_t)(scr_entref_t); 818 | 819 | typedef void (*xcommand_t)(void); 820 | 821 | typedef struct scr_function_s 822 | { 823 | const char *name; 824 | xfunction_t call; 825 | int developer; 826 | } scr_function_t; 827 | 828 | typedef struct scr_method_s 829 | { 830 | const char *name; 831 | xmethod_t call; 832 | int developer; 833 | } scr_method_t; 834 | 835 | typedef enum 836 | { 837 | EV_NONE = 0x0, 838 | EV_FOOTSTEP_RUN_DEFAULT = 0x1, 839 | EV_FOOTSTEP_RUN_BARK = 0x2, 840 | EV_FOOTSTEP_RUN_BRICK = 0x3, 841 | EV_FOOTSTEP_RUN_CARPET = 0x4, 842 | EV_FOOTSTEP_RUN_CLOTH = 0x5, 843 | EV_FOOTSTEP_RUN_CONCRETE = 0x6, 844 | EV_FOOTSTEP_RUN_DIRT = 0x7, 845 | EV_FOOTSTEP_RUN_FLESH = 0x8, 846 | EV_FOOTSTEP_RUN_FOLIAGE = 0x9, 847 | EV_FOOTSTEP_RUN_GLASS = 0xA, 848 | EV_FOOTSTEP_RUN_GRASS = 0xB, 849 | EV_FOOTSTEP_RUN_GRAVEL = 0xC, 850 | EV_FOOTSTEP_RUN_ICE = 0xD, 851 | EV_FOOTSTEP_RUN_METAL = 0xE, 852 | EV_FOOTSTEP_RUN_MUD = 0xF, 853 | EV_FOOTSTEP_RUN_PAPER = 0x10, 854 | EV_FOOTSTEP_RUN_PLASTER = 0x11, 855 | EV_FOOTSTEP_RUN_ROCK = 0x12, 856 | EV_FOOTSTEP_RUN_SAND = 0x13, 857 | EV_FOOTSTEP_RUN_SNOW = 0x14, 858 | EV_FOOTSTEP_RUN_WATER = 0x15, 859 | EV_FOOTSTEP_RUN_WOOD = 0x16, 860 | EV_FOOTSTEP_RUN_ASPHALT = 0x17, 861 | EV_FOOTSTEP_WALK_DEFAULT = 0x18, 862 | EV_FOOTSTEP_WALK_BARK = 0x19, 863 | EV_FOOTSTEP_WALK_BRICK = 0x1A, 864 | EV_FOOTSTEP_WALK_CARPET = 0x1B, 865 | EV_FOOTSTEP_WALK_CLOTH = 0x1C, 866 | EV_FOOTSTEP_WALK_CONCRETE = 0x1D, 867 | EV_FOOTSTEP_WALK_DIRT = 0x1E, 868 | EV_FOOTSTEP_WALK_FLESH = 0x1F, 869 | EV_FOOTSTEP_WALK_FOLIAGE = 0x20, 870 | EV_FOOTSTEP_WALK_GLASS = 0x21, 871 | EV_FOOTSTEP_WALK_GRASS = 0x22, 872 | EV_FOOTSTEP_WALK_GRAVEL = 0x23, 873 | EV_FOOTSTEP_WALK_ICE = 0x24, 874 | EV_FOOTSTEP_WALK_METAL = 0x25, 875 | EV_FOOTSTEP_WALK_MUD = 0x26, 876 | EV_FOOTSTEP_WALK_PAPER = 0x27, 877 | EV_FOOTSTEP_WALK_PLASTER = 0x28, 878 | EV_FOOTSTEP_WALK_ROCK = 0x29, 879 | EV_FOOTSTEP_WALK_SAND = 0x2A, 880 | EV_FOOTSTEP_WALK_SNOW = 0x2B, 881 | EV_FOOTSTEP_WALK_WATER = 0x2C, 882 | EV_FOOTSTEP_WALK_WOOD = 0x2D, 883 | EV_FOOTSTEP_WALK_ASPHALT = 0x2E, 884 | EV_FOOTSTEP_PRONE_DEFAULT = 0x2F, 885 | EV_FOOTSTEP_PRONE_BARK = 0x30, 886 | EV_FOOTSTEP_PRONE_BRICK = 0x31, 887 | EV_FOOTSTEP_PRONE_CARPET = 0x32, 888 | EV_FOOTSTEP_PRONE_CLOTH = 0x33, 889 | EV_FOOTSTEP_PRONE_CONCRETE = 0x34, 890 | EV_FOOTSTEP_PRONE_DIRT = 0x35, 891 | EV_FOOTSTEP_PRONE_FLESH = 0x36, 892 | EV_FOOTSTEP_PRONE_FOLIAGE = 0x37, 893 | EV_FOOTSTEP_PRONE_GLASS = 0x38, 894 | EV_FOOTSTEP_PRONE_GRASS = 0x39, 895 | EV_FOOTSTEP_PRONE_GRAVEL = 0x3A, 896 | EV_FOOTSTEP_PRONE_ICE = 0x3B, 897 | EV_FOOTSTEP_PRONE_METAL = 0x3C, 898 | EV_FOOTSTEP_PRONE_MUD = 0x3D, 899 | EV_FOOTSTEP_PRONE_PAPER = 0x3E, 900 | EV_FOOTSTEP_PRONE_PLASTER = 0x3F, 901 | EV_FOOTSTEP_PRONE_ROCK = 0x40, 902 | EV_FOOTSTEP_PRONE_SAND = 0x41, 903 | EV_FOOTSTEP_PRONE_SNOW = 0x42, 904 | EV_FOOTSTEP_PRONE_WATER = 0x43, 905 | EV_FOOTSTEP_PRONE_WOOD = 0x44, 906 | EV_FOOTSTEP_PRONE_ASPHALT = 0x45, 907 | EV_JUMP_DEFAULT = 0x46, 908 | EV_JUMP_BARK = 0x47, 909 | EV_JUMP_BRICK = 0x48, 910 | EV_JUMP_CARPET = 0x49, 911 | EV_JUMP_CLOTH = 0x4A, 912 | EV_JUMP_CONCRETE = 0x4B, 913 | EV_JUMP_DIRT = 0x4C, 914 | EV_JUMP_FLESH = 0x4D, 915 | EV_JUMP_FOLIAGE = 0x4E, 916 | EV_JUMP_GLASS = 0x4F, 917 | EV_JUMP_GRASS = 0x50, 918 | EV_JUMP_GRAVEL = 0x51, 919 | EV_JUMP_ICE = 0x52, 920 | EV_JUMP_METAL = 0x53, 921 | EV_JUMP_MUD = 0x54, 922 | EV_JUMP_PAPER = 0x55, 923 | EV_JUMP_PLASTER = 0x56, 924 | EV_JUMP_ROCK = 0x57, 925 | EV_JUMP_SAND = 0x58, 926 | EV_JUMP_SNOW = 0x59, 927 | EV_JUMP_WATER = 0x5A, 928 | EV_JUMP_WOOD = 0x5B, 929 | EV_JUMP_ASPHALT = 0x5C, 930 | EV_LANDING_DEFAULT = 0x5D, 931 | EV_LANDING_BARK = 0x5E, 932 | EV_LANDING_BRICK = 0x5F, 933 | EV_LANDING_CARPET = 0x60, 934 | EV_LANDING_CLOTH = 0x61, 935 | EV_LANDING_CONCRETE = 0x62, 936 | EV_LANDING_DIRT = 0x63, 937 | EV_LANDING_FLESH = 0x64, 938 | EV_LANDING_FOLIAGE = 0x65, 939 | EV_LANDING_GLASS = 0x66, 940 | EV_LANDING_GRASS = 0x67, 941 | EV_LANDING_GRAVEL = 0x68, 942 | EV_LANDING_ICE = 0x69, 943 | EV_LANDING_METAL = 0x6A, 944 | EV_LANDING_MUD = 0x6B, 945 | EV_LANDING_PAPER = 0x6C, 946 | EV_LANDING_PLASTER = 0x6D, 947 | EV_LANDING_ROCK = 0x6E, 948 | EV_LANDING_SAND = 0x6F, 949 | EV_LANDING_SNOW = 0x70, 950 | EV_LANDING_WATER = 0x71, 951 | EV_LANDING_WOOD = 0x72, 952 | EV_LANDING_ASPHALT = 0x73, 953 | EV_LANDING_PAIN_DEFAULT = 0x74, 954 | EV_LANDING_PAIN_BARK = 0x75, 955 | EV_LANDING_PAIN_BRICK = 0x76, 956 | EV_LANDING_PAIN_CARPET = 0x77, 957 | EV_LANDING_PAIN_CLOTH = 0x78, 958 | EV_LANDING_PAIN_CONCRETE = 0x79, 959 | EV_LANDING_PAIN_DIRT = 0x7A, 960 | EV_LANDING_PAIN_FLESH = 0x7B, 961 | EV_LANDING_PAIN_FOLIAGE = 0x7C, 962 | EV_LANDING_PAIN_GLASS = 0x7D, 963 | EV_LANDING_PAIN_GRASS = 0x7E, 964 | EV_LANDING_PAIN_GRAVEL = 0x7F, 965 | EV_LANDING_PAIN_ICE = 0x80, 966 | EV_LANDING_PAIN_METAL = 0x81, 967 | EV_LANDING_PAIN_MUD = 0x82, 968 | EV_LANDING_PAIN_PAPER = 0x83, 969 | EV_LANDING_PAIN_PLASTER = 0x84, 970 | EV_LANDING_PAIN_ROCK = 0x85, 971 | EV_LANDING_PAIN_SAND = 0x86, 972 | EV_LANDING_PAIN_SNOW = 0x87, 973 | EV_LANDING_PAIN_WATER = 0x88, 974 | EV_LANDING_PAIN_WOOD = 0x89, 975 | EV_LANDING_PAIN_ASPHALT = 0x8A, 976 | EV_FOLIAGE_SOUND = 0x8B, 977 | EV_STANCE_FORCE_STAND = 0x8C, 978 | EV_STANCE_FORCE_CROUCH = 0x8D, 979 | EV_STANCE_FORCE_PRONE = 0x8E, 980 | EV_STEP_VIEW = 0x8F, 981 | EV_ITEM_PICKUP = 0x90, 982 | EV_AMMO_PICKUP = 0x91, 983 | EV_NOAMMO = 0x92, 984 | EV_EMPTYCLIP = 0x93, 985 | EV_EMPTY_OFFHAND = 0x94, 986 | EV_RESET_ADS = 0x95, 987 | EV_RELOAD = 0x96, 988 | EV_RELOAD_FROM_EMPTY = 0x97, 989 | EV_RELOAD_START = 0x98, 990 | EV_RELOAD_END = 0x99, 991 | EV_RAISE_WEAPON = 0x9A, 992 | EV_PUTAWAY_WEAPON = 0x9B, 993 | EV_WEAPON_ALT = 0x9C, 994 | EV_PULLBACK_WEAPON = 0x9D, 995 | EV_FIRE_WEAPON = 0x9E, 996 | EV_FIRE_WEAPONB = 0x9F, 997 | EV_FIRE_WEAPON_LASTSHOT = 0xA0, 998 | EV_RECHAMBER_WEAPON = 0xA1, 999 | EV_EJECT_BRASS = 0xA2, 1000 | EV_MELEE_SWIPE = 0xA3, 1001 | EV_FIRE_MELEE = 0xA4, 1002 | EV_PREP_OFFHAND = 0xA5, 1003 | EV_USE_OFFHAND = 0xA6, 1004 | EV_SWITCH_OFFHAND = 0xA7, 1005 | EV_BINOCULAR_ENTER = 0xA8, 1006 | EV_BINOCULAR_EXIT = 0xA9, 1007 | EV_BINOCULAR_FIRE = 0xAA, 1008 | EV_BINOCULAR_RELEASE = 0xAB, 1009 | EV_BINOCULAR_DROP = 0xAC, 1010 | EV_MELEE_HIT = 0xAD, 1011 | EV_MELEE_MISS = 0xAE, 1012 | EV_FIRE_WEAPON_MG42 = 0xAF, 1013 | EV_FIRE_QUADBARREL_1 = 0xB0, 1014 | EV_FIRE_QUADBARREL_2 = 0xB1, 1015 | EV_BULLET_TRACER = 0xB2, 1016 | EV_SOUND_ALIAS = 0xB3, 1017 | EV_SOUND_ALIAS_AS_MASTER = 0xB4, 1018 | EV_BULLET_HIT_SMALL = 0xB5, 1019 | EV_BULLET_HIT_LARGE = 0xB6, 1020 | EV_SHOTGUN_HIT = 0xB7, 1021 | EV_BULLET_HIT_AP = 0xB8, 1022 | EV_BULLET_HIT_CLIENT_SMALL = 0xB9, 1023 | EV_BULLET_HIT_CLIENT_LARGE = 0xBA, 1024 | EV_GRENADE_BOUNCE = 0xBB, 1025 | EV_GRENADE_EXPLODE = 0xBC, 1026 | EV_ROCKET_EXPLODE = 0xBD, 1027 | EV_ROCKET_EXPLODE_NOMARKS = 0xBE, 1028 | EV_CUSTOM_EXPLODE = 0xBF, 1029 | EV_CUSTOM_EXPLODE_NOMARKS = 0xC0, 1030 | EV_BULLET = 0xC1, 1031 | EV_PLAY_FX = 0xC2, 1032 | EV_PLAY_FX_ON_TAG = 0xC3, 1033 | EV_EARTHQUAKE = 0xC4, 1034 | EV_GRENADE_SUICIDE = 0xC5, 1035 | EV_OBITUARY = 0xC6, 1036 | } entity_event_t; 1037 | 1038 | enum scriptAnimEventTypes_t 1039 | { 1040 | ANIM_ET_PAIN = 0x0, 1041 | ANIM_ET_DEATH = 0x1, 1042 | ANIM_ET_FIREWEAPON = 0x2, 1043 | ANIM_ET_JUMP = 0x3, 1044 | ANIM_ET_JUMPBK = 0x4, 1045 | ANIM_ET_LAND = 0x5, 1046 | ANIM_ET_DROPWEAPON = 0x6, 1047 | ANIM_ET_RAISEWEAPON = 0x7, 1048 | ANIM_ET_CLIMB_MOUNT = 0x8, 1049 | ANIM_ET_CLIMB_DISMOUNT = 0x9, 1050 | ANIM_ET_RELOAD = 0xA, 1051 | ANIM_ET_CROUCH_TO_PRONE = 0xB, 1052 | ANIM_ET_PRONE_TO_CROUCH = 0xC, 1053 | ANIM_ET_STAND_TO_CROUCH = 0xD, 1054 | ANIM_ET_CROUCH_TO_STAND = 0xE, 1055 | ANIM_ET_STAND_TO_PRONE = 0xF, 1056 | ANIM_ET_PRONE_TO_STAND = 0x10, 1057 | ANIM_ET_MELEEATTACK = 0x11, 1058 | ANIM_ET_SHELLSHOCK = 0x12, 1059 | NUM_ANIM_EVENTTYPES = 0x13, 1060 | }; 1061 | 1062 | enum StanceState 1063 | { 1064 | CL_STANCE_STAND = 0x0, 1065 | CL_STANCE_CROUCH = 0x1, 1066 | CL_STANCE_PRONE = 0x2, 1067 | CL_STANCE_DIVE_TO_PRONE = 0x3, 1068 | }; 1069 | 1070 | typedef enum 1071 | { 1072 | TRACE_HITTYPE_NONE = 0x0, 1073 | TRACE_HITTYPE_ENTITY = 0x1, 1074 | TRACE_HITTYPE_DYNENT_MODEL = 0x2, 1075 | TRACE_HITTYPE_DYNENT_BRUSH = 0x3, 1076 | TRACE_HITTYPE_GLASS = 0x4, 1077 | } TraceHitType; 1078 | 1079 | typedef struct trace_s 1080 | { 1081 | float fraction; 1082 | vec3_t normal; 1083 | int surfaceFlags; 1084 | int contents; 1085 | const char *material; 1086 | int entityNum; 1087 | byte allsolid; 1088 | byte startsolid; 1089 | byte walkable; 1090 | byte padding; 1091 | } trace_t; 1092 | 1093 | typedef struct leakyBucket_s 1094 | { 1095 | netadrtype_t type; 1096 | unsigned __int8 adr[4]; 1097 | int lastTime; 1098 | signed __int8 burst; 1099 | int hash; 1100 | struct leakyBucket_s *prev; 1101 | struct leakyBucket_s *next; 1102 | } leakyBucket_t; 1103 | 1104 | typedef void netProfileInfo_t; 1105 | 1106 | typedef struct 1107 | { 1108 | int outgoingSequence; 1109 | netsrc_t sock; 1110 | int dropped; 1111 | int incomingSequence; 1112 | netadr_t remoteAddress; 1113 | int qport; 1114 | int fragmentSequence; 1115 | int fragmentLength; 1116 | byte fragmentBuffer[131072]; 1117 | int unsentFragments; 1118 | int unsentFragmentStart; 1119 | int unsentLength; 1120 | byte unsentBuffer[131072]; 1121 | netProfileInfo_t *netProfile; 1122 | } netchan_t; 1123 | 1124 | typedef struct 1125 | { 1126 | char command[1024]; 1127 | int cmdTime; 1128 | int cmdType; 1129 | } reliableCommands_t; 1130 | 1131 | typedef struct 1132 | { 1133 | netadr_t adr; 1134 | int challenge; 1135 | int time; 1136 | int pingTime; 1137 | int firstTime; 1138 | int firstPing; 1139 | int connected; 1140 | int guid; 1141 | char pbguid[64]; 1142 | int ipAuthorize; 1143 | } challenge_t; 1144 | 1145 | typedef enum 1146 | { 1147 | STAT_HEALTH = 0x0, 1148 | STAT_DEAD_YAW = 0x1, 1149 | STAT_MAX_HEALTH = 0x2, 1150 | STAT_FRIENDLY_LOOKAT_CLIENTNUM = 0x3, 1151 | STAT_FRIENDLY_LOOKAT_HEALTH = 0x4, 1152 | STAT_SPAWN_COUNT = 0x5, 1153 | } statIndex_t; 1154 | 1155 | typedef struct 1156 | { 1157 | playerState_t ps; 1158 | int num_entities; 1159 | int num_clients; 1160 | int first_entity; 1161 | int first_client; 1162 | unsigned int messageSent; 1163 | unsigned int messageAcked; 1164 | int messageSize; 1165 | } clientSnapshot_t; 1166 | 1167 | #pragma pack(push, 1) 1168 | typedef struct 1169 | { 1170 | char num; 1171 | char data[256]; 1172 | int dataLen; 1173 | } voices_t; 1174 | #pragma pack(pop) 1175 | 1176 | typedef struct client_s 1177 | { 1178 | clientState_t state; 1179 | int unksnapshotvar; 1180 | int unksnapshotvar2; 1181 | char userinfo[1024]; 1182 | reliableCommands_t reliableCommands[128]; 1183 | int reliableSequence; 1184 | int reliableAcknowledge; 1185 | int reliableSent; 1186 | int messageAcknowledge; 1187 | int gamestateMessageNum; 1188 | int challenge; 1189 | usercmd_t lastUsercmd; 1190 | int lastClientCommand; 1191 | char lastClientCommandString[1024]; 1192 | gentity_t *gentity; 1193 | char name[32]; 1194 | char downloadName[64]; 1195 | fileHandle_t download; 1196 | int downloadSize; 1197 | int downloadCount; 1198 | int downloadClientBlock; 1199 | int downloadCurrentBlock; 1200 | int downloadXmitBlock; 1201 | unsigned __int8 *downloadBlocks[8]; 1202 | int downloadBlockSize[8]; 1203 | int downloadEOF; 1204 | int downloadSendTime; 1205 | char wwwDownloadURL[256]; 1206 | int wwwDownload; 1207 | int wwwDownloadStarted; 1208 | int wwwDlAck; 1209 | int wwwDl_failed; 1210 | int deltaMessage; 1211 | int floodprotect; 1212 | int lastPacketTime; 1213 | int lastConnectTime; 1214 | int nextSnapshotTime; 1215 | int rateDelayed; 1216 | int timeoutCount; 1217 | clientSnapshot_t frames[32]; 1218 | int ping; 1219 | int rate; 1220 | int snapshotMsec; 1221 | int pureAuthentic; 1222 | netchan_t netchan; 1223 | int guid; 1224 | __int16 clscriptid; 1225 | int bot; 1226 | int serverId; 1227 | voices_t voicedata[40]; 1228 | int unsentVoiceData; 1229 | byte mutedClients[64]; 1230 | byte hasVoip; 1231 | char pbguid[64]; 1232 | } client_t; 1233 | 1234 | typedef struct archivedSnapshot_s 1235 | { 1236 | int start; 1237 | int size; 1238 | } archivedSnapshot_t; 1239 | 1240 | typedef struct cachedClient_s 1241 | { 1242 | int playerStateExists; 1243 | clientState_t *cs; 1244 | playerState_t *ps; 1245 | } cachedClient_t; 1246 | 1247 | typedef struct 1248 | { 1249 | int initialized; 1250 | int time; 1251 | int snapFlagServerBit; 1252 | client_t *clients; 1253 | int numSnapshotEntities; 1254 | int numSnapshotClients; 1255 | int nextSnapshotEntities; 1256 | int nextSnapshotClients; 1257 | entityState_t *snapshotEntities; 1258 | clientState_t *snapshotClients; 1259 | int archivedSnapshotEnabled; 1260 | int nextArchivedSnapshotFrames; 1261 | archivedSnapshot_t *archivedSnapshotFrames; 1262 | int *archivedSnapshotBuffer; 1263 | int nextArchivedSnapshotBuffer; 1264 | int nextCachedSnapshotEntities; 1265 | int nextCachedSnapshotClients; 1266 | int nextCachedSnapshotFrames; 1267 | cachedClient_t cachedSnapshotClients; 1268 | int nextHeartbeatTime; 1269 | int nextStatusResponseTime; 1270 | challenge_t challenges[1024]; 1271 | netadr_t redirectAddress; 1272 | netadr_t authorizeAddress; 1273 | char netProfilingBuf[1504]; 1274 | } serverStatic_t; 1275 | 1276 | typedef struct 1277 | { 1278 | const char *key; 1279 | const char *value; 1280 | } keyValueStr_t; 1281 | 1282 | typedef struct 1283 | { 1284 | byte spawnVarsValid; 1285 | int numSpawnVars; 1286 | keyValueStr_t spawnVars[64]; 1287 | int numSpawnVarChars; 1288 | char spawnVarChars[2048]; 1289 | } SpawnVar; 1290 | 1291 | typedef struct 1292 | { 1293 | unsigned __int16 entnum; 1294 | unsigned __int16 otherEntnum; 1295 | int useCount; 1296 | int otherUseCount; 1297 | } trigger_info_t; 1298 | 1299 | typedef struct __declspec(align(4)) 1300 | { 1301 | struct gclient_s *clients; 1302 | struct gentity_s *gentities; 1303 | int gentitySize; 1304 | int num_entities; 1305 | struct gentity_s *firstFreeEnt; 1306 | struct gentity_s *lastFreeEnt; 1307 | fileHandle_t logFile; 1308 | int initializing; 1309 | int clientIsSpawning; 1310 | objective_t objectives[16]; 1311 | int maxclients; 1312 | int framenum; 1313 | int time; 1314 | int previousTime; 1315 | int frameTime; 1316 | int startTime; 1317 | int teamScores[4]; 1318 | int lastTeammateHealthTime; 1319 | int bUpdateScoresForIntermission; 1320 | int manualNameChange; 1321 | int numConnectedClients; 1322 | int sortedClients[64]; 1323 | char voteString[1024]; 1324 | char voteDisplayString[1024]; 1325 | int voteTime; 1326 | int voteExecuteTime; 1327 | int voteYes; 1328 | int voteNo; 1329 | int numVotingClients; 1330 | byte gap[2072]; 1331 | SpawnVar spawnVars; 1332 | int savePersist; 1333 | struct gentity_s *droppedWeaponCue[32]; 1334 | float fFogOpaqueDist; 1335 | float fFogOpaqueDistSqrd; 1336 | int remapCount; 1337 | int currentPlayerClone; 1338 | trigger_info_t pendingTriggerList[256]; 1339 | trigger_info_t currentTriggerList[256]; 1340 | int pendingTriggerListSize; 1341 | int currentTriggerListSize; 1342 | int finished; 1343 | int bPlayerIgnoreRadiusDamage; 1344 | int bPlayerIgnoreRadiusDamageLatched; 1345 | int registerWeapons; 1346 | int bRegisterItems; 1347 | int currentEntityThink; 1348 | void *openScriptIOFileHandles[1]; 1349 | char *openScriptIOFileBuffers[1]; 1350 | int field_3610; 1351 | int field_3614; 1352 | int field_3618; 1353 | int field_361C; 1354 | int field_3620; 1355 | } level_locals_t; 1356 | 1357 | typedef enum 1358 | { 1359 | SS_DEAD = 0x0, 1360 | SS_LOADING = 0x1, 1361 | SS_GAME = 0x2, 1362 | } serverState_t; 1363 | 1364 | typedef struct 1365 | { 1366 | int cluster; 1367 | int area; 1368 | int firstLeafBrush; 1369 | int numLeafBrushes; 1370 | int firstLeafSurface; 1371 | int numLeafSurfaces; 1372 | } cLeaf_t; 1373 | 1374 | typedef struct cmodel_s 1375 | { 1376 | vec3_t mins; 1377 | vec3_t maxs; 1378 | cLeaf_t leaf; 1379 | } cmodel_t; 1380 | 1381 | typedef struct 1382 | { 1383 | int svFlags; 1384 | int clientMask[2]; 1385 | vec3_t absmin; 1386 | vec3_t absmax; 1387 | } archivedEntityShared_t; 1388 | 1389 | typedef struct archivedEntity_s 1390 | { 1391 | entityState_t s; 1392 | archivedEntityShared_t r; 1393 | } archivedEntity_t; 1394 | 1395 | typedef struct svEntity_s 1396 | { 1397 | unsigned __int16 worldSector; 1398 | unsigned __int16 nextEntityInWorldSector; 1399 | archivedEntity_t baseline; 1400 | int numClusters; 1401 | int clusternums[16]; 1402 | int lastCluster; 1403 | int linkcontents; 1404 | float linkmin[2]; 1405 | float linkmax[2]; 1406 | } svEntity_t; 1407 | 1408 | typedef struct 1409 | { 1410 | serverState_t state; 1411 | int restarting; 1412 | int start_frameTime; 1413 | int checksumFeed; 1414 | int timeResidual; 1415 | int unk; 1416 | struct cmodel_s *models[256]; 1417 | char *configstrings[2048]; 1418 | svEntity_t svEntities[1024]; 1419 | char *entityParsePoint; 1420 | gentity_t *gentities; 1421 | int gentitySize; 1422 | int num_entities; 1423 | playerState_t *gameClients; 1424 | int gameClientSize; 1425 | int skelTimeStamp; 1426 | int skelMemPos; 1427 | int bpsWindow[20]; 1428 | int bpsWindowSteps; 1429 | int bpsTotalBytes; 1430 | int bpsMaxBytes; 1431 | int ubpsWindow[20]; 1432 | int ubpsTotalBytes; 1433 | int ubpsMaxBytes; 1434 | float ucompAve; 1435 | int ucompNum; 1436 | char gametype[64]; 1437 | } server_t; 1438 | 1439 | enum weapType_t 1440 | { 1441 | WEAPTYPE_BULLET = 0x0, 1442 | WEAPTYPE_GRENADE = 0x1, 1443 | WEAPTYPE_PROJECTILE = 0x2, 1444 | WEAPTYPE_BINOCULARS = 0x3, 1445 | WEAPTYPE_NUM = 0x4, 1446 | }; 1447 | 1448 | enum weapClass_t 1449 | { 1450 | WEAPCLASS_RIFLE = 0x0, 1451 | WEAPCLASS_MG = 0x1, 1452 | WEAPCLASS_SMG = 0x2, 1453 | WEAPCLASS_SPREAD = 0x3, 1454 | WEAPCLASS_PISTOL = 0x4, 1455 | WEAPCLASS_GRENADE = 0x5, 1456 | WEAPCLASS_ROCKETLAUNCHER = 0x6, 1457 | WEAPCLASS_TURRET = 0x7, 1458 | WEAPCLASS_NON_PLAYER = 0x8, 1459 | WEAPCLASS_ITEM = 0x9, 1460 | WEAPCLASS_NUM = 0xA, 1461 | }; 1462 | 1463 | enum ImpactType_t 1464 | { 1465 | IMPACT_TYPE_NONE = 0x0, 1466 | IMPACT_TYPE_BULLET_SMALL = 0x1, 1467 | IMPACT_TYPE_BULLET_LARGE = 0x2, 1468 | IMPACT_TYPE_BULLET_AP = 0x3, 1469 | IMPACT_TYPE_SHOTGUN = 0x4, 1470 | IMPACT_TYPE_GRENADE_BOUNCE = 0x5, 1471 | IMPACT_TYPE_GRENADE_EXPLODE = 0x6, 1472 | IMPACT_TYPE_ROCKET_EXPLODE = 0x7, 1473 | IMPACT_TYPE_PROJECTILE_DUD = 0x8, 1474 | IMPACT_TYPE_COUNT = 0x9, 1475 | }; 1476 | 1477 | enum weapInventoryType_t 1478 | { 1479 | WEAPINVENTORY_PRIMARY = 0x0, 1480 | WEAPINVENTORY_OFFHAND = 0x1, 1481 | WEAPINVENTORY_ITEM = 0x2, 1482 | WEAPINVENTORY_ALTMODE = 0x3, 1483 | WEAPINVENTORYCOUNT = 0x4, 1484 | }; 1485 | 1486 | enum OffhandClass_t 1487 | { 1488 | OFFHAND_CLASS_NONE = 0x0, 1489 | OFFHAND_CLASS_FRAG_GRENADE = 0x1, 1490 | OFFHAND_CLASS_SMOKE_GRENADE = 0x2, 1491 | OFFHAND_CLASS_COUNT = 0x3, 1492 | }; 1493 | 1494 | enum weapStance_t 1495 | { 1496 | WEAPSTANCE_STAND = 0x0, 1497 | WEAPSTANCE_DUCK = 0x1, 1498 | WEAPSTANCE_PRONE = 0x2, 1499 | WEAPSTANCE_NUM = 0x3, 1500 | }; 1501 | 1502 | enum weapOverlayReticle_t 1503 | { 1504 | WEAPOVERLAYRETICLE_NONE = 0x0, 1505 | WEAPOVERLAYRETICLE_CROSSHAIR = 0x1, 1506 | WEAPOVERLAYRETICLE_NUM = 0x2, 1507 | }; 1508 | 1509 | enum weaponIconRatioType_t 1510 | { 1511 | WEAPON_ICON_RATIO_1TO1 = 0x0, 1512 | WEAPON_ICON_RATIO_2TO1 = 0x1, 1513 | WEAPON_ICON_RATIO_4TO1 = 0x2, 1514 | WEAPON_ICON_RATIO_COUNT = 0x3, 1515 | }; 1516 | 1517 | enum weapProjExposion_t 1518 | { 1519 | WEAPPROJEXP_GRENADE = 0x0, 1520 | WEAPPROJEXP_MOLOTOV = 0x1, 1521 | WEAPPROJEXP_ROCKET = 0x2, 1522 | WEAPPROJEXP_NONE = 0x3, 1523 | WEAPPROJEXP_NUM = 0x4, 1524 | }; 1525 | 1526 | typedef const char FxEffectDef_t; 1527 | 1528 | typedef const char snd_alias_list_t; 1529 | 1530 | typedef const char Material_t; 1531 | 1532 | struct WeaponDef_t 1533 | { 1534 | const char *szInternalName; 1535 | const char *szDisplayName; 1536 | const char *szOverlayName; 1537 | const char *szViewModelName; 1538 | const char *szHandModelName; 1539 | int unknown; 1540 | const char *szXAnims[22]; 1541 | const char *szModeName; 1542 | int playerAnimType; 1543 | weapType_t weapType; 1544 | weapClass_t weapClass; 1545 | ImpactType_t impactType; 1546 | weapInventoryType_t inventoryType; 1547 | OffhandClass_t offhandClass; 1548 | weapStance_t stance; 1549 | FxEffectDef_t *viewFlashEffect; 1550 | FxEffectDef_t *worldFlashEffect; 1551 | snd_alias_list_t *pickupSound; 1552 | snd_alias_list_t *ammoPickupSound; 1553 | snd_alias_list_t *projectileSound; 1554 | snd_alias_list_t *pullbackSound; 1555 | snd_alias_list_t *fireSound; 1556 | snd_alias_list_t *fireSoundPlayer; 1557 | snd_alias_list_t *unknown4[4]; 1558 | snd_alias_list_t *fireLastSound; 1559 | snd_alias_list_t *fireLastSoundPlayer; 1560 | snd_alias_list_t *meleeSwipeSound; 1561 | snd_alias_list_t *rechamberSound; 1562 | snd_alias_list_t *rechamberSoundPlayer; 1563 | snd_alias_list_t *reloadSound; 1564 | snd_alias_list_t *reloadSoundPlayer; 1565 | snd_alias_list_t *reloadEmptySound; 1566 | snd_alias_list_t *reloadEmptySoundPlayer; 1567 | snd_alias_list_t *reloadStartSound; 1568 | snd_alias_list_t *reloadStartSoundPlayer; 1569 | snd_alias_list_t *reloadEndSound; 1570 | snd_alias_list_t *reloadEndSoundPlayer; 1571 | snd_alias_list_t *altSwitchSound; 1572 | snd_alias_list_t *raiseSound; 1573 | snd_alias_list_t *putawaySound; 1574 | snd_alias_list_t *noteTrackSoundA; 1575 | snd_alias_list_t *noteTrackSoundB; 1576 | snd_alias_list_t *noteTrackSoundC; 1577 | snd_alias_list_t *noteTrackSoundD; 1578 | FxEffectDef_t *shellEjectEffect; 1579 | FxEffectDef_t *lastShotEjectEffect; 1580 | Material_t *reticleCenter; 1581 | Material_t *reticleSide; 1582 | int iReticleCenterSize; 1583 | int iReticleSideSize; 1584 | int iReticleMinOfs; 1585 | float vStandMove[3]; 1586 | float vStandRot[3]; 1587 | float vDuckedOfs[3]; 1588 | float vDuckedMove[3]; 1589 | float vDuckedRot[3]; 1590 | float vProneOfs[3]; 1591 | float vProneMove[3]; 1592 | float vProneRot[3]; 1593 | float fPosMoveRate; 1594 | float fPosProneMoveRate; 1595 | float fStandMoveMinSpeed; 1596 | float fDuckedMoveMinSpeed; 1597 | float fProneMoveMinSpeed; 1598 | float fPosRotRate; 1599 | float fPosProneRotRate; 1600 | float fStandRotMinSpeed; 1601 | float fDuckedRotMinSpeed; 1602 | float fProneRotMinSpeed; 1603 | const char *worldModel; 1604 | Material_t *hudIcon; 1605 | Material_t *modeIcon; 1606 | int iStartAmmo; 1607 | const char *szAmmoName; 1608 | int iAmmoIndex; 1609 | const char *szClipName; 1610 | int iClipIndex; 1611 | int iMaxAmmo; 1612 | int iClipSize; 1613 | int shotCount; 1614 | const char *szSharedAmmoCapName; 1615 | int iSharedAmmoCapIndex; 1616 | int iSharedAmmoCap; 1617 | int damage; 1618 | int playerDamage; 1619 | int iMeleeDamage; 1620 | int iDamageType; 1621 | int iFireDelay; 1622 | int iMeleeDelay; 1623 | int iFireTime; 1624 | int iRechamberTime; 1625 | int iRechamberBoltTime; 1626 | int iHoldFireTime; 1627 | int iMeleeTime; 1628 | int iReloadTime; 1629 | int iReloadEmptyTime; 1630 | int iReloadAddTime; 1631 | int iReloadStartTime; 1632 | int iReloadStartAddTime; 1633 | int iReloadEndTime; 1634 | int iDropTime; 1635 | int iRaiseTime; 1636 | int iAltDropTime; 1637 | int iAltRaiseTime; 1638 | int quickDropTime; 1639 | int quickRaiseTime; 1640 | int fuseTime; 1641 | float autoAimRange; 1642 | float aimAssistRange; 1643 | float aimAssistRangeAds; 1644 | float aimPadding; 1645 | float enemyCrosshairRange; 1646 | int crosshairColorChange; 1647 | float moveSpeedScale; 1648 | float fAdsZoomFov; 1649 | float fAdsZoomInFrac; 1650 | float fAdsZoomOutFrac; 1651 | Material_t *overlayMaterial; 1652 | weapOverlayReticle_t overlayReticle; 1653 | float overlayWidth; 1654 | float overlayHeight; 1655 | float fAdsBobFactor; 1656 | float fAdsViewBobMult; 1657 | float fHipSpreadStandMin; 1658 | float fHipSpreadDuckedMin; 1659 | float fHipSpreadProneMin; 1660 | float hipSpreadStandMax; 1661 | float hipSpreadDuckedMax; 1662 | float hipSpreadProneMax; 1663 | float fHipSpreadDecayRate; 1664 | float fHipSpreadFireAdd; 1665 | float fHipSpreadTurnAdd; 1666 | float fHipSpreadMoveAdd; 1667 | float fHipSpreadDuckedDecay; 1668 | float fHipSpreadProneDecay; 1669 | float fHipReticleSidePos; 1670 | int iAdsTransInTime; 1671 | int iAdsTransOutTime; 1672 | float fAdsIdleAmount; 1673 | float fHipIdleAmount; 1674 | float adsIdleSpeed; 1675 | float hipIdleSpeed; 1676 | float fIdleCrouchFactor; 1677 | float fIdleProneFactor; 1678 | float fGunMaxPitch; 1679 | float fGunMaxYaw; 1680 | float swayMaxAngle; 1681 | float swayLerpSpeed; 1682 | float swayPitchScale; 1683 | float swayYawScale; 1684 | float swayHorizScale; 1685 | float swayVertScale; 1686 | float swayShellShockScale; 1687 | float adsSwayMaxAngle; 1688 | float adsSwayLerpSpeed; 1689 | float adsSwayPitchScale; 1690 | float adsSwayYawScale; 1691 | float adsSwayHorizScale; 1692 | float adsSwayVertScale; 1693 | int bRifleBullet; 1694 | int armorPiercing; 1695 | int semiAuto; 1696 | int bBoltAction; 1697 | int aimDownSight; 1698 | int bRechamberWhileAds; 1699 | float adsViewErrorMin; 1700 | float adsViewErrorMax; 1701 | int bCookOffHold; 1702 | int bClipOnly; 1703 | int cancelAutoHolsterWhenEmpty; 1704 | int suppressAmmoReserveDisplay; 1705 | Material_t *killIcon; 1706 | weaponIconRatioType_t killIconRatio; 1707 | int flipKillIcon; 1708 | int bNoPartialReload; 1709 | int bSegmentedReload; 1710 | int iReloadAmmoAdd; 1711 | int iReloadStartAdd; 1712 | const char *szAltWeaponName; 1713 | unsigned int altWeaponIndex; 1714 | int iDropAmmoMin; 1715 | int iDropAmmoMax; 1716 | int iExplosionRadius; 1717 | int iExplosionInnerDamage; 1718 | int iExplosionOuterDamage; 1719 | int iProjectileSpeed; 1720 | int iProjectileSpeedUp; 1721 | const char *projectileModel; 1722 | weapProjExposion_t projExplosion; 1723 | FxEffectDef_t *projExplosionEffect; 1724 | snd_alias_list_t *projExplosionSound; 1725 | int bProjImpactExplode; 1726 | float parallelBounce[23]; 1727 | float perpendicularBounce[23]; 1728 | FxEffectDef_t *projTrailEffect; 1729 | int unknown2[4]; 1730 | float fAdsAimPitch; 1731 | float fAdsCrosshairInFrac; 1732 | float fAdsCrosshairOutFrac; 1733 | int adsGunKickReducedKickBullets; 1734 | float adsGunKickReducedKickPercent; 1735 | float fAdsGunKickPitchMin; 1736 | float fAdsGunKickPitchMax; 1737 | float fAdsGunKickYawMin; 1738 | float fAdsGunKickYawMax; 1739 | float fAdsGunKickAccel; 1740 | float fAdsGunKickSpeedMax; 1741 | float fAdsGunKickSpeedDecay; 1742 | float fAdsGunKickStaticDecay; 1743 | float fAdsViewKickPitchMin; 1744 | float fAdsViewKickPitchMax; 1745 | float fAdsViewKickYawMin; 1746 | float fAdsViewKickYawMax; 1747 | float fAdsViewKickCenterSpeed; 1748 | float fAdsViewScatterMin; 1749 | float fAdsViewScatterMax; 1750 | float fAdsSpread; 1751 | int hipGunKickReducedKickBullets; 1752 | float hipGunKickReducedKickPercent; 1753 | float fHipGunKickPitchMin; 1754 | float fHipGunKickPitchMax; 1755 | float fHipGunKickYawMin; 1756 | float fHipGunKickYawMax; 1757 | float fHipGunKickAccel; 1758 | float fHipGunKickSpeedMax; 1759 | float fHipGunKickSpeedDecay; 1760 | float fHipGunKickStaticDecay; 1761 | float fHipViewKickPitchMin; 1762 | float fHipViewKickPitchMax; 1763 | float fHipViewKickYawMin; 1764 | float fHipViewKickYawMax; 1765 | float fHipViewKickCenterSpeed; 1766 | float fHipViewScatterMin; 1767 | float fHipViewScatterMax; 1768 | float fightDist; 1769 | float maxDist; 1770 | const char *aiVsAiAccuracyGraph; 1771 | const char *aiVsPlayerAccuracyGraph; 1772 | int accuracyGraphKnotCount[2]; 1773 | int originalAccuracyGraphKnotCount[2]; 1774 | int iPositionReloadTransTime; 1775 | float leftArc; 1776 | float rightArc; 1777 | float topArc; 1778 | float bottomArc; 1779 | float accuracy; 1780 | float aiSpread; 1781 | float playerSpread; 1782 | int minVertTurnSpeed; 1783 | int minHorTurnSpeed; 1784 | int maxVertTurnSpeed; 1785 | int maxHorTurnSpeed; 1786 | float pitchConvergenceTime; 1787 | float yawConvergenceTime; 1788 | float suppressTime; 1789 | float maxRange; 1790 | float fAnimHorRotateInc; 1791 | float fPlayerPositionDist; 1792 | const char *szUseHintString; 1793 | const char *dropHintString; 1794 | int iUseHintStringIndex; 1795 | int dropHintStringIndex; 1796 | float horizViewJitter; 1797 | float vertViewJitter; 1798 | const char *szScript; 1799 | float fOOPosAnimLength[2]; 1800 | int minDamage; 1801 | int minPlayerDamage; 1802 | float fMaxDamageRange; 1803 | float fMinDamageRange; 1804 | int unknown5[4]; 1805 | float locationDamageMultipliers[19]; 1806 | const char *fireRumble; 1807 | const char *meleeImpactRumble; 1808 | }; 1809 | 1810 | typedef enum 1811 | { 1812 | ANIM_BP_UNUSED = 0x0, 1813 | ANIM_BP_LEGS = 0x1, 1814 | ANIM_BP_TORSO = 0x2, 1815 | ANIM_BP_BOTH = 0x3, 1816 | NUM_ANIM_BODYPARTS = 0x4, 1817 | } animBodyPart_t; 1818 | 1819 | typedef enum 1820 | { 1821 | IT_BAD = 0x0, 1822 | IT_WEAPON = 0x1, 1823 | IT_AMMO = 0x2, 1824 | IT_HEALTH = 0x3, 1825 | IT_HOLDABLE = 0x4, 1826 | } itemType_t; 1827 | 1828 | typedef struct gitem_s 1829 | { 1830 | char *classname; 1831 | char *pickup_sound; 1832 | char *world_model; 1833 | int giTag; 1834 | char *icon; 1835 | char *display_name; 1836 | int quantity; 1837 | itemType_t giType; 1838 | int giAmmoIndex; 1839 | int giClipIndex; 1840 | int giSharedAmmoCapIndex; 1841 | } gitem_t; 1842 | 1843 | typedef struct XBoneInfo_s 1844 | { 1845 | float bounds[2][3]; 1846 | float offset[3]; 1847 | float radiusSquared; 1848 | } XBoneInfo_t; 1849 | 1850 | typedef struct XModelCollSurf_s 1851 | { 1852 | float mins[3]; 1853 | float maxs[3]; 1854 | int boneIdx; 1855 | int contents; 1856 | int surfFlags; 1857 | } XModelCollSurf_t; 1858 | 1859 | typedef struct XModelHighMipBounds_s 1860 | { 1861 | float mins[3]; 1862 | float maxs[3]; 1863 | } XModelHighMipBounds_t; 1864 | 1865 | typedef struct XModelStreamInfo_s 1866 | { 1867 | XModelHighMipBounds_t *highMipBounds; 1868 | } XModelStreamInfo_t; 1869 | 1870 | typedef struct XModel_s 1871 | { 1872 | char numBones; 1873 | char numRootBones; 1874 | unsigned __int16 *boneNames; 1875 | char *parentList; 1876 | byte unk[72]; 1877 | XModelCollSurf_t *collSurfs; 1878 | int numCollSurfs; 1879 | int contents; 1880 | XBoneInfo_t *boneInfo; 1881 | vec3_t mins; 1882 | vec3_t maxs; 1883 | __int16 numLods; 1884 | __int16 collLod; 1885 | XModelStreamInfo_t streamInfo; 1886 | int memUsage; 1887 | const char *name; 1888 | char flags; 1889 | char bad; 1890 | } XModel_t; 1891 | 1892 | typedef struct DObjSkeletonPartMatrix_s 1893 | { 1894 | float p1[4]; 1895 | float p2[4]; 1896 | } DObjSkeletonPartMatrix_t; 1897 | 1898 | typedef struct DSkelPartBits_s 1899 | { 1900 | int anim[4]; 1901 | int control[4]; 1902 | int skel[4]; 1903 | } DSkelPartBits_t; 1904 | 1905 | typedef struct DSkel_s 1906 | { 1907 | DSkelPartBits_t *partBits; 1908 | int timeStamp; 1909 | DObjSkeletonPartMatrix_t *mat; 1910 | } DSkel_t; 1911 | 1912 | typedef struct DObj_s 1913 | { 1914 | int *tree; 1915 | DSkel_t skel; 1916 | unsigned __int16 duplicateParts; 1917 | int unk2; 1918 | byte numModels; 1919 | byte numBones; 1920 | byte duplicatePartsSize; 1921 | byte pad; 1922 | XModel_t *models; 1923 | } DObj_t; 1924 | 1925 | struct pmove_t 1926 | { 1927 | struct playerState_s *ps; 1928 | usercmd_t cmd; 1929 | usercmd_t oldcmd; 1930 | int tracemask; 1931 | int numtouch; 1932 | int touchents[32]; 1933 | vec3_t mins; 1934 | vec3_t maxs; 1935 | float xyspeed; 1936 | int proneChange; 1937 | byte mantleStarted; 1938 | vec3_t mantleEndPos; 1939 | int mantleDuration; 1940 | }; 1941 | 1942 | struct __declspec(align(4)) pml_t 1943 | { 1944 | vec3_t forward; 1945 | vec3_t right; 1946 | vec3_t up; 1947 | float frametime; 1948 | int msec; 1949 | int walking; 1950 | int groundPlane; 1951 | int almostGroundPlane; 1952 | trace_t groundTrace; 1953 | float impactSpeed; 1954 | vec3_t previous_origin; 1955 | vec3_t previous_velocity; 1956 | int field_78; 1957 | }; 1958 | 1959 | typedef struct 1960 | { 1961 | __int16 emptystring; 1962 | __int16 allies; 1963 | __int16 axis; 1964 | __int16 current; 1965 | __int16 damage; 1966 | __int16 death; 1967 | __int16 dlight; 1968 | __int16 done; 1969 | __int16 empty; 1970 | __int16 entity; 1971 | __int16 failed; 1972 | __int16 fraction; 1973 | __int16 goal; 1974 | __int16 grenade; 1975 | __int16 info_notnull; 1976 | __int16 invisible; 1977 | __int16 key1; 1978 | __int16 key2; 1979 | __int16 killanimscript; 1980 | __int16 left; 1981 | __int16 movedone; 1982 | __int16 noclass; 1983 | __int16 normal; 1984 | __int16 pistol; 1985 | __int16 plane_waypoint; 1986 | __int16 player; 1987 | __int16 position; 1988 | __int16 primary; 1989 | __int16 primaryb; 1990 | __int16 prone; 1991 | __int16 right; 1992 | __int16 rocket; 1993 | __int16 rotatedone; 1994 | __int16 script_brushmodel; 1995 | __int16 script_model; 1996 | __int16 script_origin; 1997 | __int16 spectator; 1998 | __int16 stand; 1999 | __int16 surfacetype; 2000 | __int16 target_script_trigger; 2001 | __int16 tempEntity; 2002 | __int16 touch; 2003 | __int16 trigger; 2004 | __int16 trigger_use; 2005 | __int16 trigger_use_touch; 2006 | __int16 trigger_damage; 2007 | __int16 trigger_lookat; 2008 | __int16 truck_cam; 2009 | __int16 worldspawn; 2010 | __int16 binocular_enter; 2011 | __int16 binocular_exit; 2012 | __int16 binocular_fire; 2013 | __int16 binocular_release; 2014 | __int16 binocular_drop; 2015 | __int16 begin; 2016 | __int16 intermission; 2017 | __int16 menuresponse; 2018 | __int16 playing; 2019 | __int16 none; 2020 | __int16 dead; 2021 | __int16 auto_change; 2022 | __int16 manual_change; 2023 | __int16 freelook; 2024 | __int16 call_vote; 2025 | __int16 vote; 2026 | __int16 snd_enveffectsprio_level; 2027 | __int16 snd_enveffectsprio_shellshock; 2028 | __int16 snd_channelvolprio_holdbreath; 2029 | __int16 snd_channelvolprio_pain; 2030 | __int16 snd_channelvolprio_shellshock; 2031 | __int16 tag_flash; 2032 | __int16 tag_flash_11; 2033 | __int16 tag_flash_2; 2034 | __int16 tag_flash_22; 2035 | __int16 tag_brass; 2036 | __int16 j_head; 2037 | __int16 tag_weapon; 2038 | __int16 tag_player; 2039 | __int16 tag_camera; 2040 | __int16 tag_aim; 2041 | __int16 tag_aim_animated; 2042 | __int16 tag_origin; 2043 | __int16 tag_butt; 2044 | __int16 tag_weapon_right; 2045 | __int16 back_low; 2046 | __int16 back_mid; 2047 | __int16 back_up; 2048 | __int16 neck; 2049 | __int16 head; 2050 | __int16 pelvis; 2051 | } stringIndex_t; 2052 | 2053 | struct __declspec(align(4)) bgs_s 2054 | { 2055 | byte animScriptData[736200]; 2056 | int multiplayer; 2057 | int root; 2058 | int torso; 2059 | int legs; 2060 | int turning; 2061 | int turnAnimEndTime; 2062 | int frametime; 2063 | float angle; 2064 | struct XModel *(__stdcall *GetXModel)(const char *); 2065 | void (__stdcall *CreateDObj)(struct DObjModel_s *, unsigned __int16, struct XAnimTree_s *, int, int, struct clientInfo_t *); 2066 | unsigned __int16 (__stdcall *AttachWeapon)(struct DObjModel_s *, unsigned __int16, struct clientInfo_t *); 2067 | struct DObj_s *(__stdcall *GetDObj)(int, int); 2068 | void *(__stdcall *AllocXAnim)(int); 2069 | char field_B3BFC[4043]; 2070 | int field_B4BC8; 2071 | int field_B4BCC; 2072 | int field_B4BD0; 2073 | int field_B4BD4; 2074 | int field_B4BD8; 2075 | int field_B4BDC; 2076 | int field_B4BE0; 2077 | int field_B4BE4; 2078 | int field_B4BE8; 2079 | int field_B4BEC; 2080 | int field_B4BF0; 2081 | int field_B4BF4; 2082 | int field_B4BF8; 2083 | }; 2084 | 2085 | struct cg_t 2086 | { 2087 | char gap0[1001887]; 2088 | char field_F499F; 2089 | }; 2090 | 2091 | struct cgs_t 2092 | { 2093 | char gap0[174419]; 2094 | char field_2A953; 2095 | }; 2096 | 2097 | struct centity_s 2098 | { 2099 | char gap0[547]; 2100 | char field_223; 2101 | }; 2102 | 2103 | struct clientStatic_t 2104 | { 2105 | char gap0[3002367]; 2106 | char field_2DCFFF; 2107 | }; 2108 | 2109 | struct __declspec(align(4)) scrCompilePub_t 2110 | { 2111 | char gap_0[20]; 2112 | int bultinMeth; 2113 | char gap_18[28]; 2114 | int func_table_size; 2115 | int gap_38[1024]; 2116 | }; 2117 | } 2118 | -------------------------------------------------------------------------------- /src/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | 3 | namespace Main 4 | { 5 | static BYTE originalCode[5]; 6 | static PBYTE originalEP = 0; 7 | 8 | void UnprotectModule(HMODULE hModule) 9 | { 10 | PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule; 11 | PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew); 12 | 13 | // unprotect the entire PE image 14 | SIZE_T size = ntHeader->OptionalHeader.SizeOfImage; 15 | DWORD oldProtect; 16 | VirtualProtect((LPVOID)hModule, size, PAGE_EXECUTE_READWRITE, &oldProtect); 17 | } 18 | 19 | void DoInit() 20 | { 21 | // return to the original EP 22 | memcpy(originalEP, &originalCode, sizeof(originalCode)); 23 | 24 | // unprotect our entire PE image 25 | HMODULE hModule; 26 | if (SUCCEEDED(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)DoInit, &hModule))) 27 | { 28 | UnprotectModule(hModule); 29 | } 30 | 31 | // detect which executable's patches to apply 32 | DWORD dataStrData = Utils::Hook::Get(0x59B69C); 33 | if (dataStrData == 0x6C6C6143) 34 | Components::Loader::Initialize(GAMEEXE::MP); 35 | 36 | hModule = GetModuleHandle(NULL); 37 | PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule; 38 | PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew); 39 | 40 | // back up original code 41 | originalEP = (PBYTE)((DWORD)hModule + ntHeader->OptionalHeader.AddressOfEntryPoint); 42 | 43 | __asm 44 | { 45 | jmp originalEP 46 | } 47 | } 48 | 49 | void SetSafeInit() 50 | { 51 | // find the entry point for the executable process, set page access, and replace the EP 52 | HMODULE hModule = GetModuleHandle(NULL); // passing NULL should be safe even with the loader lock being held (according to ReactOS ldr.c) 53 | 54 | if (hModule) 55 | { 56 | PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule; 57 | PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew); 58 | 59 | UnprotectModule(hModule); 60 | 61 | // back up original code 62 | PBYTE ep = (PBYTE)((DWORD)hModule + ntHeader->OptionalHeader.AddressOfEntryPoint); 63 | memcpy(originalCode, ep, sizeof(originalCode)); 64 | 65 | // patch to call our EP 66 | int newEP = (int)DoInit - ((int)ep + 5); 67 | ep[0] = 0xE9; // for some reason this doesn't work properly when run under the debugger 68 | memcpy(&ep[1], &newEP, 4); 69 | 70 | originalEP = ep; 71 | } 72 | } 73 | } 74 | 75 | 76 | bool APIENTRY DllMain(HMODULE, DWORD dwReason, LPVOID) 77 | { 78 | if (dwReason == DLL_PROCESS_ATTACH) 79 | { 80 | DWORD textSegData = Utils::Hook::Get(0x401000); 81 | 82 | // detection for all executables to hook into 83 | if (textSegData == 0x0400EC81) 84 | Main::SetSafeInit(); 85 | } 86 | return true; 87 | } 88 | -------------------------------------------------------------------------------- /src/Resource.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #pragma code_page(65001) 4 | 5 | #include "STDInclude.hpp" 6 | 7 | #define APSTUDIO_READONLY_SYMBOLS 8 | ///////////////////////////////////////////////////////////////////////////// 9 | // 10 | // Generated from the TEXTINCLUDE 2 resource. 11 | // 12 | #include "windows.h" 13 | 14 | ///////////////////////////////////////////////////////////////////////////// 15 | #undef APSTUDIO_READONLY_SYMBOLS 16 | 17 | ///////////////////////////////////////////////////////////////////////////// 18 | // English (United States) resources 19 | 20 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 21 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 22 | 23 | #ifdef APSTUDIO_INVOKED 24 | ///////////////////////////////////////////////////////////////////////////// 25 | // 26 | // TEXTINCLUDE 27 | // 28 | 29 | 1 TEXTINCLUDE 30 | BEGIN 31 | "#include ""windows.h""\r\n" 32 | "\0" 33 | END 34 | 35 | 2 TEXTINCLUDE 36 | BEGIN 37 | "\r\n" 38 | "\0" 39 | END 40 | 41 | #endif // APSTUDIO_INVOKED 42 | 43 | ///////////////////////////////////////////////////////////////////////////// 44 | // 45 | // Version 46 | // 47 | 48 | VS_VERSION_INFO VERSIONINFO 49 | FILEFLAGSMASK 0x3fL 50 | #ifdef _DEBUG 51 | FILEFLAGS 0x1L 52 | #else 53 | FILEFLAGS 0x0L 54 | #endif 55 | FILEOS 0x40004L 56 | FILETYPE VFT_DLL 57 | FILESUBTYPE 0x0L 58 | BEGIN 59 | BLOCK "StringFileInfo" 60 | BEGIN 61 | BLOCK "040904b0" 62 | BEGIN 63 | VALUE "CompanyName", "CoD2m" 64 | #ifdef _DEBUG 65 | VALUE "FileDescription", "CoD2 client/server modification (DEBUG)" 66 | #else 67 | VALUE "FileDescription", "CoD2 client/server modification" 68 | #endif 69 | VALUE "FileVersion", SHORTVERSION 70 | VALUE "InternalName", "cod2m" 71 | VALUE "LegalCopyright", "All rights reserved." 72 | VALUE "OriginalFilename", "d3d9.dll" 73 | VALUE "ProductName", "CoD2m" 74 | VALUE "ProductVersion", SHORTVERSION 75 | END 76 | END 77 | BLOCK "VarFileInfo" 78 | BEGIN 79 | VALUE "Translation", 0x409, 1200 80 | END 81 | END 82 | 83 | #endif // English (United States) resources 84 | ///////////////////////////////////////////////////////////////////////////// 85 | 86 | 87 | 88 | #ifndef APSTUDIO_INVOKED 89 | ///////////////////////////////////////////////////////////////////////////// 90 | // 91 | // Generated from the TEXTINCLUDE 3 resource. 92 | // 93 | 94 | 95 | ///////////////////////////////////////////////////////////////////////////// 96 | #endif // not APSTUDIO_INVOKED 97 | 98 | -------------------------------------------------------------------------------- /src/SDLLP.cpp: -------------------------------------------------------------------------------- 1 | // --------------------------------------+ 2 | // System Dynamic Link Library Proxy 3 | // by momo5502 4 | // --------------------------------------+ 5 | 6 | #include "STDInclude.hpp" 7 | 8 | // Macro to declare an export 9 | // --------------------------------------+ 10 | #define EXPORT(_export) extern "C" __declspec(naked) __declspec(dllexport) void _export() { static FARPROC function = 0; if(!function) function = SDLLP::GetExport(__FUNCTION__, LIBRARY); __asm { jmp function } } 11 | 12 | // Static class 13 | // --------------------------------------+ 14 | class SDLLP 15 | { 16 | private: 17 | static std::map mLibraries; 18 | 19 | static void Log(const char* message, ...); 20 | static void LoadLibrary(const char* library); 21 | static bool IsLibraryLoaded(const char* library); 22 | 23 | public: 24 | static FARPROC GetExport(const char* function, const char* library); 25 | }; 26 | 27 | // Class variable declarations 28 | // --------------------------------------+ 29 | std::map SDLLP::mLibraries; 30 | 31 | // Load necessary library 32 | // --------------------------------------+ 33 | void SDLLP::LoadLibrary(const char* library) 34 | { 35 | Log("[SDLLP] Loading library '%s'.", library); 36 | 37 | CHAR mPath[MAX_PATH]; 38 | 39 | GetSystemDirectoryA(mPath, MAX_PATH); 40 | strcat_s(mPath, "\\"); 41 | strcat_s(mPath, library); 42 | 43 | mLibraries[library] = ::LoadLibraryA(mPath); 44 | 45 | if (!IsLibraryLoaded(library)) Log("[SDLLP] Unable to load library '%s'.", library); 46 | } 47 | 48 | // Check if export already loaded 49 | // --------------------------------------+ 50 | bool SDLLP::IsLibraryLoaded(const char* library) 51 | { 52 | return (mLibraries.find(library) != mLibraries.end() && mLibraries[library]); 53 | } 54 | 55 | // Get export address 56 | // --------------------------------------+ 57 | FARPROC SDLLP::GetExport(const char* function, const char* library) 58 | { 59 | Log("[SDLLP] Export '%s' requested from %s.", function, library); 60 | 61 | if (!IsLibraryLoaded(library)) LoadLibrary(library); 62 | 63 | FARPROC address = GetProcAddress(mLibraries[library], function); 64 | 65 | if (!address) Log("[SDLLP] Unable to load export '%s' from library '%s'.", function, library); 66 | return address; 67 | } 68 | 69 | // Write debug string 70 | // --------------------------------------+ 71 | void SDLLP::Log(const char* message, ...) 72 | { 73 | CHAR buffer[1024]; 74 | va_list ap; 75 | 76 | va_start(ap, message); 77 | vsprintf(buffer, message, ap); 78 | va_end(ap); 79 | 80 | OutputDebugStringA(buffer); 81 | } 82 | 83 | // --------------------------------------+ 84 | // Adapt export functions and library 85 | // --------------------------------------+ 86 | 87 | #define LIBRARY "d3d9.dll" 88 | EXPORT(D3DPERF_BeginEvent) 89 | EXPORT(D3DPERF_EndEvent) 90 | EXPORT(Direct3DCreate9) 91 | -------------------------------------------------------------------------------- /src/STDInclude.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | 3 | // Rename sections 4 | #ifndef DEBUG 5 | #pragma comment(linker, "/merge:.text=.UPX0") 6 | #pragma comment(linker, "/merge:.data=.UPX1") 7 | #pragma comment(linker, "/merge:.rdata=.UPX2") 8 | #pragma comment(linker, "/merge:.tls=.UPX3") 9 | #pragma comment(linker, "/merge:.gfids=.UPX4") 10 | #endif 11 | 12 | #pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 13 | 14 | // Do necessary assertions here 15 | // Some compilers treat them differently which causes a size mismatch 16 | 17 | // WinAPI types 18 | AssertSize(DWORD, 4); 19 | AssertSize(WORD, 2); 20 | AssertSize(BYTE, 1); 21 | 22 | // 128 bit integers (only x64) 23 | //AssertSize(__int128, 16); 24 | //AssertSize(unsigned __int128, 16); 25 | 26 | // 64 bit integers 27 | AssertSize(__int64, 8); 28 | AssertSize(unsigned __int64, 8); 29 | AssertSize(long long, 8); 30 | AssertSize(unsigned long long, 8); 31 | AssertSize(int64_t, 8); 32 | AssertSize(uint64_t, 8); 33 | AssertSize(std::int64_t, 8); 34 | AssertSize(std::uint64_t, 8); 35 | 36 | // 64 bit double precision floating point numbers 37 | AssertSize(double, 8); 38 | 39 | // 32 bit integers 40 | AssertSize(__int32, 4); 41 | AssertSize(unsigned __int32, 4); 42 | AssertSize(int, 4); 43 | AssertSize(unsigned int, 4); 44 | AssertSize(long, 4); 45 | AssertSize(unsigned long, 4); 46 | AssertSize(int32_t, 4); 47 | AssertSize(uint32_t, 4); 48 | AssertSize(std::int32_t, 4); 49 | AssertSize(std::uint32_t, 4); 50 | 51 | // 32 bit single precision floating point numbers 52 | AssertSize(float, 4); 53 | 54 | // 16 bit integers 55 | AssertSize(__int16, 2); 56 | AssertSize(unsigned __int16, 2); 57 | AssertSize(short, 2); 58 | AssertSize(unsigned short, 2); 59 | AssertSize(int16_t, 2); 60 | AssertSize(uint16_t, 2); 61 | AssertSize(std::int16_t, 2); 62 | AssertSize(std::uint16_t, 2); 63 | 64 | // 8 bit integers 65 | AssertSize(bool, 1); 66 | AssertSize(__int8, 1); 67 | AssertSize(unsigned __int8, 1); 68 | AssertSize(char, 1); 69 | AssertSize(unsigned char, 1); 70 | AssertSize(int8_t, 1); 71 | AssertSize(uint8_t, 1); 72 | AssertSize(std::int8_t, 1); 73 | AssertSize(std::uint8_t, 1); 74 | 75 | // Ensure pointers are 4 bytes in size (32-bit) 76 | // ReSharper disable CppRedundantBooleanExpressionArgument 77 | static_assert(sizeof(intptr_t) == 4 && sizeof(void*) == 4 && sizeof(size_t) == 4, "This doesn't seem to be a 32-bit environment!"); 78 | // ReSharper restore CppRedundantBooleanExpressionArgument 79 | 80 | #if !defined(_M_IX86) 81 | #error "Invalid processor achritecture!" 82 | #endif 83 | 84 | extern "C" 85 | { 86 | // Disable telemetry data logging 87 | void __cdecl __vcrt_initialize_telemetry_provider() {} 88 | void __cdecl __telemetry_main_invoke_trigger() {} 89 | void __cdecl __telemetry_main_return_trigger() {} 90 | void __cdecl __vcrt_uninitialize_telemetry_provider() {} 91 | 92 | // Enable 'High Performance Graphics' 93 | __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; 94 | 95 | // Tommath fixes 96 | int s_read_arc4random(void*, size_t) 97 | { 98 | return -1; 99 | } 100 | 101 | int s_read_getrandom(void*, size_t) 102 | { 103 | return -1; 104 | } 105 | 106 | int s_read_urandom(void*, size_t) 107 | { 108 | return -1; 109 | } 110 | 111 | int s_read_ltm_rng(void*, size_t) 112 | { 113 | return -1; 114 | } 115 | }; 116 | -------------------------------------------------------------------------------- /src/STDInclude.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Version number 4 | #include "version.h" 5 | 6 | #ifndef RC_INVOKED 7 | 8 | #define _HAS_CXX17 1 9 | #define _HAS_CXX20 1 10 | #define VC_EXTRALEAN 11 | #define WIN32_LEAN_AND_MEAN 12 | #define _CRT_SECURE_NO_WARNINGS 13 | 14 | // Requires Visual Leak Detector plugin: http://vld.codeplex.com/ 15 | #define VLD_FORCE_ENABLE 16 | //#include 17 | #pragma warning(disable: 4740) 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #pragma warning(push) 30 | #pragma warning(disable: 4091) 31 | #pragma warning(disable: 4244) 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | // Experimental C++17 features 44 | #include 45 | #include 46 | 47 | #pragma warning(pop) 48 | 49 | // Usefull for debugging 50 | template class Sizer { }; 51 | #define BindNum(x, y) Sizer y; 52 | #define Size_Of(x, y) BindNum(sizeof(x), y) 53 | #define Offset_Of(x, y, z) BindNum(offsetof(x, y), z) 54 | 55 | // Submodules 56 | // Ignore the warnings, it's not our code! 57 | #pragma warning(push) 58 | #pragma warning(disable: 4005) 59 | #pragma warning(disable: 4091) 60 | #pragma warning(disable: 4100) 61 | #pragma warning(disable: 4244) 62 | #pragma warning(disable: 4389) 63 | #pragma warning(disable: 4702) 64 | #pragma warning(disable: 4800) 65 | #pragma warning(disable: 4996) // _CRT_SECURE_NO_WARNINGS 66 | #pragma warning(disable: 5054) 67 | #pragma warning(disable: 6001) 68 | #pragma warning(disable: 6011) 69 | #pragma warning(disable: 6031) 70 | #pragma warning(disable: 6255) 71 | #pragma warning(disable: 6258) 72 | #pragma warning(disable: 6386) 73 | #pragma warning(disable: 6387) 74 | 75 | #ifdef max 76 | #undef max 77 | #endif 78 | 79 | #ifdef min 80 | #undef min 81 | #endif 82 | 83 | #pragma warning(pop) 84 | 85 | enum GAMEEXE 86 | { 87 | MP 88 | }; 89 | 90 | #include "Utils/Hooking.hpp" 91 | #include "Utils/Memory.hpp" 92 | #include "Utils/String.hpp" 93 | #include "Utils/Time.hpp" 94 | #include "Utils/Utils.hpp" 95 | 96 | #include "Game/Structs.hpp" 97 | #include "Game/Game.hpp" 98 | 99 | #include "Components/Loader.hpp" 100 | 101 | // Libraries 102 | #pragma comment(lib, "Winmm.lib") 103 | #pragma comment(lib, "Crypt32.lib") 104 | #pragma comment(lib, "Ws2_32.lib") 105 | #pragma comment(lib, "Wininet.lib") 106 | #pragma comment(lib, "shlwapi.lib") 107 | #pragma comment(lib, "Urlmon.lib") 108 | #pragma comment(lib, "Advapi32.lib") 109 | #pragma comment(lib, "rpcrt4.lib") 110 | #pragma comment(lib, "dbghelp.lib") 111 | 112 | // Enable additional literals 113 | using namespace std::literals; 114 | 115 | #endif 116 | 117 | #define STRINGIZE_(x) #x 118 | #define STRINGIZE(x) STRINGIZE_(x) 119 | 120 | #define AssertSize(x, size) static_assert(sizeof(x) == size, STRINGIZE(x) " structure has an invalid size.") 121 | #define AssertOffset(x, y, offset) static_assert(offsetof(x, y) == offset, STRINGIZE(x) "::" STRINGIZE(y) " is not at the right offset.") 122 | 123 | // Resource stuff 124 | #ifdef APSTUDIO_INVOKED 125 | #ifndef APSTUDIO_READONLY_SYMBOLS 126 | // Defines below make accessing the resources from the code easier. 127 | #define _APS_NEXT_RESOURCE_VALUE 102 128 | #define _APS_NEXT_COMMAND_VALUE 40001 129 | #define _APS_NEXT_CONTROL_VALUE 1001 130 | #define _APS_NEXT_SYMED_VALUE 101 131 | #endif 132 | #endif 133 | -------------------------------------------------------------------------------- /src/Utils/Hooking.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | 3 | namespace Utils 4 | { 5 | std::map Hook::Interceptor::IReturn; 6 | std::map Hook::Interceptor::ICallbacks; 7 | 8 | void Hook::Signature::process() 9 | { 10 | if (this->signatures.empty()) return; 11 | 12 | char* _start = reinterpret_cast(this->start); 13 | 14 | unsigned int sigCount = this->signatures.size(); 15 | Hook::Signature::Container* containers = this->signatures.data(); 16 | 17 | for (size_t i = 0; i < this->length; ++i) 18 | { 19 | char* address = _start + i; 20 | 21 | for (unsigned int k = 0; k < sigCount; ++k) 22 | { 23 | Hook::Signature::Container* container = &containers[k]; 24 | 25 | unsigned int j; 26 | for (j = 0; j < strlen(container->mask); ++j) 27 | { 28 | if (container->mask[j] != '?' &&container->signature[j] != address[j]) 29 | { 30 | break; 31 | } 32 | } 33 | 34 | if (j == strlen(container->mask)) 35 | { 36 | container->callback(address); 37 | } 38 | } 39 | } 40 | } 41 | 42 | void Hook::Signature::add(Hook::Signature::Container& container) 43 | { 44 | Hook::Signature::signatures.push_back(container); 45 | } 46 | 47 | void Hook::Interceptor::Install(void* place, void* stub) 48 | { 49 | return Hook::Interceptor::Install(place, static_cast(stub)); 50 | } 51 | 52 | void Hook::Interceptor::Install(void* place, void(*stub)()) 53 | { 54 | return Hook::Interceptor::Install(reinterpret_cast(place), stub); 55 | } 56 | 57 | void Hook::Interceptor::Install(void** place, void(*stub)()) 58 | { 59 | Hook::Interceptor::IReturn[place] = *place; 60 | Hook::Interceptor::ICallbacks[place] = stub; 61 | *place = Hook::Interceptor::InterceptionStub; 62 | } 63 | 64 | __declspec(naked) void Hook::Interceptor::InterceptionStub() 65 | { 66 | __asm 67 | { 68 | sub esp, 4h // Reserve space on the stack for the return address 69 | pushad // Store registers 70 | 71 | lea eax, [esp + 20h] // Load initial stack pointer 72 | push eax // Push it onto the stack 73 | 74 | call Hook::Interceptor::RunCallback // Run the callback based on the given stack pointer 75 | call Hook::Interceptor::PopReturn // Get the initial return address according to the stack pointer 76 | 77 | add esp, 4h // Clear the stack 78 | 79 | mov [esp + 20h], eax // Store the return address at the reserved space 80 | popad // Restore the registers 81 | 82 | retn // Return (jump to our return address) 83 | } 84 | } 85 | 86 | void Hook::Interceptor::RunCallback(void* place) 87 | { 88 | auto iCallback = Hook::Interceptor::ICallbacks.find(place); 89 | if (iCallback != Hook::Interceptor::ICallbacks.end()) 90 | { 91 | iCallback->second(); 92 | Hook::Interceptor::ICallbacks.erase(iCallback); 93 | } 94 | } 95 | 96 | void* Hook::Interceptor::PopReturn(void* _place) 97 | { 98 | void* retVal = nullptr; 99 | 100 | auto iReturn = Hook::Interceptor::IReturn.find(_place); 101 | if (iReturn != Hook::Interceptor::IReturn.end()) 102 | { 103 | retVal = iReturn->second; 104 | Hook::Interceptor::IReturn.erase(iReturn); 105 | } 106 | 107 | return retVal; 108 | } 109 | 110 | Hook::~Hook() 111 | { 112 | if (this->initialized) 113 | { 114 | this->uninstall(); 115 | } 116 | } 117 | 118 | Hook* Hook::initialize(DWORD _place, void(*_stub)(), bool _useJump) 119 | { 120 | return this->initialize(_place, reinterpret_cast(_stub), _useJump); 121 | } 122 | 123 | Hook* Hook::initialize(DWORD _place, void* _stub, bool _useJump) 124 | { 125 | return this->initialize(reinterpret_cast(_place), _stub, _useJump); 126 | } 127 | 128 | Hook* Hook::initialize(void* _place, void* _stub, bool _useJump) 129 | { 130 | if (this->initialized) return this; 131 | this->initialized = true; 132 | 133 | this->useJump = _useJump; 134 | this->place = _place; 135 | this->stub = _stub; 136 | 137 | this->original = static_cast(this->place) + 5 + *reinterpret_cast((static_cast(this->place) + 1)); 138 | 139 | return this; 140 | } 141 | 142 | Hook* Hook::install(bool unprotect, bool keepUnprotected) 143 | { 144 | std::lock_guard _(this->stateMutex); 145 | 146 | if (!this->initialized || this->installed) 147 | { 148 | return this; 149 | } 150 | 151 | this->installed = true; 152 | 153 | if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), PAGE_EXECUTE_READWRITE, &this->protection); 154 | std::memcpy(this->buffer, this->place, sizeof(this->buffer)); 155 | 156 | char* code = static_cast(this->place); 157 | 158 | *code = static_cast(this->useJump ? 0xE9 : 0xE8); 159 | 160 | *reinterpret_cast(code + 1) = reinterpret_cast(this->stub) - (reinterpret_cast(this->place) + 5); 161 | 162 | if (unprotect && !keepUnprotected) VirtualProtect(this->place, sizeof(this->buffer), this->protection, &this->protection); 163 | 164 | FlushInstructionCache(GetCurrentProcess(), this->place, sizeof(this->buffer)); 165 | 166 | return this; 167 | } 168 | 169 | void Hook::quick() 170 | { 171 | if (Hook::installed) 172 | { 173 | Hook::installed = false; 174 | } 175 | } 176 | 177 | Hook* Hook::uninstall(bool unprotect) 178 | { 179 | std::lock_guard _(this->stateMutex); 180 | 181 | if (!this->initialized || !this->installed) 182 | { 183 | return this; 184 | } 185 | 186 | this->installed = false; 187 | 188 | if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), PAGE_EXECUTE_READWRITE, &this->protection); 189 | 190 | std::memcpy(this->place, this->buffer, sizeof(this->buffer)); 191 | 192 | if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), this->protection, &this->protection); 193 | 194 | FlushInstructionCache(GetCurrentProcess(), this->place, sizeof(this->buffer)); 195 | 196 | return this; 197 | } 198 | 199 | void* Hook::getAddress() 200 | { 201 | return this->place; 202 | } 203 | 204 | void Hook::Nop(void* place, size_t length) 205 | { 206 | DWORD oldProtect; 207 | VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &oldProtect); 208 | 209 | memset(place, 0x90, length); 210 | 211 | VirtualProtect(place, length, oldProtect, &oldProtect); 212 | FlushInstructionCache(GetCurrentProcess(), place, length); 213 | } 214 | 215 | void Hook::Nop(DWORD place, size_t length) 216 | { 217 | Nop(reinterpret_cast(place), length); 218 | } 219 | 220 | void Hook::SetString(void* place, const char* string, size_t length) 221 | { 222 | DWORD oldProtect; 223 | VirtualProtect(place, length + 1, PAGE_EXECUTE_READWRITE, &oldProtect); 224 | 225 | strncpy_s(static_cast(place), length, string, length); 226 | 227 | VirtualProtect(place, length + 1, oldProtect, &oldProtect); 228 | } 229 | 230 | void Hook::SetString(DWORD place, const char* string, size_t length) 231 | { 232 | Hook::SetString(reinterpret_cast(place), string, length); 233 | } 234 | 235 | void Hook::SetString(void* place, const char* string) 236 | { 237 | Hook::SetString(place, string, strlen(static_cast(place))); 238 | } 239 | 240 | void Hook::SetString(DWORD place, const char* string) 241 | { 242 | Hook::SetString(reinterpret_cast(place), string); 243 | } 244 | 245 | void Hook::RedirectJump(void* place, void* stub) 246 | { 247 | char* operandPtr = static_cast(place) + 2; 248 | int newOperand = reinterpret_cast(stub) - (reinterpret_cast(place) + 6); 249 | Utils::Hook::Set(operandPtr, newOperand); 250 | } 251 | 252 | void Hook::RedirectJump(DWORD place, void* stub) 253 | { 254 | Hook::RedirectJump(reinterpret_cast(place), stub); 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/Utils/Hooking.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define HOOK_JUMP true 4 | #define HOOK_CALL false 5 | 6 | namespace Utils 7 | { 8 | class Hook 9 | { 10 | public: 11 | class Signature 12 | { 13 | public: 14 | struct Container 15 | { 16 | const char* signature; 17 | const char* mask; 18 | std::function callback; 19 | }; 20 | 21 | Signature(void* _start, size_t _length) : start(_start), length(_length) {} 22 | Signature(DWORD _start, size_t _length) : Signature(reinterpret_cast(_start), _length) {} 23 | Signature() : Signature(0x400000, 0x800000) {} 24 | 25 | void process(); 26 | void add(Container& container); 27 | 28 | private: 29 | void* start; 30 | size_t length; 31 | std::vector signatures; 32 | }; 33 | 34 | class Interceptor 35 | { 36 | public: 37 | static void Install(void* place, void* stub); 38 | static void Install(void* place, void(*stub)()); 39 | static void Install(void** place, void(*stub)()); 40 | 41 | private: 42 | static std::map IReturn; 43 | static std::map ICallbacks; 44 | 45 | static void InterceptionStub(); 46 | static void RunCallback(void* place); 47 | static void* PopReturn(void* place); 48 | }; 49 | 50 | Hook() : initialized(false), installed(false), place(nullptr), stub(nullptr), original(nullptr), useJump(false), protection(0) { ZeroMemory(this->buffer, sizeof(this->buffer)); } 51 | 52 | Hook(void* place, void* stub, bool useJump = true) : Hook() { this->initialize(place, stub, useJump); } 53 | Hook(void* place, void(*stub)(), bool useJump = true) : Hook(place, reinterpret_cast(stub), useJump) {} 54 | 55 | Hook(DWORD place, void* stub, bool useJump = true) : Hook(reinterpret_cast(place), stub, useJump) {} 56 | Hook(DWORD place, DWORD stub, bool useJump = true) : Hook(reinterpret_cast(place), reinterpret_cast(stub), useJump) {} 57 | Hook(DWORD place, void(*stub)(), bool useJump = true) : Hook(reinterpret_cast(place), reinterpret_cast(stub), useJump) {} 58 | 59 | ~Hook(); 60 | 61 | Hook* initialize(void* place, void* stub, bool useJump = true); 62 | Hook* initialize(DWORD place, void* stub, bool useJump = true); 63 | Hook* initialize(DWORD place, void(*stub)(), bool useJump = true); // For lambdas 64 | Hook* install(bool unprotect = true, bool keepUnprotected = false); 65 | Hook* uninstall(bool unprotect = true); 66 | 67 | void* getAddress(); 68 | void quick(); 69 | 70 | template static std::function Call(DWORD function) 71 | { 72 | return std::function(reinterpret_cast(function)); 73 | } 74 | 75 | template static std::function Call(FARPROC function) 76 | { 77 | return Call(reinterpret_cast(function)); 78 | } 79 | 80 | template static std::function Call(void* function) 81 | { 82 | return Call(reinterpret_cast(function)); 83 | } 84 | 85 | static void SetString(void* place, const char* string, size_t length); 86 | static void SetString(DWORD place, const char* string, size_t length); 87 | 88 | static void SetString(void* place, const char* string); 89 | static void SetString(DWORD place, const char* string); 90 | 91 | static void Nop(void* place, size_t length); 92 | static void Nop(DWORD place, size_t length); 93 | 94 | static void RedirectJump(void* place, void* stub); 95 | static void RedirectJump(DWORD place, void* stub); 96 | 97 | template static void Set(void* place, T value) 98 | { 99 | DWORD oldProtect; 100 | VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect); 101 | 102 | *static_cast(place) = value; 103 | 104 | VirtualProtect(place, sizeof(T), oldProtect, &oldProtect); 105 | FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); 106 | } 107 | 108 | template static void Set(DWORD place, T value) 109 | { 110 | return Set(reinterpret_cast(place), value); 111 | } 112 | 113 | template static void Xor(void* place, T value) 114 | { 115 | DWORD oldProtect; 116 | VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect); 117 | 118 | *static_cast(place) ^= value; 119 | 120 | VirtualProtect(place, sizeof(T), oldProtect, &oldProtect); 121 | FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); 122 | } 123 | 124 | template static void Xor(DWORD place, T value) 125 | { 126 | return Xor(reinterpret_cast(place), value); 127 | } 128 | 129 | template static void Or(void* place, T value) 130 | { 131 | DWORD oldProtect; 132 | VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect); 133 | 134 | *static_cast(place) |= value; 135 | 136 | VirtualProtect(place, sizeof(T), oldProtect, &oldProtect); 137 | FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); 138 | } 139 | 140 | template static void Or(DWORD place, T value) 141 | { 142 | return Or(reinterpret_cast(place), value); 143 | } 144 | 145 | template static void And(void* place, T value) 146 | { 147 | DWORD oldProtect; 148 | VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect); 149 | 150 | *static_cast(place) &= value; 151 | 152 | VirtualProtect(place, sizeof(T), oldProtect, &oldProtect); 153 | FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); 154 | } 155 | 156 | template static void And(DWORD place, T value) 157 | { 158 | return And(reinterpret_cast(place), value); 159 | } 160 | 161 | template static T Get(void* place) 162 | { 163 | return *static_cast(place); 164 | } 165 | 166 | template static T Get(DWORD place) 167 | { 168 | return Get(reinterpret_cast(place)); 169 | } 170 | 171 | private: 172 | bool initialized; 173 | bool installed; 174 | 175 | void* place; 176 | void* stub; 177 | void* original; 178 | char buffer[5]; 179 | bool useJump; 180 | 181 | DWORD protection; 182 | 183 | std::mutex stateMutex; 184 | }; 185 | } 186 | -------------------------------------------------------------------------------- /src/Utils/Memory.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | 3 | namespace Utils 4 | { 5 | Utils::Memory::Allocator Memory::MemAllocator; 6 | 7 | void* Memory::AllocateAlign(size_t length, size_t alignment) 8 | { 9 | void* data = _aligned_malloc(length, alignment); 10 | assert(data != nullptr); 11 | if (data) ZeroMemory(data, length); 12 | return data; 13 | } 14 | 15 | void* Memory::Allocate(size_t length) 16 | { 17 | void* data = calloc(length, 1); 18 | assert(data != nullptr); 19 | return data; 20 | } 21 | 22 | char* Memory::DuplicateString(const std::string& string) 23 | { 24 | char* newString = Memory::AllocateArray(string.size() + 1); 25 | std::memcpy(newString, string.data(), string.size()); 26 | return newString; 27 | } 28 | 29 | void Memory::Free(void* data) 30 | { 31 | if (data) 32 | { 33 | free(data); 34 | } 35 | } 36 | 37 | void Memory::Free(const void* data) 38 | { 39 | Memory::Free(const_cast(data)); 40 | } 41 | 42 | void Memory::FreeAlign(void* data) 43 | { 44 | if (data) 45 | { 46 | _aligned_free(data); 47 | } 48 | } 49 | 50 | void Memory::FreeAlign(const void* data) 51 | { 52 | Memory::FreeAlign(const_cast(data)); 53 | } 54 | 55 | // Complementary function for memset, which checks if memory is filled with a char 56 | bool Memory::IsSet(void* mem, char chr, size_t length) 57 | { 58 | char* memArr = reinterpret_cast(mem); 59 | 60 | for (size_t i = 0; i < length; ++i) 61 | { 62 | if (memArr[i] != chr) 63 | { 64 | return false; 65 | } 66 | } 67 | 68 | return true; 69 | } 70 | 71 | bool Memory::IsBadReadPtr(const void* ptr) 72 | { 73 | MEMORY_BASIC_INFORMATION mbi = { nullptr }; 74 | if (VirtualQuery(ptr, &mbi, sizeof(mbi))) 75 | { 76 | DWORD mask = (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); 77 | bool b = !(mbi.Protect & mask); 78 | // check the page is not a guard page 79 | if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; 80 | 81 | return b; 82 | } 83 | return true; 84 | } 85 | 86 | bool Memory::IsBadCodePtr(const void* ptr) 87 | { 88 | MEMORY_BASIC_INFORMATION mbi = { nullptr }; 89 | if (VirtualQuery(ptr, &mbi, sizeof(mbi))) 90 | { 91 | DWORD mask = (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); 92 | bool b = !(mbi.Protect & mask); 93 | // check the page is not a guard page 94 | if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; 95 | 96 | return b; 97 | } 98 | return true; 99 | } 100 | 101 | Utils::Memory::Allocator* Memory::GetAllocator() 102 | { 103 | return &Memory::MemAllocator; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Utils/Memory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Utils 4 | { 5 | class Memory 6 | { 7 | public: 8 | class Allocator 9 | { 10 | public: 11 | typedef void(*FreeCallback)(void*); 12 | 13 | Allocator() 14 | { 15 | this->pool.clear(); 16 | this->refMemory.clear(); 17 | } 18 | ~Allocator() 19 | { 20 | this->clear(); 21 | } 22 | 23 | void clear() 24 | { 25 | std::lock_guard _(this->mutex); 26 | 27 | for (auto i = this->refMemory.begin(); i != this->refMemory.end(); ++i) 28 | { 29 | if (i->first && i->second) 30 | { 31 | i->second(i->first); 32 | } 33 | } 34 | 35 | this->refMemory.clear(); 36 | 37 | for (auto& data : this->pool) 38 | { 39 | Memory::Free(data); 40 | } 41 | 42 | this->pool.clear(); 43 | } 44 | 45 | void free(void* data) 46 | { 47 | std::lock_guard _(this->mutex); 48 | 49 | auto i = this->refMemory.find(data); 50 | if (i != this->refMemory.end()) 51 | { 52 | i->second(i->first); 53 | this->refMemory.erase(i); 54 | } 55 | 56 | auto j = std::find(this->pool.begin(), this->pool.end(), data); 57 | if (j != this->pool.end()) 58 | { 59 | Memory::Free(data); 60 | this->pool.erase(j); 61 | } 62 | } 63 | 64 | void free(const void* data) 65 | { 66 | this->free(const_cast(data)); 67 | } 68 | 69 | void reference(void* memory, FreeCallback callback) 70 | { 71 | std::lock_guard _(this->mutex); 72 | 73 | this->refMemory[memory] = callback; 74 | } 75 | 76 | void* allocate(size_t length) 77 | { 78 | std::lock_guard _(this->mutex); 79 | 80 | void* data = Memory::Allocate(length); 81 | this->pool.push_back(data); 82 | return data; 83 | } 84 | template inline T* allocate() 85 | { 86 | return this->allocateArray(1); 87 | } 88 | template inline T* allocateArray(size_t count = 1) 89 | { 90 | return static_cast(this->allocate(count * sizeof(T))); 91 | } 92 | 93 | bool empty() 94 | { 95 | return (this->pool.empty() && this->refMemory.empty()); 96 | } 97 | 98 | char* duplicateString(const std::string& string) 99 | { 100 | std::lock_guard _(this->mutex); 101 | 102 | char* data = Memory::DuplicateString(string); 103 | this->pool.push_back(data); 104 | return data; 105 | } 106 | 107 | bool isPointerMapped(void* ptr) 108 | { 109 | return this->ptrMap.find(ptr) != this->ptrMap.end(); 110 | } 111 | 112 | template T* getPointer(void* oldPtr) 113 | { 114 | if (this->isPointerMapped(oldPtr)) 115 | { 116 | return reinterpret_cast(this->ptrMap[oldPtr]); 117 | } 118 | 119 | return nullptr; 120 | } 121 | 122 | void mapPointer(void* oldPtr, void* newPtr) 123 | { 124 | this->ptrMap[oldPtr] = newPtr; 125 | } 126 | 127 | private: 128 | std::mutex mutex; 129 | std::vector pool; 130 | std::unordered_map ptrMap; 131 | std::unordered_map refMemory; 132 | }; 133 | 134 | static void* AllocateAlign(size_t length, size_t alignment); 135 | static void* Allocate(size_t length); 136 | template static inline T* Allocate() 137 | { 138 | return AllocateArray(1); 139 | } 140 | template static inline T* AllocateArray(size_t count = 1) 141 | { 142 | return static_cast(Allocate(count * sizeof(T))); 143 | } 144 | 145 | static char* DuplicateString(const std::string& string); 146 | 147 | static void Free(void* data); 148 | static void Free(const void* data); 149 | 150 | static void FreeAlign(void* data); 151 | static void FreeAlign(const void* data); 152 | 153 | static bool IsSet(void* mem, char chr, size_t length); 154 | 155 | static bool IsBadReadPtr(const void* ptr); 156 | static bool IsBadCodePtr(const void* ptr); 157 | 158 | static Utils::Memory::Allocator* GetAllocator(); 159 | 160 | private: 161 | static Utils::Memory::Allocator MemAllocator; 162 | }; 163 | } 164 | -------------------------------------------------------------------------------- /src/Utils/String.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | 3 | namespace Utils 4 | { 5 | namespace String 6 | { 7 | const char *VA(const char *fmt, ...) 8 | { 9 | static VAProvider<4, 100> globalProvider; 10 | static thread_local VAProvider<8, 256> provider; 11 | 12 | va_list ap; 13 | va_start(ap, fmt); 14 | 15 | const char* result; 16 | if (Components::Loader::IsUninitializing()) result = globalProvider.get(fmt, ap); 17 | else result = provider.get(fmt, ap); 18 | 19 | va_end(ap); 20 | return result; 21 | } 22 | 23 | std::string ToLower(std::string input) 24 | { 25 | std::transform(input.begin(), input.end(), input.begin(), ::tolower); 26 | return input; 27 | } 28 | 29 | std::string ToUpper(std::string input) 30 | { 31 | std::transform(input.begin(), input.end(), input.begin(), ::toupper); 32 | return input; 33 | } 34 | 35 | std::string DumpHex(const std::string& data, const std::string& separator) 36 | { 37 | std::string result; 38 | 39 | for (unsigned int i = 0; i < data.size(); ++i) 40 | { 41 | if (i > 0) 42 | { 43 | result.append(separator); 44 | } 45 | 46 | result.append(Utils::String::VA("%02X", data[i] & 0xFF)); 47 | } 48 | 49 | return result; 50 | } 51 | 52 | std::string XOR(std::string str, char value) 53 | { 54 | for (unsigned int i = 0; i < str.size(); ++i) 55 | { 56 | str[i] ^= value; 57 | } 58 | 59 | return str; 60 | } 61 | 62 | std::vector Explode(const std::string& str, char delim) 63 | { 64 | std::vector result; 65 | std::istringstream iss(str); 66 | 67 | for (std::string token; std::getline(iss, token, delim);) 68 | { 69 | std::string _entry = std::move(token); 70 | 71 | // Remove trailing 0x0 bytes 72 | while (_entry.size() && !_entry.back()) 73 | { 74 | _entry = _entry.substr(0, _entry.size() - 1); 75 | } 76 | 77 | result.push_back(_entry); 78 | } 79 | 80 | return result; 81 | } 82 | 83 | void Replace(std::string &string, const std::string& find, const std::string& replace) 84 | { 85 | size_t nPos = 0; 86 | 87 | while ((nPos = string.find(find, nPos)) != std::string::npos) 88 | { 89 | string = string.replace(nPos, find.length(), replace); 90 | nPos += replace.length(); 91 | } 92 | } 93 | 94 | bool StartsWith(const std::string& haystack, const std::string& needle) 95 | { 96 | return (haystack.size() >= needle.size() && haystack.substr(0, needle.size()) == needle); 97 | } 98 | 99 | bool EndsWith(const std::string& haystack, const std::string& needle) 100 | { 101 | return (haystack.size() >= needle.size() && haystack.substr(haystack.size() - needle.size()) == needle); 102 | } 103 | 104 | int IsSpace(int c) 105 | { 106 | if (c < -1) return 0; 107 | return _isspace_l(c, nullptr); 108 | } 109 | 110 | // trim from start 111 | std::string <rim(std::string &s) 112 | { 113 | s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int val) 114 | { 115 | return !IsSpace(val); 116 | })); 117 | return s; 118 | } 119 | 120 | // trim from end 121 | std::string &RTrim(std::string &s) 122 | { 123 | s.erase(std::find_if(s.rbegin(), s.rend(), [](int val) 124 | { 125 | return !IsSpace(val); 126 | }).base(), s.end()); 127 | return s; 128 | } 129 | 130 | // trim from both ends 131 | std::string &Trim(std::string &s) 132 | { 133 | return LTrim(RTrim(s)); 134 | } 135 | 136 | std::string FormatTimeSpan(int milliseconds) 137 | { 138 | int secondsTotal = milliseconds / 1000; 139 | int seconds = secondsTotal % 60; 140 | int minutesTotal = secondsTotal / 60; 141 | int minutes = minutesTotal % 60; 142 | int hoursTotal = minutesTotal / 60; 143 | 144 | return Utils::String::VA("%02d:%02d:%02d", hoursTotal, minutes, seconds); 145 | } 146 | 147 | std::string FormatBandwidth(size_t bytes, int milliseconds) 148 | { 149 | static const char* sizes[] = 150 | { 151 | "B", 152 | "KB", 153 | "MB", 154 | "GB", 155 | "TB" 156 | }; 157 | 158 | if (!milliseconds) return "0.00 B/s"; 159 | 160 | double bytesPerSecond = (1000.0 / milliseconds) * bytes; 161 | 162 | int i; 163 | for (i = 0; bytesPerSecond > 1000 && i < ARRAYSIZE(sizes); ++i) // 1024 or 1000? 164 | { 165 | bytesPerSecond /= 1000; 166 | } 167 | 168 | return Utils::String::VA("%.2f %s/s", static_cast(bytesPerSecond), sizes[i]); 169 | } 170 | 171 | #ifdef ENABLE_BASE64 172 | // Encodes a given string in Base64 173 | std::string EncodeBase64(const char* input, const unsigned long inputSize) 174 | { 175 | unsigned long outlen = long(inputSize + (inputSize / 3.0) + 16); 176 | unsigned char* outbuf = new unsigned char[outlen]; //Reserve output memory 177 | base64_encode(reinterpret_cast(const_cast(input)), inputSize, outbuf, &outlen); 178 | std::string ret(reinterpret_cast(outbuf), outlen); 179 | delete[] outbuf; 180 | return ret; 181 | } 182 | 183 | // Encodes a given string in Base64 184 | std::string EncodeBase64(const std::string& input) 185 | { 186 | return EncodeBase64(input.data(), input.size()); 187 | } 188 | #endif 189 | 190 | #ifdef ENABLE_BASE128 191 | // Encodes a given string in Base128 192 | std::string EncodeBase128(const std::string& input) 193 | { 194 | base128 encoder; 195 | 196 | void* inbuffer = const_cast(input.data()); 197 | char* buffer = encoder.encode(inbuffer, input.size()); 198 | /* 199 | Interesting to see that the buffer returned by the encoder is not a standalone string copy 200 | but instead is a pointer to the internal "encoded" field of the encoder. So if you deinitialize 201 | the encoder that string will probably become garbage. 202 | */ 203 | std::string retval(buffer); 204 | return retval; 205 | } 206 | #endif 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/Utils/String.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Utils 4 | { 5 | namespace String 6 | { 7 | template 8 | class VAProvider 9 | { 10 | public: 11 | static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0"); 12 | 13 | VAProvider() : currentBuffer(0) {} 14 | ~VAProvider() {} 15 | 16 | const char* get(const char* format, va_list ap) 17 | { 18 | ++this->currentBuffer %= ARRAYSIZE(this->stringPool); 19 | auto entry = &this->stringPool[this->currentBuffer]; 20 | 21 | if (!entry->size || !entry->buffer) 22 | { 23 | throw std::runtime_error("String pool not initialized"); 24 | } 25 | 26 | while (true) 27 | { 28 | int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap); 29 | if (res > 0) break; // Success 30 | if (res == 0) return ""; // Error 31 | 32 | entry->doubleSize(); 33 | } 34 | 35 | return entry->buffer; 36 | } 37 | 38 | private: 39 | class Entry 40 | { 41 | public: 42 | Entry(size_t _size = MinBufferSize) : size(_size), buffer(nullptr) 43 | { 44 | if (this->size < MinBufferSize) this->size = MinBufferSize; 45 | this->allocate(); 46 | } 47 | 48 | ~Entry() 49 | { 50 | if (this->buffer) Utils::Memory::GetAllocator()->free(this->buffer); 51 | this->size = 0; 52 | this->buffer = nullptr; 53 | } 54 | 55 | void allocate() 56 | { 57 | if (this->buffer) Utils::Memory::GetAllocator()->free(this->buffer); 58 | this->buffer = Utils::Memory::GetAllocator()->allocateArray(this->size + 1); 59 | } 60 | 61 | void doubleSize() 62 | { 63 | this->size *= 2; 64 | this->allocate(); 65 | } 66 | 67 | size_t size; 68 | char* buffer; 69 | }; 70 | 71 | size_t currentBuffer; 72 | Entry stringPool[Buffers]; 73 | }; 74 | 75 | const char *VA(const char *fmt, ...); 76 | 77 | int IsSpace(int c); 78 | std::string ToLower(std::string input); 79 | std::string ToUpper(std::string input); 80 | bool EndsWith(const std::string& haystack, const std::string& needle); 81 | std::vector Explode(const std::string& str, char delim); 82 | void Replace(std::string &string, const std::string& find, const std::string& replace); 83 | bool StartsWith(const std::string& haystack, const std::string& needle); 84 | std::string <rim(std::string &s); 85 | std::string &RTrim(std::string &s); 86 | std::string &Trim(std::string &s); 87 | 88 | std::string FormatTimeSpan(int milliseconds); 89 | std::string FormatBandwidth(size_t bytes, int milliseconds); 90 | 91 | std::string DumpHex(const std::string& data, const std::string& separator = " "); 92 | 93 | std::string XOR(const std::string str, char value); 94 | 95 | std::string EncodeBase64(const char* input, const unsigned long inputSize); 96 | std::string EncodeBase64(const std::string& input); 97 | 98 | std::string EncodeBase128(const std::string& input); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Utils/Time.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | 3 | namespace Utils 4 | { 5 | namespace Time 6 | { 7 | void Interval::update() 8 | { 9 | this->lastPoint = std::chrono::high_resolution_clock::now(); 10 | } 11 | 12 | bool Interval::elapsed(std::chrono::nanoseconds nsecs) 13 | { 14 | return ((std::chrono::high_resolution_clock::now() - this->lastPoint) >= nsecs); 15 | } 16 | 17 | Point::Point() : lastPoint(Game::Sys_Milliseconds()) 18 | { 19 | 20 | } 21 | 22 | void Point::update() 23 | { 24 | this->lastPoint = Game::Sys_Milliseconds(); 25 | } 26 | 27 | int Point::diff(Point point) 28 | { 29 | return point.lastPoint - this->lastPoint; 30 | } 31 | 32 | bool Point::after(Point point) 33 | { 34 | return this->diff(point) < 0; 35 | } 36 | 37 | bool Point::elapsed(int milliseconds) 38 | { 39 | return (Game::Sys_Milliseconds() - this->lastPoint) >= milliseconds; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Utils/Time.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Utils 4 | { 5 | namespace Time 6 | { 7 | class Interval 8 | { 9 | protected: 10 | std::chrono::high_resolution_clock::time_point lastPoint; 11 | 12 | public: 13 | Interval() : lastPoint(std::chrono::high_resolution_clock::now()) {} 14 | 15 | void update(); 16 | bool elapsed(std::chrono::nanoseconds nsecs); 17 | }; 18 | 19 | class Point 20 | { 21 | public: 22 | Point(); 23 | 24 | void update(); 25 | int diff(Point point); 26 | bool after(Point point); 27 | bool elapsed(int milliseconds); 28 | 29 | private: 30 | int lastPoint; 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Utils/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "STDInclude.hpp" 2 | 3 | namespace Utils 4 | { 5 | std::string GetMimeType(const std::string& url) 6 | { 7 | wchar_t* mimeType = nullptr; 8 | FindMimeFromData(nullptr, std::wstring(url.begin(), url.end()).data(), nullptr, 0, nullptr, 0, &mimeType, 0); 9 | 10 | if (mimeType) 11 | { 12 | std::wstring wMimeType(mimeType); 13 | return std::string(wMimeType.begin(), wMimeType.end()); 14 | } 15 | 16 | return "application/octet-stream"; 17 | } 18 | 19 | std::string ParseChallenge(const std::string& data) 20 | { 21 | auto pos = data.find_first_of("\n "); 22 | if (pos == std::string::npos) return data; 23 | return data.substr(0, pos).data(); 24 | } 25 | 26 | void OutputDebugLastError() 27 | { 28 | DWORD errorMessageID = ::GetLastError(); 29 | OutputDebugStringA(Utils::String::VA("Last error code: 0x%08X (%s)\n", errorMessageID, GetLastWindowsError().data())); 30 | } 31 | 32 | std::string GetLastWindowsError() 33 | { 34 | DWORD errorMessageID = ::GetLastError(); 35 | LPSTR messageBuffer = nullptr; 36 | size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 37 | nullptr, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&messageBuffer), 0, nullptr); 38 | std::string message(messageBuffer, size); 39 | LocalFree(messageBuffer); 40 | return message; 41 | } 42 | 43 | bool IsWineEnvironment() 44 | { 45 | HMODULE hntdll = GetModuleHandleA("ntdll.dll"); 46 | if (!hntdll) return false; 47 | 48 | return (GetProcAddress(hntdll, "wine_get_version") != nullptr); 49 | } 50 | 51 | unsigned long GetParentProcessId() 52 | { 53 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 54 | if (hSnapshot == INVALID_HANDLE_VALUE) return 0; 55 | 56 | Utils::Memory::Allocator allocator; 57 | allocator.reference(hSnapshot, [](void* handle) { CloseHandle(handle); }); 58 | 59 | PROCESSENTRY32 pe32; 60 | ZeroMemory(&pe32, sizeof(pe32)); 61 | pe32.dwSize = sizeof(pe32); 62 | 63 | DWORD pid = GetCurrentProcessId(); 64 | while (Process32Next(hSnapshot, &pe32)) 65 | { 66 | if (pe32.th32ProcessID == pid) 67 | { 68 | return pe32.th32ParentProcessID; 69 | } 70 | } 71 | 72 | return 0; 73 | } 74 | 75 | size_t GetModuleSize(HMODULE module) 76 | { 77 | PIMAGE_DOS_HEADER header = PIMAGE_DOS_HEADER(module); 78 | PIMAGE_NT_HEADERS ntHeader = PIMAGE_NT_HEADERS(DWORD(module) + header->e_lfanew); 79 | return ntHeader->OptionalHeader.SizeOfImage; 80 | } 81 | 82 | void* GetThreadStartAddress(HANDLE hThread) 83 | { 84 | HMODULE ntdll = Utils::GetNTDLL(); 85 | if (!ntdll) return nullptr; 86 | 87 | 88 | static uint8_t ntQueryInformationThread[] = { 0xB1, 0x8B, 0xAE, 0x8A, 0x9A, 0x8D, 0x86, 0xB6, 0x91, 0x99, 0x90, 0x8D, 0x92, 0x9E, 0x8B, 0x96, 0x90, 0x91, 0xAB, 0x97, 0x8D, 0x9A, 0x9E, 0x9B }; // NtQueryInformationThread 89 | NtQueryInformationThread_t NtQueryInformationThread = NtQueryInformationThread_t(GetProcAddress(ntdll, Utils::String::XOR(std::string(reinterpret_cast(ntQueryInformationThread), sizeof ntQueryInformationThread), -1).data())); 90 | if (!NtQueryInformationThread) return nullptr; 91 | 92 | HANDLE dupHandle, currentProcess = GetCurrentProcess(); 93 | if (!DuplicateHandle(currentProcess, hThread, currentProcess, &dupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)) 94 | { 95 | SetLastError(ERROR_ACCESS_DENIED); 96 | return nullptr; 97 | } 98 | 99 | void* address = nullptr; 100 | NTSTATUS status = NtQueryInformationThread(dupHandle, ThreadQuerySetWin32StartAddress, &address, sizeof(address), nullptr); 101 | CloseHandle(dupHandle); 102 | 103 | if (status != 0) return nullptr; 104 | return address; 105 | } 106 | 107 | void SetEnvironment() 108 | { 109 | wchar_t exeName[512]; 110 | GetModuleFileName(GetModuleHandle(nullptr), exeName, sizeof(exeName) / 2); 111 | 112 | wchar_t* exeBaseName = wcsrchr(exeName, L'\\'); 113 | exeBaseName[0] = L'\0'; 114 | 115 | SetCurrentDirectory(exeName); 116 | } 117 | 118 | HMODULE GetNTDLL() 119 | { 120 | static uint8_t ntdll[] = { 0x91, 0x8B, 0x9B, 0x93, 0x93, 0xD1, 0x9B, 0x93, 0x93 }; // ntdll.dll 121 | return GetModuleHandleA(Utils::String::XOR(std::string(reinterpret_cast(ntdll), sizeof ntdll), -1).data()); 122 | } 123 | 124 | void SafeShellExecute(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd) 125 | { 126 | [=]() 127 | { 128 | __try 129 | { 130 | ShellExecuteA(hwnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd); 131 | } 132 | __finally 133 | {} 134 | }(); 135 | 136 | std::this_thread::yield(); 137 | } 138 | 139 | void OpenUrl(const std::string& url) 140 | { 141 | SafeShellExecute(nullptr, "open", url.data(), nullptr, nullptr, SW_SHOWNORMAL); 142 | } 143 | 144 | bool HasIntercection(unsigned int base1, unsigned int len1, unsigned int base2, unsigned int len2) 145 | { 146 | return !(base1 + len1 <= base2 || base2 + len2 <= base1); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/Utils/Utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef LONG NTSTATUS; 4 | typedef NTSTATUS(NTAPI *NtCreateThreadEx_t)(PHANDLE hThread, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, BOOL CreateSuspended, DWORD StackZeroBits, DWORD SizeOfStackCommit, DWORD SizeOfStackReserve, LPVOID lpBytesBuffer); 5 | typedef NTSTATUS(NTAPI* NtQueryInformationThread_t)(HANDLE ThreadHandle, LONG ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength); 6 | #define ThreadQuerySetWin32StartAddress 9 7 | 8 | namespace Utils 9 | { 10 | std::string GetMimeType(const std::string& url); 11 | std::string ParseChallenge(const std::string& data); 12 | void OutputDebugLastError(); 13 | std::string GetLastWindowsError(); 14 | 15 | bool IsWineEnvironment(); 16 | 17 | unsigned long GetParentProcessId(); 18 | size_t GetModuleSize(HMODULE); 19 | void* GetThreadStartAddress(HANDLE hThread); 20 | HMODULE GetNTDLL(); 21 | 22 | void SetEnvironment(); 23 | 24 | void OpenUrl(const std::string& url); 25 | 26 | bool HasIntercection(unsigned int base1, unsigned int len1, unsigned int base2, unsigned int len2); 27 | 28 | template inline void RotLeft(T& object, size_t bits) 29 | { 30 | bits %= sizeof(T) * 8; 31 | 32 | T sign = 1; 33 | sign = sign << (sizeof(T) * 8 - 1); 34 | 35 | bool negative = (object & sign) != 0; 36 | object &= ~sign; 37 | object = (object << bits) | (object >> (sizeof(T) * 8 - bits)); 38 | object |= T(negative) << ((sizeof(T) * 8 - 1 + bits) % (sizeof(T) * 8)); 39 | } 40 | 41 | template inline void RotRight(T& object, size_t bits) 42 | { 43 | bits %= (sizeof(T) * 8); 44 | RotLeft(object, ((sizeof(T) * 8) - bits)); 45 | } 46 | 47 | template inline void Merge(std::vector* target, T* source, size_t length) 48 | { 49 | if (source) 50 | { 51 | for (size_t i = 0; i < length; ++i) 52 | { 53 | target->push_back(source[i]); 54 | } 55 | } 56 | } 57 | 58 | template inline void Merge(std::vector* target, std::vector source) 59 | { 60 | for (auto &entry : source) 61 | { 62 | target->push_back(entry); 63 | } 64 | } 65 | 66 | template using Slot = std::function; 67 | template 68 | class Signal 69 | { 70 | public: 71 | Signal() 72 | { 73 | std::lock_guard _(this->mutex); 74 | 75 | this->slots.clear(); 76 | } 77 | 78 | Signal(Signal& obj) : Signal() 79 | { 80 | std::lock_guard _(this->mutex); 81 | std::lock_guard __(obj.mutex); 82 | 83 | Utils::Merge(&this->slots, obj.getSlots()); 84 | } 85 | 86 | void connect(Slot slot) 87 | { 88 | std::lock_guard _(this->mutex); 89 | 90 | if (slot) 91 | { 92 | this->slots.push_back(slot); 93 | } 94 | } 95 | 96 | void clear() 97 | { 98 | std::lock_guard _(this->mutex); 99 | 100 | this->slots.clear(); 101 | } 102 | 103 | std::vector>& getSlots() 104 | { 105 | return this->slots; 106 | } 107 | 108 | template 109 | void operator()(Args&&... args) const 110 | { 111 | std::lock_guard _(this->mutex); 112 | 113 | std::vector> copiedSlots; 114 | Utils::Merge(&copiedSlots, this->slots); 115 | 116 | for (auto& slot : copiedSlots) 117 | { 118 | if (slot) 119 | { 120 | slot(std::forward(args)...); 121 | } 122 | } 123 | } 124 | 125 | private: 126 | mutable std::recursive_mutex mutex; 127 | std::vector> slots; 128 | }; 129 | } 130 | -------------------------------------------------------------------------------- /tools/premake5.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ineedbots/cod2m/9b1f27c2586bb3988ca421a74199bb23c4a5ce67/tools/premake5.exe -------------------------------------------------------------------------------- /tools/protoc.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ineedbots/cod2m/9b1f27c2586bb3988ca421a74199bb23c4a5ce67/tools/protoc.exe --------------------------------------------------------------------------------