From 6bda5ecbba9b64e6eecf264f2916562b61a69293 Mon Sep 17 00:00:00 2001 From: s1lent Date: Sun, 23 Apr 2017 20:42:15 +0700 Subject: [PATCH 1/2] Restructuring of rehlds for HLTV project. Improved hooks stuff: Removed wrappers for virtual functions hooks. --- dep/bzip2/msvc/bzip2.vcxproj.filters | 28 +- rehlds/build.gradle | 30 +- rehlds/common/BaseSystemModule.cpp | 52 +- rehlds/common/BaseSystemModule.h | 60 +- rehlds/common/IAdminServer.h | 35 +- rehlds/common/IBaseSystem.h | 40 +- rehlds/common/IObjectContainer.h | 34 +- rehlds/common/ISystemModule.h | 36 +- rehlds/common/IVGuiModule.h | 34 +- rehlds/common/ObjectDictionary.cpp | 242 +- rehlds/common/ObjectDictionary.h | 59 +- rehlds/common/ObjectList.cpp | 149 +- rehlds/common/ObjectList.h | 46 +- rehlds/common/SteamAppStartUp.cpp | 28 + rehlds/common/SteamAppStartUp.h | 34 +- rehlds/common/TextConsoleUnix.cpp | 28 + rehlds/common/TextConsoleUnix.h | 34 +- rehlds/common/TextConsoleWin32.cpp | 31 +- rehlds/common/TextConsoleWin32.h | 34 +- rehlds/common/TokenLine.cpp | 21 +- rehlds/common/TokenLine.h | 42 +- rehlds/common/hltv.h | 9 +- rehlds/common/textconsole.cpp | 32 +- rehlds/common/textconsole.h | 34 +- rehlds/dedicated/build.gradle | 3 +- rehlds/dedicated/src/dbg.cpp | 136 +- rehlds/dedicated/src/icommandline.h | 25 - rehlds/dedicated/src/precompiled.h | 1 - rehlds/engine/common.cpp | 6 - rehlds/engine/common.h | 21 +- rehlds/engine/net.h | 4 +- rehlds/engine/sv_main.cpp | 12 +- rehlds/engine/sv_remoteaccess.cpp | 12 +- rehlds/engine/sv_remoteaccess.h | 3 - rehlds/engine/sv_steam3.cpp | 31 +- rehlds/engine/sv_steam3.h | 2 - rehlds/engine/sys_dll.h | 18 +- rehlds/engine/sys_dll2.cpp | 49 +- rehlds/engine/sys_dll2.h | 8 - rehlds/engine/sys_engine.cpp | 80 - rehlds/engine/sys_engine.h | 19 - rehlds/engine/sys_linuxwind.cpp | 72 +- rehlds/engine/sys_linuxwnd.h | 59 +- rehlds/hookers/6132_hooker.cpp | 2572 --------------------- rehlds/hookers/engine/hooklist.cpp | 2431 +++++++++++++++++++ rehlds/hookers/engine/hooklist.h | 5 + rehlds/hookers/{ => engine}/main.cpp | 235 +- rehlds/hookers/{ => engine}/main_swds.cpp | 140 +- rehlds/hookers/helper.h | 159 ++ rehlds/hookers/hooker.cpp | 112 +- rehlds/hookers/hooker.h | 17 + rehlds/hookers/memory.h | 8 +- rehlds/msvc/ReHLDS.vcxproj | 33 +- rehlds/msvc/ReHLDS.vcxproj.filters | 62 +- rehlds/public/engine_hlds_api.h | 1 - rehlds/public/engine_launcher_api.h | 14 +- rehlds/public/icommandline.h | 47 + rehlds/public/interface.cpp | 57 +- rehlds/public/interface.h | 8 +- rehlds/public/rehlds/custom.h | 13 +- rehlds/public/rehlds/maintypes.h | 18 +- rehlds/public/rehlds/model.h | 4 +- rehlds/public/rehlds/osconfig.h | 4 + rehlds/{hookers => rehlds}/engine.h | 166 +- rehlds/rehlds/precompiled.h | 9 +- rehlds/unittests/security_tests.cpp | 68 +- shared_msvc.gradle | 2 +- 67 files changed, 4060 insertions(+), 3858 deletions(-) delete mode 100644 rehlds/dedicated/src/icommandline.h delete mode 100644 rehlds/hookers/6132_hooker.cpp create mode 100644 rehlds/hookers/engine/hooklist.cpp create mode 100644 rehlds/hookers/engine/hooklist.h rename rehlds/hookers/{ => engine}/main.cpp (92%) rename rehlds/hookers/{ => engine}/main_swds.cpp (95%) create mode 100644 rehlds/hookers/helper.h create mode 100644 rehlds/public/icommandline.h rename rehlds/{hookers => rehlds}/engine.h (96%) diff --git a/dep/bzip2/msvc/bzip2.vcxproj.filters b/dep/bzip2/msvc/bzip2.vcxproj.filters index d395a6b..68bf491 100644 --- a/dep/bzip2/msvc/bzip2.vcxproj.filters +++ b/dep/bzip2/msvc/bzip2.vcxproj.filters @@ -1,51 +1,43 @@  - + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - Source Files + src - Source Files + src - Source Files + src - Source Files + src - Source Files + src - Source Files + src - Source Files + src - Source Files + src - Source Files + src \ No newline at end of file diff --git a/rehlds/build.gradle b/rehlds/build.gradle index fb3f6bc..b1871d4 100644 --- a/rehlds/build.gradle +++ b/rehlds/build.gradle @@ -176,7 +176,7 @@ void setupToolchain(NativeBinarySpec b) { if (!unitTestExecutable && !swdsLib) { cfg.singleDefines 'HOOK_ENGINE' } - + if (unitTestExecutable) { cfg.singleDefines 'REHLDS_UNIT_TESTS' } @@ -194,22 +194,26 @@ void setupToolchain(NativeBinarySpec b) { class RehldsSrc { static void rehlds_src(def h) { - h.rehlds_src(CppSourceSet) { + h.rehlds_engine(CppSourceSet) { source { - srcDirs "engine", "rehlds", "public", "version" + srcDirs "engine", "rehlds", "version" if (GradleCppUtils.windows) srcDirs "testsuite" include "**/*.cpp" exclude "precompiled.cpp" - exclude GradleCppUtils.windows ? "tier0/platform_linux.cpp" : "tier0/platform_win32.cpp" - exclude "interface.cpp", "rehlds/crc32c.cpp", "rehlds/sys_shared.cpp" } - + } + h.rehlds_public(CppSourceSet) { + source { + srcDirs "public" + include "registry.cpp", "steamid.cpp", "utlbuffer.cpp", "tier0/dbg.cpp" + } + } + h.rehlds_memory(CppSourceSet) { source { srcDirs "hookers" - include "**/*.cpp" - exclude "6132_hooker.cpp", "hooker.cpp", "main.cpp", "main_swds.cpp" - if (!GradleCppUtils.windows) exclude "rehlds_debug.cpp" + include "memory.cpp" + if (GradleCppUtils.windows) include "rehlds_debug.cpp" } } } @@ -227,7 +231,7 @@ class RehldsSrc { h.rehlds_hooker_src(CppSourceSet) { source { srcDirs "hookers" - include "6132_hooker.cpp", "hooker.cpp" + include "engine/hooklist.cpp", "hooker.cpp" } } } @@ -236,7 +240,7 @@ class RehldsSrc { h.rehlds_hooker_main_src(CppSourceSet) { source { srcDirs "hookers" - include "main.cpp" + include "engine/main.cpp" } } } @@ -244,8 +248,8 @@ class RehldsSrc { static void rehlds_swds_main_src(def h) { h.rehlds_swds_main_src(CppSourceSet) { source { - srcDirs "hookers" - include "main_swds.cpp" + srcDir "hookers" + include "engine/main_swds.cpp" } } } diff --git a/rehlds/common/BaseSystemModule.cpp b/rehlds/common/BaseSystemModule.cpp index 2082d0b..b5ba97e 100644 --- a/rehlds/common/BaseSystemModule.cpp +++ b/rehlds/common/BaseSystemModule.cpp @@ -1,15 +1,32 @@ -#include "BaseSystemModule.h" -#include +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ -BaseSystemModule::BaseSystemModule() -{ - m_State = MODULE_INACTIVE; -} - -BaseSystemModule::~BaseSystemModule() -{ - ; -} +#include "precompiled.h" char *BaseSystemModule::GetName() { @@ -53,15 +70,13 @@ bool BaseSystemModule::Init(IBaseSystem *system, int serial, char *name) if (!system) return false; - m_State = MODULE_PENDING; + m_State = MODULE_INITIALIZING; m_System = system; m_Serial = serial; m_SystemTime = 0; - if (name) - { - strncpy(m_Name, name, sizeof m_Name - 1); - m_Name[sizeof m_Name - 1] = '\0'; + if (name) { + strcopy(m_Name, name); } return true; @@ -74,13 +89,12 @@ void BaseSystemModule::RunFrame(double time) void BaseSystemModule::ShutDown() { - if (m_State == MODULE_UNLOAD) + if (m_State == MODULE_DISCONNECTED) return; m_Listener.Clear(); - m_State = MODULE_UNLOAD; + m_State = MODULE_DISCONNECTED; - // TODO: Check me! if (!m_System->RemoveModule(this)) { m_System->DPrintf("ERROR! BaseSystemModule::ShutDown: faild to remove module %s.\n", m_Name); diff --git a/rehlds/common/BaseSystemModule.h b/rehlds/common/BaseSystemModule.h index dc76fa7..0a15382 100644 --- a/rehlds/common/BaseSystemModule.h +++ b/rehlds/common/BaseSystemModule.h @@ -1,30 +1,43 @@ -#ifndef BASESYSTEMMODULE_H -#define BASESYSTEMMODULE_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif #include "ObjectList.h" #include "IBaseSystem.h" -#define SIGNAL_MODULE_CLOSE 8 // closing down module - -enum ModuleState -{ - MODULE_INACTIVE, - MODULE_PENDING, - MODULE_RUNNING, - MODULE_LOAD, - MODULE_UNLOAD -}; - // C4250 - 'class1' : inherits 'BaseSystemModule::member' via dominance #pragma warning(disable:4250) class BaseSystemModule: virtual public ISystemModule { public: - BaseSystemModule(); - virtual ~BaseSystemModule(); + BaseSystemModule() : m_State(MODULE_UNDEFINED) {} + virtual ~BaseSystemModule() {} virtual bool Init(IBaseSystem *system, int serial, char *name); virtual void RunFrame(double time); @@ -37,11 +50,20 @@ public: virtual char *GetStatusLine(); virtual char *GetType(); virtual char *GetName(); + + enum ModuleState { + MODULE_UNDEFINED = 0, + MODULE_INITIALIZING, + MODULE_CONNECTING, + MODULE_RUNNING, + MODULE_DISCONNECTED + }; + virtual int GetState(); virtual int GetVersion(); virtual void ShutDown(); virtual char *COM_GetBaseDir() { return ""; } - void FireSignal(unsigned int signal, void *data); + void FireSignal(unsigned int signal, void *data = nullptr); protected: IBaseSystem *m_System; @@ -51,5 +73,3 @@ protected: unsigned int m_Serial; double m_SystemTime; }; - -#endif // BASESYSTEMMODULE_H diff --git a/rehlds/common/IAdminServer.h b/rehlds/common/IAdminServer.h index 41a5d21..ab367ce 100644 --- a/rehlds/common/IAdminServer.h +++ b/rehlds/common/IAdminServer.h @@ -1,8 +1,32 @@ -#ifndef IADMINSERVER_H -#define IADMINSERVER_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif #include "interface.h" @@ -28,6 +52,3 @@ public: }; #define ADMINSERVER_INTERFACE_VERSION "AdminServer002" - - -#endif // IAdminServer_H diff --git a/rehlds/common/IBaseSystem.h b/rehlds/common/IBaseSystem.h index 20239d1..209950b 100644 --- a/rehlds/common/IBaseSystem.h +++ b/rehlds/common/IBaseSystem.h @@ -1,15 +1,39 @@ -#ifndef IBASESYSTEM_H -#define IBASESYSTEM_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif #include "ISystemModule.h" +#include "IVGuiModule.h" class Panel; class ObjectList; class IFileSystem; -class IVGuiModule; class IBaseSystem: virtual public ISystemModule { public: @@ -22,10 +46,10 @@ public: virtual void Printf(char *fmt, ...) = 0; virtual void DPrintf(char *fmt, ...) = 0; - virtual void RedirectOutput(char *buffer, int maxSize) = 0; + virtual void RedirectOutput(char *buffer = nullptr, int maxSize = 0) = 0; virtual IFileSystem *GetFileSystem() = 0; - virtual unsigned char *LoadFile(const char *name, int *length) = 0; + virtual unsigned char *LoadFile(const char *name, int *length = nullptr) = 0; virtual void FreeFile(unsigned char *fileHandle) = 0; virtual void SetTitle(char *text) = 0; @@ -55,5 +79,3 @@ public: virtual void Stop() = 0; virtual char *COM_GetBaseDir() = 0; }; - -#endif // IBASESYSTEM_H diff --git a/rehlds/common/IObjectContainer.h b/rehlds/common/IObjectContainer.h index d44ffa3..de08bbf 100644 --- a/rehlds/common/IObjectContainer.h +++ b/rehlds/common/IObjectContainer.h @@ -1,8 +1,32 @@ -#ifndef IOBJECTCONTAINER_H -#define IOBJECTCONTAINER_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif class IObjectContainer { public: @@ -21,5 +45,3 @@ public: virtual bool Contains(void *object) = 0; virtual bool IsEmpty() = 0; }; - -#endif // IOBJECTCONTAINER_H diff --git a/rehlds/common/ISystemModule.h b/rehlds/common/ISystemModule.h index 334ffea..9004a95 100644 --- a/rehlds/common/ISystemModule.h +++ b/rehlds/common/ISystemModule.h @@ -1,8 +1,32 @@ -#ifndef ISYSTEMMODULE_H -#define ISYSTEMMODULE_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif #include "interface.h" @@ -15,7 +39,7 @@ public: virtual bool Init(IBaseSystem *system, int serial, char *name) = 0; virtual void RunFrame(double time) = 0; - virtual void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) = 0; + virtual void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data = nullptr) = 0; virtual void ExecuteCommand(int commandID, char *commandLine) = 0; virtual void RegisterListener(ISystemModule *module) = 0; virtual void RemoveListener(ISystemModule *module) = 0; @@ -31,5 +55,3 @@ public: virtual int GetVersion() = 0; virtual void ShutDown() = 0; }; - -#endif // ISYSTEMMODULE_H diff --git a/rehlds/common/IVGuiModule.h b/rehlds/common/IVGuiModule.h index e95263a..4af7658 100644 --- a/rehlds/common/IVGuiModule.h +++ b/rehlds/common/IVGuiModule.h @@ -1,8 +1,32 @@ -#ifndef IVGUIMODULE_H -#define IVGUIMODULE_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif #include #include "interface.h" @@ -50,5 +74,3 @@ public: }; #define VGUIMODULE_INTERFACE_VERSION "VGuiModuleAdminServer001" - -#endif // IVGUIMODULE_H diff --git a/rehlds/common/ObjectDictionary.cpp b/rehlds/common/ObjectDictionary.cpp index 3fbf34b..b14c62d 100644 --- a/rehlds/common/ObjectDictionary.cpp +++ b/rehlds/common/ObjectDictionary.cpp @@ -1,17 +1,50 @@ -#include "ObjectDictionary.h" -#include "maintypes.h" +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ -ObjectDictionary::ObjectDictionary() : - maxSize(0), - size(0), - entries(nullptr) +#include "precompiled.h" + +ObjectDictionary::ObjectDictionary() { + m_currentEntry = 0; + m_findKey = 0; + m_entries = nullptr; + + memset(m_cache, 0, sizeof(m_cache)); + + m_cacheIndex = 0; + m_size = 0; + m_maxSize = 0; } ObjectDictionary::~ObjectDictionary() { - if (entries) { - free(entries); + if (m_entries) { + free(m_entries); } } @@ -19,32 +52,32 @@ void ObjectDictionary::Clear(bool freeObjectssMemory) { if (freeObjectssMemory) { - for (int i = 0; i < size; i++) + for (int i = 0; i < m_size; i++) { - void *obj = entries[i].object; + void *obj = m_entries[i].object; if (obj) { free(obj); } } } - size = 0; + m_size = 0; CheckSize(); ClearCache(); } bool ObjectDictionary::Add(void *object, float key) { - if (size == maxSize && !CheckSize()) + if (m_size == m_maxSize && !CheckSize()) return false; entry_t *p; - if (size && key < entries[size - 1].key) + if (m_size && key < m_entries[m_size - 1].key) { - p = &entries[FindClosestAsIndex(key)]; + p = &m_entries[FindClosestAsIndex(key)]; - entry_t *e1 = &entries[size]; - entry_t *e2 = &entries[size - 1]; + entry_t *e1 = &m_entries[m_size]; + entry_t *e2 = &m_entries[m_size - 1]; while (p->key <= key) { p++; } while (p != e1) @@ -57,11 +90,11 @@ bool ObjectDictionary::Add(void *object, float key) } } else - p = &entries[size]; + p = &m_entries[m_size]; p->key = key; p->object = object; - size++; + m_size++; ClearCache(); AddToCache(p); @@ -71,38 +104,37 @@ bool ObjectDictionary::Add(void *object, float key) int ObjectDictionary::FindClosestAsIndex(float key) { - UNTESTED - - if (size <= 0) + if (m_size <= 0) return -1; - if (key <= entries->key) + if (key <= m_entries->key) return 0; int index = FindKeyInCache(key); - if (index >= 0) + if (index >= 0) { return index; + } int middle; int first = 0; - int last = size - 1; + int last = m_size - 1; float keyMiddle, keyNext; - if (key == entries[last].key) + if (key < m_entries[last].key) { while (true) { middle = (last + first) >> 1; - keyMiddle = entries[middle].key; + keyMiddle = m_entries[middle].key; if (keyMiddle == key) break; if (keyMiddle < key) { - if (entries[middle + 1].key != key) + if (m_entries[middle + 1].key >= key) { - if (entries[middle + 1].key - key < key - keyMiddle) + if (m_entries[middle + 1].key - key < key - keyMiddle) ++middle; break; } @@ -120,29 +152,29 @@ int ObjectDictionary::FindClosestAsIndex(float key) middle = last; } - keyNext = entries[middle - 1].key; + keyNext = m_entries[middle - 1].key; while (keyNext == key) { - keyNext = entries[middle--].key; + keyNext = m_entries[middle--].key; } - AddToCache(&entries[middle], key); + AddToCache(&m_entries[middle], key); return middle; } void ObjectDictionary::ClearCache() { - memset(cache, 0, sizeof(cache)); - cacheIndex = 0; + memset(m_cache, 0, sizeof(m_cache)); + m_cacheIndex = 0; } bool ObjectDictionary::RemoveIndex(int index, bool freeObjectMemory) { - if (index < 0 || index >= size) + if (index < 0 || index >= m_size) return false; - entry_t *p = &entries[size - 1]; - entry_t *e1 = &entries[size]; - entry_t *e2 = &entries[size + 1]; + entry_t *p = &m_entries[m_size - 1]; + entry_t *e1 = &m_entries[index]; + entry_t *e2 = &m_entries[index + 1]; if (freeObjectMemory && e1->object) free(e1->object); @@ -158,7 +190,7 @@ bool ObjectDictionary::RemoveIndex(int index, bool freeObjectMemory) p->object = nullptr; p->key = 0; - size--; + m_size--; CheckSize(); ClearCache(); @@ -173,20 +205,20 @@ bool ObjectDictionary::RemoveIndexRange(int minIndex, int maxIndex) if (maxIndex < 0) maxIndex = 0; - if (minIndex >= size) - minIndex = size - 1; + if (minIndex >= m_size) + minIndex = m_size - 1; } else { if (minIndex < 0) minIndex = 0; - if (maxIndex >= size) - maxIndex = size - 1; + if (maxIndex >= m_size) + maxIndex = m_size - 1; } int offset = minIndex + maxIndex - 1; - size -= offset; + m_size -= offset; CheckSize(); return true; } @@ -194,9 +226,9 @@ bool ObjectDictionary::RemoveIndexRange(int minIndex, int maxIndex) bool ObjectDictionary::Remove(void *object) { bool found = false; - for (int i = 0; i < size; ++i) + for (int i = 0; i < m_size; i++) { - if (entries[i].object == object) { + if (m_entries[i].object == object) { RemoveIndex(i); found = true; } @@ -207,9 +239,9 @@ bool ObjectDictionary::Remove(void *object) bool ObjectDictionary::RemoveSingle(void *object) { - for (int i = 0; i < size; ++i) + for (int i = 0; i < m_size; i++) { - if (entries[i].object == object) { + if (m_entries[i].object == object) { RemoveIndex(i); return true; } @@ -221,13 +253,13 @@ bool ObjectDictionary::RemoveSingle(void *object) bool ObjectDictionary::RemoveKey(float key) { int i = FindClosestAsIndex(key); - if (entries[i].key == key) + if (m_entries[i].key == key) { int j = i; do { ++j; } - while (key == entries[j + 1].key); + while (key == m_entries[j + 1].key); return RemoveIndexRange(i, j); } @@ -237,32 +269,32 @@ bool ObjectDictionary::RemoveKey(float key) bool ObjectDictionary::CheckSize() { - int newSize = maxSize; - if (size == maxSize) + int newSize = m_maxSize; + if (m_size == m_maxSize) { - newSize = 1 - (int)(maxSize * -1.25f); + newSize = 1 - (int)(m_maxSize * -1.25f); } - else if (maxSize * 0.5f >size) + else if (m_maxSize * 0.5f > m_size) { - newSize = (int)(maxSize * 0.75f); + newSize = (int)(m_maxSize * 0.75f); } - if (newSize != maxSize) + if (newSize != m_maxSize) { - entry_t *newEntries = (entry_t *)malloc(sizeof(entry_t)); + entry_t *newEntries = (entry_t *)malloc(sizeof(entry_t) * newSize); if (!newEntries) return false; - memset(&newEntries[size], 0, sizeof(entry_t) * (newSize - size)); + memset(&newEntries[m_size], 0, sizeof(entry_t) * (newSize - m_size)); - if (entries && size) + if (m_entries && m_size) { - memcpy(newEntries, entries, sizeof(entry_t) * size); - free(entries); + memcpy(newEntries, m_entries, sizeof(entry_t) * m_size); + free(m_entries); } - entries = newEntries; - maxSize = newSize; + m_entries = newEntries; + m_maxSize = newSize; } return true; @@ -270,9 +302,9 @@ bool ObjectDictionary::CheckSize() void ObjectDictionary::Init() { - size = 0; - maxSize = 0; - entries = nullptr; + m_size = 0; + m_maxSize = 0; + m_entries = nullptr; CheckSize(); ClearCache(); @@ -280,12 +312,12 @@ void ObjectDictionary::Init() void ObjectDictionary::Init(int baseSize) { - size = 0; - maxSize = 0; - entries = (entry_t *)Mem_ZeroMalloc(sizeof(entry_t) * baseSize); + m_size = 0; + m_maxSize = 0; + m_entries = (entry_t *)Mem_ZeroMalloc(sizeof(entry_t) * baseSize); - if (entries) { - maxSize = baseSize; + if (m_entries) { + m_maxSize = baseSize; } } @@ -296,12 +328,12 @@ bool ObjectDictionary::Add(void *object) int ObjectDictionary::CountElements() { - return size; + return m_size; } bool ObjectDictionary::IsEmpty() { - return (size == 0) ? true : false; + return (m_size == 0) ? true : false; } bool ObjectDictionary::Contains(void *object) @@ -309,9 +341,9 @@ bool ObjectDictionary::Contains(void *object) if (FindObjectInCache(object) >= 0) return true; - for (int i = 0; i < size; i++) + for (int i = 0; i < m_size; i++) { - entry_t *e = &entries[i]; + entry_t *e = &m_entries[i]; if (e->object == object) { AddToCache(e); return true; @@ -323,13 +355,13 @@ bool ObjectDictionary::Contains(void *object) void *ObjectDictionary::GetFirst() { - currentEntry = 0; + m_currentEntry = 0; return GetNext(); } void *ObjectDictionary::GetLast() { - return (size > 0) ? entries[size - 1].object : nullptr; + return (m_size > 0) ? m_entries[m_size - 1].object : nullptr; } bool ObjectDictionary::ChangeKey(void *object, float newKey) @@ -337,33 +369,33 @@ bool ObjectDictionary::ChangeKey(void *object, float newKey) int pos = FindObjectInCache(object); if (pos < 0) { - for (pos = 0; pos < size; pos++) + for (pos = 0; pos < m_size; pos++) { - if (entries[pos].object == object) { - AddToCache(&entries[pos]); + if (m_entries[pos].object == object) { + AddToCache(&m_entries[pos]); break; } } - if (pos == size) { + if (pos == m_size) { return false; } } entry_t *p, *e; - p = &entries[pos]; + p = &m_entries[pos]; if (p->key == newKey) return false; int newpos = FindClosestAsIndex(newKey); - e = &entries[newpos]; + e = &m_entries[newpos]; if (pos < newpos) { if (e->key > newKey) e--; - entry_t *e2 = &entries[pos + 1]; + entry_t *e2 = &m_entries[pos + 1]; while (p < e) { p->object = e2->object; @@ -378,7 +410,7 @@ bool ObjectDictionary::ChangeKey(void *object, float newKey) if (e->key > newKey) e++; - entry_t *e2 = &entries[pos - 1]; + entry_t *e2 = &m_entries[pos - 1]; while (p > e) { p->object = e2->object; @@ -401,47 +433,47 @@ bool ObjectDictionary::UnsafeChangeKey(void *object, float newKey) int pos = FindObjectInCache(object); if (pos < 0) { - for (pos = 0; pos < size; pos++) + for (pos = 0; pos < m_size; pos++) { - if (entries[pos].object == object) { + if (m_entries[pos].object == object) { break; } } - if (pos == size) { + if (pos == m_size) { return false; } } - entries[pos].key = newKey; + m_entries[pos].key = newKey; ClearCache(); return true; } void ObjectDictionary::AddToCache(entry_t *entry) { - int i = (cacheIndex % 32); + int i = (m_cacheIndex % MAX_OBJECT_CACHE); - cache[i].object = entry; - cache[i].key = entry->key; - cacheIndex++; + m_cache[i].object = entry; + m_cache[i].key = entry->key; + m_cacheIndex++; } void ObjectDictionary::AddToCache(entry_t *entry, float key) { - int i = (cacheIndex % 32); + int i = (m_cacheIndex % MAX_OBJECT_CACHE); - cache[i].object = entry; - cache[i].key = key; - cacheIndex++; + m_cache[i].object = entry; + m_cache[i].key = key; + m_cacheIndex++; } int ObjectDictionary::FindKeyInCache(float key) { - for (auto& ch : cache) + for (auto& ch : m_cache) { if (ch.object && ch.key == key) { - return (entry_t *)ch.object - entries; + return (entry_t *)ch.object - m_entries; } } @@ -450,10 +482,10 @@ int ObjectDictionary::FindKeyInCache(float key) int ObjectDictionary::FindObjectInCache(void *object) { - for (auto& ch : cache) + for (auto& ch : m_cache) { if (ch.object && ch.object == object) { - return (entry_t *)ch.object - entries; + return (entry_t *)ch.object - m_entries; } } @@ -462,22 +494,22 @@ int ObjectDictionary::FindObjectInCache(void *object) void *ObjectDictionary::FindClosestKey(float key) { - currentEntry = FindClosestAsIndex(key); + m_currentEntry = FindClosestAsIndex(key); return GetNext(); } void *ObjectDictionary::GetNext() { - if (currentEntry < 0 || currentEntry >= size) + if (m_currentEntry < 0 || m_currentEntry >= m_size) return nullptr; - return &entries[currentEntry++]; + return m_entries[m_currentEntry++].object; } void *ObjectDictionary::FindExactKey(float key) { - if ((currentEntry = FindClosestAsIndex(key)) < 0) + if ((m_currentEntry = FindClosestAsIndex(key)) < 0) return nullptr; - return (entries[currentEntry].key == key) ? GetNext() : nullptr; + return (m_entries[m_currentEntry].key == key) ? GetNext() : nullptr; } diff --git a/rehlds/common/ObjectDictionary.h b/rehlds/common/ObjectDictionary.h index d72d89b..bf1b77f 100644 --- a/rehlds/common/ObjectDictionary.h +++ b/rehlds/common/ObjectDictionary.h @@ -1,16 +1,35 @@ -#ifndef OBJECTDICTIONARY_H -#define OBJECTDICTIONARY_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif #include "IObjectContainer.h" -typedef struct entry_s { - void *object; - float key; -} entry_t; - class ObjectDictionary: public IObjectContainer { public: ObjectDictionary(); @@ -48,6 +67,11 @@ public: void ClearCache(); bool CheckSize(); + typedef struct entry_s { + void *object; + float key; + } entry_t; + void AddToCache(entry_t *entry); void AddToCache(entry_t *entry, float key); @@ -56,18 +80,15 @@ public: int FindClosestAsIndex(float key); protected: - - int currentEntry; - float findKey; + int m_currentEntry; + float m_findKey; enum { MAX_OBJECT_CACHE = 32 }; - entry_t *entries; - entry_t cache[MAX_OBJECT_CACHE]; + entry_t *m_entries; + entry_t m_cache[MAX_OBJECT_CACHE]; - int cacheIndex; - int size; - int maxSize; + int m_cacheIndex; + int m_size; + int m_maxSize; }; - -#endif // OBJECTDICTIONARY_H diff --git a/rehlds/common/ObjectList.cpp b/rehlds/common/ObjectList.cpp index 789c4a7..0eba24e 100644 --- a/rehlds/common/ObjectList.cpp +++ b/rehlds/common/ObjectList.cpp @@ -1,14 +1,42 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #include "precompiled.h" ObjectList::ObjectList() { - head = tail = current = nullptr; - number = 0; + m_head = m_tail = m_current = nullptr; + m_number = 0; } ObjectList::~ObjectList() { - ObjectList::Clear(false); + Clear(false); } bool ObjectList::AddHead(void *newObject) @@ -23,20 +51,19 @@ bool ObjectList::AddHead(void *newObject) // insert element newElement->object = newObject; - if (head) + if (m_head) { - newElement->next = head; - head->prev = newElement; + newElement->next = m_head; + m_head->prev = newElement; } - head = newElement; + m_head = newElement; - // if list was empty set new tail - if (!tail) - tail = head; - - number++; + // if list was empty set new m_tail + if (!m_tail) + m_tail = m_head; + m_number++; return true; } @@ -44,23 +71,23 @@ void *ObjectList::RemoveHead() { void *retObj; - // check head is present - if (head) + // check m_head is present + if (m_head) { - retObj = head->object; - element_t *newHead = head->next; + retObj = m_head->object; + element_t *newHead = m_head->next; if (newHead) newHead->prev = nullptr; - // if only one element is in list also update tail + // if only one element is in list also update m_tail // if we remove this prev element - if (tail == head) - tail = nullptr; + if (m_tail == m_head) + m_tail = nullptr; - free(head); - head = newHead; + free(m_head); + m_head = newHead; - number--; + m_number--; } else retObj = nullptr; @@ -80,19 +107,19 @@ bool ObjectList::AddTail(void *newObject) // insert element newElement->object = newObject; - if (tail) + if (m_tail) { - newElement->prev = tail; - tail->next = newElement; + newElement->prev = m_tail; + m_tail->next = newElement; } - tail = newElement; + m_tail = newElement; - // if list was empty set new tail - if (!head) - head = tail; + // if list was empty set new m_tail + if (!m_head) + m_head = m_tail; - number++; + m_number++; return true; } @@ -100,23 +127,23 @@ void *ObjectList::RemoveTail() { void *retObj; - // check tail is present - if (tail) + // check m_tail is present + if (m_tail) { - retObj = tail->object; - element_t *newTail = tail->prev; + retObj = m_tail->object; + element_t *newTail = m_tail->prev; if (newTail) newTail->next = nullptr; - // if only one element is in list also update tail + // if only one element is in list also update m_tail // if we remove this prev element - if (head == tail) - head = nullptr; + if (m_head == m_tail) + m_head = nullptr; - free(tail); - tail = newTail; + free(m_tail); + m_tail = newTail; - number--; + m_number--; } else @@ -127,23 +154,23 @@ void *ObjectList::RemoveTail() bool ObjectList::IsEmpty() { - return (head == nullptr); + return (m_head == nullptr); } int ObjectList::CountElements() { - return number; + return m_number; } bool ObjectList::Contains(void *object) { - element_t *e = head; + element_t *e = m_head; while (e && e->object != object) { e = e->next; } if (e) { - current = e; + m_current = e; return true; } else @@ -155,7 +182,7 @@ bool ObjectList::Contains(void *object) void ObjectList::Clear(bool freeElementsMemory) { element_t *ne; - element_t *e = head; + element_t *e = m_head; while (e) { @@ -168,13 +195,13 @@ void ObjectList::Clear(bool freeElementsMemory) e = ne; } - head = tail = current = nullptr; - number = 0; + m_head = m_tail = m_current = nullptr; + m_number = 0; } bool ObjectList::Remove(void *object) { - element_t *e = head; + element_t *e = m_head; while (e && e->object != object) { e = e->next; } @@ -183,12 +210,12 @@ bool ObjectList::Remove(void *object) if (e->prev) e->prev->next = e->next; if (e->next) e->next->prev = e->prev; - if (head == e) head = e->next; - if (tail == e) tail = e->prev; - if (current == e) current= e->next; + if (m_head == e) m_head = e->next; + if (m_tail == e) m_tail = e->prev; + if (m_current == e) m_current= e->next; free(e); - number--; + m_number--; } return (e != nullptr); @@ -196,20 +223,20 @@ bool ObjectList::Remove(void *object) void ObjectList::Init() { - head = tail = current = nullptr; - number = 0; + m_head = m_tail = m_current = nullptr; + m_number = 0; } void *ObjectList::GetFirst() { - if (head) + if (m_head) { - current = head->next; - return head->object; + m_current = m_head->next; + return m_head->object; } else { - current = nullptr; + m_current = nullptr; return nullptr; } } @@ -217,10 +244,10 @@ void *ObjectList::GetFirst() void *ObjectList::GetNext() { void *retObj = nullptr; - if (current) + if (m_current) { - retObj = current->object; - current = current->next; + retObj = m_current->object; + m_current = m_current->next; } return retObj; diff --git a/rehlds/common/ObjectList.h b/rehlds/common/ObjectList.h index 821a82a..d351ac3 100644 --- a/rehlds/common/ObjectList.h +++ b/rehlds/common/ObjectList.h @@ -1,8 +1,32 @@ -#ifndef OBJECTLIST_H -#define OBJECTLIST_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif #include "IObjectContainer.h" @@ -28,16 +52,14 @@ public: bool IsEmpty(); typedef struct element_s { - element_s *prev; // pointer to the last element or NULL - element_s *next; // pointer to the next elemnet or NULL + struct element_s *prev; // pointer to the last element or NULL + struct element_s *next; // pointer to the next elemnet or NULL void *object; // the element's object } element_t; protected: - element_t *head; // first element in list - element_t *tail; // last element in list - element_t *current; // current element in list - int number; + element_t *m_head; // first element in list + element_t *m_tail; // last element in list + element_t *m_current; // current element in list + int m_number; }; - -#endif // OBJECTLIST_H diff --git a/rehlds/common/SteamAppStartUp.cpp b/rehlds/common/SteamAppStartUp.cpp index 344c360..87cdc55 100644 --- a/rehlds/common/SteamAppStartUp.cpp +++ b/rehlds/common/SteamAppStartUp.cpp @@ -1,3 +1,31 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #include "precompiled.h" #ifdef _WIN32 diff --git a/rehlds/common/SteamAppStartUp.h b/rehlds/common/SteamAppStartUp.h index c30048e..2b9fbe7 100644 --- a/rehlds/common/SteamAppStartUp.h +++ b/rehlds/common/SteamAppStartUp.h @@ -1,8 +1,32 @@ -#ifndef STEAMAPPSTARTUP_H -#define STEAMAPPSTARTUP_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif // Call this first thing at startup // Works out if the app is a steam app that is being ran outside of steam, @@ -11,5 +35,3 @@ // if it returns true, then exit // if it ruturns false, then continue with normal startup bool ShouldLaunchAppViaSteam(const char *cmdLine, const char *steamFilesystemDllName, const char *stdioFilesystemDllName); - -#endif // STEAMAPPSTARTUP_H diff --git a/rehlds/common/TextConsoleUnix.cpp b/rehlds/common/TextConsoleUnix.cpp index 08a4e54..e5f446a 100644 --- a/rehlds/common/TextConsoleUnix.cpp +++ b/rehlds/common/TextConsoleUnix.cpp @@ -1,3 +1,31 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #include "precompiled.h" #if !defined(_WIN32) diff --git a/rehlds/common/TextConsoleUnix.h b/rehlds/common/TextConsoleUnix.h index cd06735..b40cbc4 100644 --- a/rehlds/common/TextConsoleUnix.h +++ b/rehlds/common/TextConsoleUnix.h @@ -1,8 +1,32 @@ -#ifndef TEXTCONSOLE_UNIX_H -#define TEXTCONSOLE_UNIX_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif #include #include "textconsole.h" @@ -33,5 +57,3 @@ private: }; extern CTextConsoleUnix console; - -#endif // TEXTCONSOLE_UNIX_H diff --git a/rehlds/common/TextConsoleWin32.cpp b/rehlds/common/TextConsoleWin32.cpp index 6bcdfc5..101470b 100644 --- a/rehlds/common/TextConsoleWin32.cpp +++ b/rehlds/common/TextConsoleWin32.cpp @@ -1,8 +1,37 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #include "precompiled.h" #if defined(_WIN32) CTextConsoleWin32 console; +#pragma comment(lib, "user32.lib") BOOL WINAPI ConsoleHandlerRoutine(DWORD CtrlType) { @@ -217,7 +246,7 @@ int CTextConsoleWin32::GetWidth() void CTextConsoleWin32::SetStatusLine(char *pszStatus) { strncpy(statusline, pszStatus, sizeof(statusline) - 1); - statusline[sizeof statusline - 2] = '\0'; + statusline[sizeof(statusline) - 2] = '\0'; UpdateStatus(); } diff --git a/rehlds/common/TextConsoleWin32.h b/rehlds/common/TextConsoleWin32.h index 5ad91b2..dbe6c32 100644 --- a/rehlds/common/TextConsoleWin32.h +++ b/rehlds/common/TextConsoleWin32.h @@ -1,8 +1,32 @@ -#ifndef TEXTCONSOLE_WIN32_H -#define TEXTCONSOLE_WIN32_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif #include #include "TextConsole.h" @@ -35,5 +59,3 @@ private: }; extern CTextConsoleWin32 console; - -#endif // TEXTCONSOLE_WIN32_H diff --git a/rehlds/common/TokenLine.cpp b/rehlds/common/TokenLine.cpp index e74eb0b..df8643a 100644 --- a/rehlds/common/TokenLine.cpp +++ b/rehlds/common/TokenLine.cpp @@ -1,9 +1,12 @@ -#include "TokenLine.h" -#include +#include "precompiled.h" TokenLine::TokenLine() { + memset(m_token, 0, sizeof(m_token)); + memset(m_fullLine, 0, sizeof(m_fullLine)); + memset(m_tokenBuffer, 0, sizeof(m_tokenBuffer)); + m_tokenNumber = 0; } TokenLine::TokenLine(char *string) @@ -22,22 +25,20 @@ bool TokenLine::SetLine(const char *newLine) if (!newLine || (strlen(newLine) >= (MAX_LINE_CHARS - 1))) { - memset(m_fullLine, 0, MAX_LINE_CHARS); - memset(m_tokenBuffer, 0, MAX_LINE_CHARS); + memset(m_fullLine, 0, sizeof(m_fullLine)); + memset(m_tokenBuffer, 0, sizeof(m_tokenBuffer)); return false; } - strncpy(m_fullLine, newLine, MAX_LINE_CHARS - 1); - m_fullLine[MAX_LINE_CHARS - 1] = '\0'; - - strncpy(m_tokenBuffer, newLine, MAX_LINE_CHARS - 1); - m_tokenBuffer[MAX_LINE_CHARS - 1] = '\0'; + strcopy(m_fullLine, newLine); + strcopy(m_tokenBuffer, newLine); // parse tokens char *charPointer = m_tokenBuffer; while (*charPointer && (m_tokenNumber < MAX_LINE_TOKENS)) { - while (*charPointer && ((*charPointer <= 32) || (*charPointer > 126))) + // skip nonprintable chars + while (*charPointer && ((*charPointer <= ' ') || (*charPointer > '~'))) charPointer++; if (*charPointer) diff --git a/rehlds/common/TokenLine.h b/rehlds/common/TokenLine.h index dfa1792..0d16fb6 100644 --- a/rehlds/common/TokenLine.h +++ b/rehlds/common/TokenLine.h @@ -1,8 +1,32 @@ -#ifndef TOKENLINE_H -#define TOKENLINE_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif class TokenLine { public: @@ -10,11 +34,11 @@ public: TokenLine(char *string); virtual ~TokenLine(); - char *GetRestOfLine(int i); // returns all chars after token i - int CountToken(); // returns number of token + char *GetRestOfLine(int i); // returns all chars after token i + int CountToken(); // returns number of token char *CheckToken(char *parm); // returns token after token parm or "" - char *GetToken(int i); // returns token i - char *GetLine(); // returns full line + char *GetToken(int i); // returns token i + char *GetLine(); // returns full line bool SetLine(const char *newLine); // set new token line and parses it private: @@ -25,5 +49,3 @@ private: char *m_token[MAX_LINE_TOKENS]; int m_tokenNumber; }; - -#endif // TOKENLINE_H diff --git a/rehlds/common/hltv.h b/rehlds/common/hltv.h index 136183d..556ef32 100644 --- a/rehlds/common/hltv.h +++ b/rehlds/common/hltv.h @@ -1,6 +1,6 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ // -// Purpose: +// Purpose: // // $NoKeywords: $ //============================================================================= @@ -13,12 +13,13 @@ #define TYPE_CLIENT 0 // client is a normal HL client (default) #define TYPE_PROXY 1 // client is another proxy +#define TYPE_DIRECTOR 2 #define TYPE_COMMENTATOR 3 // client is a commentator #define TYPE_DEMO 4 // client is a demo file // sub commands of svc_hltv: #define HLTV_ACTIVE 0 // tells client that he's an spectator and will get director commands -#define HLTV_STATUS 1 // send status infos about proxy +#define HLTV_STATUS 1 // send status infos about proxy #define HLTV_LISTEN 2 // tell client to listen to a multicast stream // director command types: @@ -44,7 +45,7 @@ // DRC_CMD_EVENT event flags #define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) -#define DRC_FLAG_SIDE (1<<4) // +#define DRC_FLAG_SIDE (1<<4) // #define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene #define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo #define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc) diff --git a/rehlds/common/textconsole.cpp b/rehlds/common/textconsole.cpp index 8af181c..076137d 100644 --- a/rehlds/common/textconsole.cpp +++ b/rehlds/common/textconsole.cpp @@ -1,4 +1,32 @@ -#include "precompiled.h" +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" bool CTextConsole::Init(IBaseSystem *system) { @@ -223,7 +251,7 @@ void CTextConsole::ReceiveTab() if (Q_strcmp(szCommonCmd, m_szConsoleText)) { Q_strcpy(m_szConsoleText, szCommonCmd); - m_nConsoleTextLen = Q_strlen(szCommonCmd); + m_nConsoleTextLen = Q_strlen(szCommonCmd); } Echo(m_szConsoleText); diff --git a/rehlds/common/textconsole.h b/rehlds/common/textconsole.h index e205f17..25fc128 100644 --- a/rehlds/common/textconsole.h +++ b/rehlds/common/textconsole.h @@ -1,8 +1,32 @@ -#ifndef TEXTCONSOLE_H -#define TEXTCONSOLE_H -#ifdef _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #pragma once -#endif #include "IBaseSystem.h" @@ -67,5 +91,3 @@ protected: #endif // defined(_WIN32) void Sys_Printf(char *fmt, ...); - -#endif // TEXTCONSOLE_H diff --git a/rehlds/dedicated/build.gradle b/rehlds/dedicated/build.gradle index 66faa15..3d4dcc0 100644 --- a/rehlds/dedicated/build.gradle +++ b/rehlds/dedicated/build.gradle @@ -59,9 +59,8 @@ void setupToolchain(NativeBinarySpec b) { } else { cfg.compilerOptions.args '-Qoption,cpp,--treat_func_as_string_literal_cpp', '-fno-rtti' } + cfg.compilerOptions.args '-fno-exceptions' - cfg.linkerOptions.stripSymbolTable = false; - cfg.linkerOptions.staticLibStdCpp = false; cfg.extraLibs 'dl' } diff --git a/rehlds/dedicated/src/dbg.cpp b/rehlds/dedicated/src/dbg.cpp index f0b6b43..b7180a4 100644 --- a/rehlds/dedicated/src/dbg.cpp +++ b/rehlds/dedicated/src/dbg.cpp @@ -1,137 +1,5 @@ #include "precompiled.h" -class CPerformanceCounter -{ -public: - CPerformanceCounter(); - - void InitializePerformanceCounter(); - double GetCurTime(); - -private: - int m_iLowShift; - double m_flPerfCounterFreq; - double m_flCurrentTime; - double m_flLastCurrentTime; -}; - -inline CPerformanceCounter::CPerformanceCounter() : - m_iLowShift(0), - m_flPerfCounterFreq(0), - m_flCurrentTime(0), - m_flLastCurrentTime(0) -{ - InitializePerformanceCounter(); -} - -inline void CPerformanceCounter::InitializePerformanceCounter() -{ -#ifdef _WIN32 - - LARGE_INTEGER performanceFreq; - QueryPerformanceFrequency(&performanceFreq); - - // get 32 out of the 64 time bits such that we have around - // 1 microsecond resolution - unsigned int lowpart, highpart; - lowpart = (unsigned int)performanceFreq.LowPart; - highpart = (unsigned int)performanceFreq.HighPart; - m_iLowShift = 0; - - while (highpart || (lowpart > 2000000.0)) - { - m_iLowShift++; - lowpart >>= 1; - lowpart |= (highpart & 1) << 31; - highpart >>= 1; - } - - m_flPerfCounterFreq = 1.0 / (double)lowpart; - -#endif // _WIN32 -} - -inline double CPerformanceCounter::GetCurTime() -{ -#ifdef _WIN32 - - static int sametimecount; - static unsigned int oldtime; - static int first = 1; - LARGE_INTEGER PerformanceCount; - unsigned int temp, t2; - double time; - - QueryPerformanceCounter(&PerformanceCount); - if (m_iLowShift == 0) - { - temp = (unsigned int)PerformanceCount.LowPart; - } - else - { - temp = ((unsigned int)PerformanceCount.LowPart >> m_iLowShift) | - ((unsigned int)PerformanceCount.HighPart << (32 - m_iLowShift)); - } - - if (first) - { - oldtime = temp; - first = 0; - } - else - { - // check for turnover or backward time - if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000)) - { - // so we can't get stuck - oldtime = temp; - } - else - { - t2 = temp - oldtime; - - time = (double)t2 * m_flPerfCounterFreq; - oldtime = temp; - - m_flCurrentTime += time; - - if (m_flCurrentTime == m_flLastCurrentTime) - { - if (++sametimecount > 100000) - { - m_flCurrentTime += 1.0; - sametimecount = 0; - } - } - else - { - sametimecount = 0; - } - - m_flLastCurrentTime = m_flCurrentTime; - } - } - - return m_flCurrentTime; - -#else // _WIN32 - - struct timeval tp; - static int secbase = 0; - - gettimeofday(&tp, NULL); - - if (!secbase) - { - secbase = tp.tv_sec; - return (tp.tv_usec / 1000000.0); - } - - return ((tp.tv_sec - secbase) + tp.tv_usec / 1000000.0); - -#endif // _WIN32 -} - void _LogFunctionTrace(const char *pFunctionName, const char *param) { //{ @@ -141,7 +9,7 @@ void _LogFunctionTrace(const char *pFunctionName, const char *param) double _StartFunctionTimer() { - //CPerformanceCounter::GetCurTime(); + //CCounter::GetCurTime(); return 0; } @@ -149,7 +17,7 @@ void _LogFunctionTraceMaxTime(const char *pFunctionName, double startTime, doubl { //{ // double timeDiff; - // CPerformanceCounter::GetCurTime(); + // CCounter::GetCurTime(); // _LogFunctionTrace(const char *pFunctionName, const char *param); //} } diff --git a/rehlds/dedicated/src/icommandline.h b/rehlds/dedicated/src/icommandline.h deleted file mode 100644 index 3e65189..0000000 --- a/rehlds/dedicated/src/icommandline.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef ICOMMANDLINE_H -#define ICOMMANDLINE_H -#ifdef _WIN32 -#pragma once -#endif - -// Interface to engine command line -class ICommandLine { -public: - virtual void CreateCmdLine(const char *commandline) = 0; - virtual void CreateCmdLine(int argc, const char **argv) = 0; - virtual const char *GetCmdLine() const = 0; - - // Check whether a particular parameter exists - virtual const char *CheckParm(const char *psz, char **ppszValue = nullptr) const = 0; - virtual void RemoveParm(const char *pszParm) = 0; - virtual void AppendParm(const char *pszParm, const char *pszValues) = 0; - - virtual void SetParm(const char *pszParm, const char *pszValues) = 0; - virtual void SetParm(const char *pszParm, int iValue) = 0; -}; - -ICommandLine *CommandLine(); - -#endif // ICOMMANDLINE_H diff --git a/rehlds/dedicated/src/precompiled.h b/rehlds/dedicated/src/precompiled.h index 91e53c0..a475ef8 100644 --- a/rehlds/dedicated/src/precompiled.h +++ b/rehlds/dedicated/src/precompiled.h @@ -19,7 +19,6 @@ struct DLL_FUNCTIONS; #endif #include "sys_ded.h" -#include "icommandline.h" #include "textconsole.h" #include "vgui/vguihelpers.h" diff --git a/rehlds/engine/common.cpp b/rehlds/engine/common.cpp index 169b688..3a82b1e 100644 --- a/rehlds/engine/common.cpp +++ b/rehlds/engine/common.cpp @@ -33,12 +33,6 @@ char serverinfo[MAX_INFO_STRING]; char gpszVersionString[32]; char gpszProductString[32]; -char* strcpy_safe(char* dst, char* src) { - int len = Q_strlen(src); - Q_memmove(dst, src, len + 1); - return dst; -} - char *Info_Serverinfo(void) { return serverinfo; diff --git a/rehlds/engine/common.h b/rehlds/engine/common.h index 543de1f..1df658b 100644 --- a/rehlds/engine/common.h +++ b/rehlds/engine/common.h @@ -220,8 +220,25 @@ NOBODY uint64 Q_strtoull(char *str); #endif // Q_functions -//strcpy that works correctly with overlapping src and dst buffers -char* strcpy_safe(char* dst, char* src); +template +char *strcopy(char (&dest)[N], const char *src) { + Q_strncpy(dest, src, N - 1); + dest[N - 1] = '\0'; + return dest; +} + +inline char *strncopy(char *dest, const char *src, size_t n) { + Q_strncpy(dest, src, n - 1); + dest[n - 1] = '\0'; + return dest; +} + +// strcpy that works correctly with overlapping src and dst buffers +inline char *strcpy_safe(char *dst, char *src) { + int len = Q_strlen(src); + Q_memmove(dst, src, len + 1); + return dst; +} int build_number(void); char *Info_Serverinfo(void); diff --git a/rehlds/engine/net.h b/rehlds/engine/net.h index 0341b5e..2d300fa 100644 --- a/rehlds/engine/net.h +++ b/rehlds/engine/net.h @@ -86,7 +86,7 @@ enum { FRAG_NORMAL_STREAM = 0, FRAG_FILE_STREAM, - + MAX_STREAMS }; @@ -224,7 +224,7 @@ enum { FLOW_OUTGOING = 0, FLOW_INCOMING, - + MAX_FLOWS }; diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index 6dc4432..28bb037 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -1408,7 +1408,7 @@ void SV_WriteClientdataToMessage(client_t *client, sizebuf_t *msg) #ifdef REHLDS_FIXES // So, HL and CS games send absolute gametime in these vars, DMC and Ricochet games don't send absolute gametime // TODO: idk about other games - // FIXME: there is a loss of precision, because gamedll has already written float gametime in them + // FIXME: there is a loss of precision, because gamedll has already written float gametime in them if (sv_rehlds_local_gametime.value != 0.0f) { auto convertGlobalGameTimeToLocal = @@ -5255,7 +5255,7 @@ void SV_CreateGenericResources(void) Con_Printf("Can't precache .dll files: %s\n", com_token); else successful = true; - + } else successful = true; @@ -5642,7 +5642,7 @@ void SetCStrikeFlags(void) g_eGameType = GT_CZero; #else g_bIsCZero = 1; -#endif +#endif } else if (!Q_stricmp(com_gamedir, "czeror")) { @@ -5650,7 +5650,7 @@ void SetCStrikeFlags(void) g_eGameType = GT_CZeroRitual; #else g_bIsCZeroRitual = 1; -#endif +#endif } else if (!Q_stricmp(com_gamedir, "terror")) { @@ -5658,7 +5658,7 @@ void SetCStrikeFlags(void) g_eGameType = GT_TerrorStrike; #else g_bIsTerrorStrike = 1; -#endif +#endif } else if (!Q_stricmp(com_gamedir, "tfc")) { @@ -5666,7 +5666,7 @@ void SetCStrikeFlags(void) g_eGameType = GT_TFC; #else g_bIsTFC = 1; -#endif +#endif } #ifndef REHLDS_FIXES diff --git a/rehlds/engine/sv_remoteaccess.cpp b/rehlds/engine/sv_remoteaccess.cpp index 61c6736..1dcc1ca 100644 --- a/rehlds/engine/sv_remoteaccess.cpp +++ b/rehlds/engine/sv_remoteaccess.cpp @@ -36,16 +36,6 @@ CServerRemoteAccess::CServerRemoteAccess() { } void CServerRemoteAccess::WriteDataRequest(const void *buffer, int bufferSize) -{ - WriteDataRequest_noVirt(buffer, bufferSize); -} - -int CServerRemoteAccess::ReadDataResponse(void *data, int len) -{ - return ReadDataResponse_noVirt(data, len); -} - -void CServerRemoteAccess::WriteDataRequest_noVirt(const void *buffer, int bufferSize) { int requestID; int requestType; @@ -78,7 +68,7 @@ void CServerRemoteAccess::WriteDataRequest_noVirt(const void *buffer, int buffer } } -int CServerRemoteAccess::ReadDataResponse_noVirt(void *data, int len) +int CServerRemoteAccess::ReadDataResponse(void *data, int len) { int i = m_ResponsePackets.Head(); if (!m_ResponsePackets.IsValidIndex(i)) diff --git a/rehlds/engine/sv_remoteaccess.h b/rehlds/engine/sv_remoteaccess.h index 7948e38..4755ff7 100644 --- a/rehlds/engine/sv_remoteaccess.h +++ b/rehlds/engine/sv_remoteaccess.h @@ -52,9 +52,6 @@ public: virtual void WriteDataRequest(const void *buffer, int bufferSize); virtual int ReadDataResponse(void *data, int len); - void WriteDataRequest_noVirt(const void *buffer, int bufferSize); - int ReadDataResponse_noVirt(void *data, int len); - void SendMessageToAdminUI(const char *message); void RequestValue(int requestID, const char *variable); void SetValue(const char *variable, const char *value); diff --git a/rehlds/engine/sv_steam3.cpp b/rehlds/engine/sv_steam3.cpp index 0071e03..8b8d3bb 100644 --- a/rehlds/engine/sv_steam3.cpp +++ b/rehlds/engine/sv_steam3.cpp @@ -28,8 +28,6 @@ #include "precompiled.h" -bool (CSteam3Server::*pNotifyClientConnect)(client_t *client, const void *pvSteam2Key, uint32 ucbSteam2Key) = &CSteam3Server::NotifyClientConnect; - void CSteam3Server::OnGSPolicyResponse(GSPolicyResponse_t *pPolicyResponse) { if (CRehldsPlatformHolder::get()->SteamGameServer()->BSecure()) @@ -47,7 +45,7 @@ void CSteam3Server::OnLogonSuccess(SteamServersConnected_t *pLogonSuccess) } else { - m_bLogOnResult = 1; + m_bLogOnResult = true; if (!m_bLanOnly) Con_Printf("Connection to Steam servers successful.\n"); } @@ -107,12 +105,12 @@ void CSteam3Server::OnGSClientDenyHelper(client_t *cl, EDenyReason eDenyReason, break; case k_EDenyNotLoggedOn: - if (!this->m_bLanOnly) + if (!m_bLanOnly) SV_DropClient(cl, 0, "No Steam logon\n"); break; case k_EDenyLoggedInElseWhere: - if (!this->m_bLanOnly) + if (!m_bLanOnly) SV_DropClient(cl, 0, "This Steam account is being used in another location\n"); break; @@ -144,12 +142,12 @@ void CSteam3Server::OnGSClientDenyHelper(client_t *cl, EDenyReason eDenyReason, break; case k_EDenySteamConnectionLost: - if (!this->m_bLanOnly) + if (!m_bLanOnly) SV_DropClient(cl, 0, "Steam connection lost\n"); break; case k_EDenySteamConnectionError: - if (!this->m_bLanOnly) + if (!m_bLanOnly) SV_DropClient(cl, 0, "Unable to connect to Steam\n"); break; @@ -158,7 +156,7 @@ void CSteam3Server::OnGSClientDenyHelper(client_t *cl, EDenyReason eDenyReason, break; case k_EDenySteamValidationStalled: - if (this->m_bLanOnly) + if (m_bLanOnly) cl->network_userid.m_SteamID = 1; break; @@ -253,7 +251,7 @@ void CSteam3Server::Activate() if (m_bLoggedOn) { bLanOnly = sv_lan.value != 0.0; - if (this->m_bLanOnly != bLanOnly) + if (m_bLanOnly != bLanOnly) { m_bLanOnly = bLanOnly; m_bWantToBeSecure = !COM_CheckParm("-insecure") && !bLanOnly; @@ -261,7 +259,7 @@ void CSteam3Server::Activate() } else { - m_bLoggedOn = 1; + m_bLoggedOn = true; unIP = 0; usSteamPort = 26900; argSteamPort = COM_CheckParm("-sport"); @@ -333,13 +331,13 @@ void CSteam3Server::Activate() void CSteam3Server::Shutdown() { - if (this->m_bLoggedOn) + if (m_bLoggedOn) { SteamGameServer()->EnableHeartbeats(0); SteamGameServer()->LogOff(); SteamGameServer_Shutdown(); - this->m_bLoggedOn = false; + m_bLoggedOn = false; } } @@ -524,10 +522,10 @@ void CSteam3Server::SendUpdatedServerDetails() void CSteam3Client::Shutdown() { - if (this->m_bLoggedOn) + if (m_bLoggedOn) { SteamAPI_Shutdown(); - this->m_bLoggedOn = false; + m_bLoggedOn = false; } } @@ -879,7 +877,6 @@ void Master_SetMaster_f() return; } - pszCmd = Cmd_Argv(1); if (!pszCmd || !pszCmd[0]) return; @@ -890,14 +887,14 @@ void Master_SetMaster_f() { if (gfNoMasterServer) { - gfNoMasterServer = 0; + gfNoMasterServer = FALSE; CRehldsPlatformHolder::get()->SteamGameServer()->EnableHeartbeats(gfNoMasterServer != 0); } } } else { - gfNoMasterServer = 1; + gfNoMasterServer = TRUE; CRehldsPlatformHolder::get()->SteamGameServer()->EnableHeartbeats(gfNoMasterServer != 0); } } diff --git a/rehlds/engine/sv_steam3.h b/rehlds/engine/sv_steam3.h index 44d2169..16a4ff6 100644 --- a/rehlds/engine/sv_steam3.h +++ b/rehlds/engine/sv_steam3.h @@ -127,8 +127,6 @@ public: extern CSteam3Server *s_Steam3Server; extern CSteam3Client s_Steam3Client; -extern bool (CSteam3Server::*pNotifyClientConnect)(client_t *client, const void *pvSteam2Key, uint32 ucbSteam2Key); - uint64 ISteamGameServer_CreateUnauthenticatedUserConnection(); bool ISteamGameServer_BUpdateUserData(uint64 steamid, const char *netname, uint32 score); bool ISteamApps_BIsSubscribedApp(uint32 appid); diff --git a/rehlds/engine/sys_dll.h b/rehlds/engine/sys_dll.h index 0d03870..7e83a83 100644 --- a/rehlds/engine/sys_dll.h +++ b/rehlds/engine/sys_dll.h @@ -33,28 +33,12 @@ #include "FileSystem.h" #include "pr_dlls.h" -//vmodes.h must be included before cdll_int.h (wrect_t declaration) +// vmodes.h must be included before cdll_int.h (wrect_t declaration) #include "vmodes.h" #include "cdll_int.h" - -#define CONST_INTEGER_AS_STRING(x) #x //Wraps the integer in quotes, allowing us to form constant strings with it -#define __HACK_LINE_AS_STRING__(x) CONST_INTEGER_AS_STRING(x) //__LINE__ can only be converted to an actual number by going through this, otherwise the output is literally "__LINE__" -#define __LINE__AS_STRING __HACK_LINE_AS_STRING__(__LINE__) //Gives you the line number in constant string form - -#if defined _MSC_VER || defined __INTEL_COMPILER -#define NOXREFCHECK int __retAddr; __asm { __asm mov eax, [ebp + 4] __asm mov __retAddr, eax }; Sys_Error("[NOXREFCHECK]: %s: (" __FILE__ ":" __LINE__AS_STRING ") NOXREF, but called from 0x%.08x", __func__, __retAddr) -#else -// For EBP based stack (older gcc) (uncomment version apropriate for your compiler) -//#define NOXREFCHECK int __retAddr; __asm__ __volatile__("movl 4(%%ebp), %%eax;" "movl %%eax, %0":"=r"(__retAddr)::"%eax"); Sys_Error("[NOXREFCHECK]: %s: (" __FILE__ ":" __LINE__AS_STRING ") NOXREF, but called from 0x%.08x", __func__, __retAddr); -// For ESP based stack (newer gcc) (uncomment version apropriate for your compiler) -#define NOXREFCHECK int __retAddr; __asm__ __volatile__("movl 16(%%esp), %%eax;" "movl %%eax, %0":"=r"(__retAddr)::"%eax"); Sys_Error("[NOXREFCHECK]: %s: (" __FILE__ ":" __LINE__AS_STRING ") NOXREF, but called from 0x%.08x", __func__, __retAddr); -#endif - - #define MAX_DISCONNECT_REASON 256 - #ifdef HOOK_ENGINE #define g_hfind (*pg_hfind) diff --git a/rehlds/engine/sys_dll2.cpp b/rehlds/engine/sys_dll2.cpp index df546cf..ffe7b5a 100644 --- a/rehlds/engine/sys_dll2.cpp +++ b/rehlds/engine/sys_dll2.cpp @@ -92,7 +92,7 @@ void EXPORT F(IEngineAPI **api) { CreateInterfaceFn fn; fn = Sys_GetFactoryThis(); - *api = (IEngineAPI *)fn("VENGINE_LAUNCHER_API_VERSION002", NULL); + *api = (IEngineAPI *)fn(VENGINE_LAUNCHER_API_VERSION, NULL); } void Sys_GetCDKey(char *pszCDKey, int *nLength, int *bDedicated) @@ -574,25 +574,18 @@ void ClearIOStates(void) #endif // SWDS } - -class CEngineAPI : public IEngineAPI +class CEngineAPI: public IEngineAPI { public: - int Run(void *instance, char *basedir, char *cmdline, char *postRestartCmdLineArgs, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory) { return 0; } }; -CEngineAPI g_CEngineAPI; - -IBaseInterface *CreateCEngineAPI(void) -{ - return &g_CEngineAPI; -}; - -InterfaceReg g_CreateCEngineAPI = InterfaceReg(CreateCEngineAPI, "VENGINE_LAUNCHER_API_VERSION002"); +#ifndef HOOK_ENGINE +EXPOSE_SINGLE_INTERFACE(CEngineAPI, IEngineAPI, VENGINE_LAUNCHER_API_VERSION); +#endif // HOOK_ENGINE // TODO: Needs rechecking /* @@ -666,11 +659,6 @@ NOXREF int BuildMapCycleListHints(char **hints) */ bool CDedicatedServerAPI::Init(char *basedir, char *cmdline, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory) -{ - return Init_noVirt(basedir, cmdline, launcherFactory, filesystemFactory); -} - -bool CDedicatedServerAPI::Init_noVirt(char *basedir, char *cmdline, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory) { dedicated_ = (IDedicatedExports *)launcherFactory(VENGINE_DEDICATEDEXPORTS_API_VERSION, NULL); if (!dedicated_) @@ -709,12 +697,7 @@ bool CDedicatedServerAPI::Init_noVirt(char *basedir, char *cmdline, CreateInterf return false; } -int CDedicatedServerAPI::Shutdown(void) -{ - return Shutdown_noVirt(); -} - -int CDedicatedServerAPI::Shutdown_noVirt(void) +int CDedicatedServerAPI::Shutdown() { eng->Unload(); game->Shutdown(); @@ -729,12 +712,7 @@ int CDedicatedServerAPI::Shutdown_noVirt(void) return giActive; } -bool CDedicatedServerAPI::RunFrame(void) -{ - return RunFrame_noVirt(); -} - -bool CDedicatedServerAPI::RunFrame_noVirt(void) +bool CDedicatedServerAPI::RunFrame() { if (eng->GetQuitting()) return false; @@ -744,28 +722,15 @@ bool CDedicatedServerAPI::RunFrame_noVirt(void) } void CDedicatedServerAPI::AddConsoleText(char *text) -{ - AddConsoleText_noVirt(text); -} - -void CDedicatedServerAPI::AddConsoleText_noVirt(char *text) { Cbuf_AddText(text); } void CDedicatedServerAPI::UpdateStatus(float *fps, int *nActive, int *nMaxPlayers, char *pszMap) -{ - UpdateStatus_noVirt(fps, nActive, nMaxPlayers, pszMap); -} - -void CDedicatedServerAPI::UpdateStatus_noVirt(float *fps, int *nActive, int *nMaxPlayers, char *pszMap) { Host_GetHostInfo(fps, nActive, NULL, nMaxPlayers, pszMap); } #ifndef HOOK_ENGINE - EXPOSE_SINGLE_INTERFACE(CDedicatedServerAPI, IDedicatedServerAPI, VENGINE_HLDS_API_VERSION); - #endif // HOOK_ENGINE - diff --git a/rehlds/engine/sys_dll2.h b/rehlds/engine/sys_dll2.h index 805ae2e..6e856a5 100644 --- a/rehlds/engine/sys_dll2.h +++ b/rehlds/engine/sys_dll2.h @@ -72,14 +72,6 @@ public: virtual bool RunFrame(); virtual void AddConsoleText(char *text); virtual void UpdateStatus(float *fps, int *nActive, int *nMaxPlayers, char *pszMap); - - // non-virtual function's of wrap for hooks a virtual - // Only need to HOOK_ENGINE - bool Init_noVirt(char *basedir, char *cmdline, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory); - int Shutdown_noVirt(); - bool RunFrame_noVirt(); - void AddConsoleText_noVirt(char *text); - void UpdateStatus_noVirt(float *fps, int *nActive, int *nMaxPlayers, char *pszMap); }; const char *GetCurrentSteamAppName(); diff --git a/rehlds/engine/sys_engine.cpp b/rehlds/engine/sys_engine.cpp index 3ea8922..726f7a2 100644 --- a/rehlds/engine/sys_engine.cpp +++ b/rehlds/engine/sys_engine.cpp @@ -64,11 +64,6 @@ CEngine::~CEngine() } void CEngine::Unload() -{ - Unload_noVirt(); -} - -void CEngine::Unload_noVirt() { Sys_ShutdownGame(); m_nDLLState = DLL_INACTIVE; @@ -98,11 +93,6 @@ void ForceReloadProfile() } bool CEngine::Load(bool dedicated, char *basedir, char *cmdline) -{ - return Load_noVirt(dedicated, basedir, cmdline); -} - -bool CEngine::Load_noVirt(bool dedicated, char *basedir, char *cmdline) { bool success = false; SetState(DLL_ACTIVE); @@ -117,11 +107,6 @@ bool CEngine::Load_noVirt(bool dedicated, char *basedir, char *cmdline) } int CEngine::Frame() -{ - return Frame_noVirt(); -} - -int CEngine::Frame_noVirt() { #ifndef SWDS (*(void(**)(void))(*(_DWORD *)cdaudio + 24))(); @@ -160,82 +145,42 @@ int CEngine::Frame_noVirt() } void CEngine::SetSubState(int iSubState) -{ - SetSubState_noVirt(iSubState); -} - -void CEngine::SetSubState_noVirt(int iSubState) { if (iSubState != 1) GameSetSubState(iSubState); } void CEngine::SetState(int iState) -{ - SetState_noVirt(iState); -} - -void CEngine::SetState_noVirt(int iState) { m_nDLLState = iState; GameSetState(iState); } int CEngine::GetState() -{ - return GetState_noVirt(); -} - -int CEngine::GetState_noVirt() { return m_nDLLState; } int CEngine::GetSubState() -{ - return GetSubState_noVirt(); -} - -int CEngine::GetSubState_noVirt() { return m_nSubState; } double CEngine::GetFrameTime() -{ - return GetFrameTime_noVirt(); -} - -double CEngine::GetFrameTime_noVirt() { return m_fFrameTime; } double CEngine::GetCurTime() -{ - return GetCurTime_noVirt(); -} - -double CEngine::GetCurTime_noVirt() { return m_fCurTime; } void CEngine::TrapKey_Event(int key, bool down) -{ - TrapKey_Event_noVirt(key, down); -} - -void CEngine::TrapKey_Event_noVirt(int key, bool down) { } void CEngine::TrapMouse_Event(int buttons, bool down) -{ - TrapMouse_Event_noVirt(buttons, down); -} - -void CEngine::TrapMouse_Event_noVirt(int buttons, bool down) { if (m_bTrapMode && buttons && !down) { @@ -251,11 +196,6 @@ void CEngine::TrapMouse_Event_noVirt(int buttons, bool down) } void CEngine::StartTrapMode() -{ - StartTrapMode_noVirt(); -} - -void CEngine::StartTrapMode_noVirt() { if (!m_bTrapMode) { @@ -265,21 +205,11 @@ void CEngine::StartTrapMode_noVirt() } bool CEngine::IsTrapping() -{ - return IsTrapping_noVirt(); -} - -bool CEngine::IsTrapping_noVirt() { return m_bTrapMode; } bool CEngine::CheckDoneTrapping(int & buttons, int & key) -{ - return CheckDoneTrapping_noVirt(buttons, key); -} - -bool CEngine::CheckDoneTrapping_noVirt(int & buttons, int & key) { if (m_bTrapMode) { @@ -299,21 +229,11 @@ bool CEngine::CheckDoneTrapping_noVirt(int & buttons, int & key) } void CEngine::SetQuitting(int quittype) -{ - SetQuitting_noVirt(quittype); -} - -void CEngine::SetQuitting_noVirt(int quittype) { m_nQuitting = quittype; } int CEngine::GetQuitting() -{ - return GetQuitting_noVirt(); -} - -int CEngine::GetQuitting_noVirt() { return m_nQuitting; } diff --git a/rehlds/engine/sys_engine.h b/rehlds/engine/sys_engine.h index e3977d1..eeddd83 100644 --- a/rehlds/engine/sys_engine.h +++ b/rehlds/engine/sys_engine.h @@ -77,23 +77,4 @@ public: virtual bool CheckDoneTrapping(int& buttons, int& keys); virtual int GetQuitting(); virtual void SetQuitting(int quittype); - - // non-virtual function's of wrap for hooks a virtual - // Only need to HOOK_ENGINE - bool Load_noVirt(bool dedicated, char *rootDir, char *cmdLine); - void Unload_noVirt(); - void SetState_noVirt(int iState); - int GetState_noVirt(); - void SetSubState_noVirt(int iSubstate); - int GetSubState_noVirt(); - int Frame_noVirt(); - double GetFrameTime_noVirt(); - double GetCurTime_noVirt(); - void TrapKey_Event_noVirt(int key, bool down); - void TrapMouse_Event_noVirt(int buttons, bool down); - void StartTrapMode_noVirt(); - bool IsTrapping_noVirt(); - bool CheckDoneTrapping_noVirt(int& buttons, int& keys); - int GetQuitting_noVirt(); - void SetQuitting_noVirt(int quittype); }; diff --git a/rehlds/engine/sys_linuxwind.cpp b/rehlds/engine/sys_linuxwind.cpp index c719702..72b5061 100644 --- a/rehlds/engine/sys_linuxwind.cpp +++ b/rehlds/engine/sys_linuxwind.cpp @@ -52,41 +52,21 @@ CGame::~CGame() } bool CGame::Init(void *pvInstance) -{ - return Init_noVirt(pvInstance); -} - -bool CGame::Init_noVirt(void *pvInstance) { return true; } bool CGame::Shutdown() -{ - return Shutdown_noVirt(); -} - -bool CGame::Shutdown_noVirt() { return true; } bool CGame::CreateGameWindow() -{ - return CreateGameWindow_noVirt(); -} - -bool CGame::CreateGameWindow_noVirt() { return true; } void CGame::SleepUntilInput(int time) -{ - SleepUntilInput_noVirt(time); -} - -void CGame::SleepUntilInput_noVirt(int time) { #ifdef _WIN32 Sleep(time * 1000); @@ -96,49 +76,24 @@ void CGame::SleepUntilInput_noVirt(int time) } HWND CGame::GetMainWindow() -{ - return GetMainWindow_noVirt(); -} - -HWND CGame::GetMainWindow_noVirt() { return NULL; } -HWND * CGame::GetMainWindowAddress() -{ - return GetMainWindowAddress_noVirt(); -} - -HWND * CGame::GetMainWindowAddress_noVirt() +HWND *CGame::GetMainWindowAddress() { return NULL; } void CGame::SetWindowXY(int x, int y) -{ - SetWindowXY_noVirt(x, y); -} - -void CGame::SetWindowXY_noVirt(int x, int y) { } void CGame::SetWindowSize(int w, int h) -{ - SetWindowSize_noVirt(w, h); -} - -void CGame::SetWindowSize_noVirt(int w, int h) { } void CGame::GetWindowRect(int *x, int *y, int *w, int *h) -{ - GetWindowRect_noVirt(x, y, w, h); -} - -void CGame::GetWindowRect_noVirt(int *x, int *y, int *w, int *h) { if (x) *x = 0; if (y) *y = 0; @@ -147,48 +102,23 @@ void CGame::GetWindowRect_noVirt(int *x, int *y, int *w, int *h) } bool CGame::IsActiveApp() -{ - return IsActiveApp_noVirt(); -} - -bool CGame::IsActiveApp_noVirt() { return m_bActiveApp; } bool CGame::IsMultiplayer() -{ - return IsMultiplayer_noVirt(); -} - -bool CGame::IsMultiplayer_noVirt() { return true; } void CGame::PlayStartupVideos() -{ - return PlayStartupVideos_noVirt(); -} - -void CGame::PlayStartupVideos_noVirt() { } void CGame::PlayAVIAndWait(const char *aviFile) -{ - PlayAVIAndWait_noVirt(aviFile); -} - -void CGame::PlayAVIAndWait_noVirt(const char *aviFile) { } void CGame::SetCursorVisible(bool bState) -{ - SetCursorVisible_noVirt(bState); -} - -void CGame::SetCursorVisible_noVirt(bool bState) { } diff --git a/rehlds/engine/sys_linuxwnd.h b/rehlds/engine/sys_linuxwnd.h index 3d183b4..ae29e14 100644 --- a/rehlds/engine/sys_linuxwnd.h +++ b/rehlds/engine/sys_linuxwnd.h @@ -31,43 +31,26 @@ #include "maintypes.h" #include "igame.h" -class CGame: public IGame { -private: - bool m_bActiveApp; - -public: - CGame(); - virtual ~CGame(); - - virtual bool Init(void *pvInstance); - virtual bool Shutdown(); - virtual bool CreateGameWindow(); - virtual void SleepUntilInput(int time); - virtual HWND GetMainWindow(); - virtual HWND * GetMainWindowAddress(); - virtual void SetWindowXY(int x, int y); - virtual void SetWindowSize(int w, int h); - virtual void GetWindowRect(int *x, int *y, int *w, int *h); - virtual bool IsActiveApp(); - virtual bool IsMultiplayer(); - virtual void PlayStartupVideos(); - virtual void PlayAVIAndWait(const char *aviFile); - virtual void SetCursorVisible(bool bState); +class CGame: public IGame { +private: + bool m_bActiveApp; - // non-virtual function's of wrap for hooks a virtual - // Only need to HOOK_ENGINE - bool Init_noVirt(void *pvInstance); - bool Shutdown_noVirt(); - bool CreateGameWindow_noVirt(); - void SleepUntilInput_noVirt(int time); - HWND GetMainWindow_noVirt(); - HWND * GetMainWindowAddress_noVirt(); - void SetWindowXY_noVirt(int x, int y); - void SetWindowSize_noVirt(int w, int h); - void GetWindowRect_noVirt(int *x, int *y, int *w, int *h); - bool IsActiveApp_noVirt(); - bool IsMultiplayer_noVirt(); - void PlayStartupVideos_noVirt(); - void PlayAVIAndWait_noVirt(const char *aviFile); - void SetCursorVisible_noVirt(bool bState); +public: + CGame(); + virtual ~CGame(); + + virtual bool Init(void *pvInstance); + virtual bool Shutdown(); + virtual bool CreateGameWindow(); + virtual void SleepUntilInput(int time); + virtual HWND GetMainWindow(); + virtual HWND * GetMainWindowAddress(); + virtual void SetWindowXY(int x, int y); + virtual void SetWindowSize(int w, int h); + virtual void GetWindowRect(int *x, int *y, int *w, int *h); + virtual bool IsActiveApp(); + virtual bool IsMultiplayer(); + virtual void PlayStartupVideos(); + virtual void PlayAVIAndWait(const char *aviFile); + virtual void SetCursorVisible(bool bState); }; diff --git a/rehlds/hookers/6132_hooker.cpp b/rehlds/hookers/6132_hooker.cpp deleted file mode 100644 index a39c5f4..0000000 --- a/rehlds/hookers/6132_hooker.cpp +++ /dev/null @@ -1,2572 +0,0 @@ -/* -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2 of the License, or (at -* your option) any later version. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* In addition, as a special exception, the author gives permission to -* link the code of this program with the Half-Life Game Engine ("HL -* Engine") and Modified Game Libraries ("MODs") developed by Valve, -* L.L.C ("Valve"). You must obey the GNU General Public License in all -* respects for all of the code used other than the HL Engine and MODs -* from Valve. If you modify this file, you may extend this exception -* to your version of the file, but you are not obligated to do so. If -* you do not wish to do so, delete this exception statement from your -* version. -* -*/ - -#include "precompiled.h" - -template -size_t mfunc_ptr_cast(MFUNC f) { - auto x = f; - size_t addr = (size_t &)x; - return addr; -} - -// Offset where engine assumed be loaded to ajust hooks offsets. NULL for the Linux to trigger symbols searching. -#ifdef _WIN32 -extern const size_t g_BaseOffset = 0x01D00000; -#else -extern const size_t g_BaseOffset = NULL; -#endif - -/* - Requred hooks for runing hooker with rehlds API enabled: - Whole regions: - Common_MSG_region - Common_SZ_region - Sv_Steam3_region - - SysDll_region: - Sys_FloatTime, Sys_InitHardwareTimer - - Pr_Cmds_region: - SeedRandomNumberGenerator, ran1, fran1, RandomFloat, RandomLong, PF_GetPlayerAuthId - - Sv_Main_region: - SV_RejectConnection, SV_FilterUser, SV_CheckChallenge, SV_CheckIPRestrictions, SV_CheckIPConnectionReuse, SV_FinishCertificateCheck, SV_CheckKeyInfo - SV_CheckForDuplicateSteamID, SV_CheckForDuplicateNames, SV_CheckUserInfo, SV_ConnectClient, SVC_GetChallenge, SVC_ServiceChallenge, - SV_SetMaxclients, SV_CompareUserID, SV_GetIDString, SV_GetClientIDString -*/ - -//#define Common_MSG_region -//#define Common_SZ_region -#define Common_COM_region -#define Delta_region -#define Main_region -#define Zone_region -#define FileSystem_Internal_region -#define FileSystem_region -#define Unicode_StrTools_region -#define Cmd_region -#define Cvar_region -#define Info_region -//#define SysDll_region -#define Sys_Dll2_region -#define CModel_region -#define Model_region -#define Sv_Log_region -#define Cl_Null_region -#define Snd_Null_region -//#define Sv_Steam3_region -#define Host_region -#define Host_Cmd_region -#define Pmove_region -#define Pmovetst_region -#define Pr_Edict_region -//#define Pr_Cmds_region -#define Mathlib_region -#define World_region -#define Sv_Phys_region -#define Sv_Move_region -#define Sv_pmove_region -//#define Sv_Main_region -#define R_Studio_region -#define TraceInit_Region -#define Net_ws_region -#define Net_chan_region -#define Hashpak_region -#define Sv_user_region -#define Wad_region -#define Textures_region -#define Tmessage_region -#define Vid_null_region -#define L_studio_region -#define Crc_region -#define Sv_RemoteAccess_region -#define Com_custom -#define Sv_upld -#define Decals -#define IpratelimitWrapper_region -#define Sys_engine -#define Sys_linuxwind - -//#define Function_References_region -//#define Data_References_region - - -void* malloc_wrapper(size_t size) { - void* res = malloc(size); - //Rehlds_Debug_logAlloc(size, res); - return res; -} - -void* realloc_wrapper(void* orig, size_t newSize) { - void* res = realloc(orig, newSize); - //Rehlds_Debug_logRealloc(newSize, orig, res); - return res; -} - -void free_wrapper(void* mem) { - //Rehlds_Debug_logFree(mem); - free(mem); -} - -void* calloc_wrapper(size_t count, size_t size) { - void* res = calloc(count, size); - //Rehlds_Debug_logAlloc(size * count, res); - return res; -} - -void* __nh_malloc_wrapper(size_t sz, int unk) { - void* res = malloc(sz); - //Rehlds_Debug_logAlloc(sz, res); - return res; -} - - -FunctionHook g_FunctionHooks[] = -{ - // DO NOT DISABLE, other functions depends on memory allocation routines -#ifndef Mem_region - - { 0x01D50AB0, "Mem_Malloc", (size_t)&Mem_Malloc }, - { 0x01D50AD0, "Mem_ZeroMalloc", (size_t)&Mem_ZeroMalloc }, - { 0x01D50B00, "Mem_Realloc", (size_t)&Mem_Realloc }, - { 0x01D50B20, "Mem_Calloc", (size_t)&Mem_Calloc }, - { 0x01D50B40, "Mem_Strdup", (size_t)&Mem_Strdup }, - { 0x01D50B60, "Mem_Free", (size_t)&Mem_Free }, - -#ifdef _WIN32 - { 0x01DFE945, "_malloca", (size_t)&malloc_wrapper }, - { 0x01DFEA7F, "realloc", (size_t)&realloc_wrapper }, - { 0x01DFE35D, "_frea", (size_t)&free_wrapper }, - { 0x01DFF016, "calloc", (size_t)&calloc_wrapper }, - { 0x01DFE957, "__nh_malloc", (size_t)&__nh_malloc_wrapper }, - -#endif //_WIN32 - -#endif // Mem_region - -#ifndef Common_MSG_region - -#ifdef Q_functions - - //{ 0x, "Q_memset", (size_t)&Q_memset }, - //{ 0x, "Q_memcpy", (size_t)&Q_memcpy }, - //{ 0x, "Q_memcmp", (size_t)&Q_memcmp }, - { 0x01D28AF0, "Q_strcpy", (size_t)&Q_strcpy }, - //{ 0x, "Q_strncpy", (size_t)&Q_strncpy }, - { 0x01D28B50, "Q_strlen", (size_t)&Q_strlen }, - //{ 0x, "Q_strrchr", (size_t)&Q_strrchr }, - //{ 0x, "Q_strcat", (size_t)&Q_strcat }, - //{ 0x, "Q_strcmp", (size_t)&Q_strcmp }, - //{ 0x, "Q_strncmp", (size_t)&Q_strncmp }, - //{ 0x, "Q_strncasecmp", (size_t)&Q_strncasecmp }, - //{ 0x, "Q_strcasecmp", (size_t)&Q_strcasecmp }, - //{ 0x, "Q_stricmp", (size_t)&Q_stricmp }, - //{ 0x, "Q_strnicmp", (size_t)&Q_strnicmp }, - //{ 0x, "Q_atoi", (size_t)&Q_atoi }, - //{ 0x, "Q_atof", (size_t)&Q_atof }, - //{ 0x, "Q_strlwr", (size_t)&Q_strlwr }, - //{ 0x, "Q_FileNameCmp", (size_t)&Q_FileNameCmp }, - //{ 0x, "Q_strstr", (size_t)&Q_strstr }, - //{ 0x, "Q_strtoull", (size_t)&Q_strtoull }, - -#endif // Q_functions - - { 0x01D29290, "MSG_WriteChar", (size_t)&MSG_WriteChar }, - { 0x01D292B0, "MSG_WriteByte", (size_t)&MSG_WriteByte }, - { 0x01D292D0, "MSG_WriteShort", (size_t)&MSG_WriteShort }, - { 0x01D292F0, "MSG_WriteWord", (size_t)&MSG_WriteWord }, - { 0x01D29310, "MSG_WriteLong", (size_t)&MSG_WriteLong }, - { 0x01D29340, "MSG_WriteFloat", (size_t)&MSG_WriteFloat }, - { 0x01D29370, "MSG_WriteString", (size_t)&MSG_WriteString }, - { 0x01D293B0, "MSG_WriteBuf", (size_t)&MSG_WriteBuf }, - { 0x01D293D0, "MSG_WriteAngle", (size_t)&MSG_WriteAngle }, - { 0x01D29420, "MSG_WriteHiresAngle", (size_t)&MSG_WriteHiresAngle }, - { 0x01D29470, "MSG_WriteUsercmd", (size_t)&MSG_WriteUsercmd }, - { 0x01D294D0, "MSG_WriteOneBit", (size_t)&MSG_WriteOneBit }, - { 0x01D29550, "MSG_StartBitWriting", (size_t)&MSG_StartBitWriting }, - { 0x01D29580, "MSG_IsBitWriting", (size_t)&MSG_IsBitWriting }, // NOXREF - { 0x01D29590, "MSG_EndBitWriting", (size_t)&MSG_EndBitWriting }, - { 0x01D295E0, "MSG_WriteBits", (size_t)&MSG_WriteBits }, - { 0x01D29700, "MSG_WriteSBits", (size_t)&MSG_WriteSBits }, - { 0x01D29750, "MSG_WriteBitString", (size_t)&MSG_WriteBitString }, - { 0x01D29790, "MSG_WriteBitData", (size_t)&MSG_WriteBitData }, - { 0x01D297C0, "MSG_WriteBitAngle", (size_t)&MSG_WriteBitAngle }, - { 0x01D29850, "MSG_ReadBitAngle", (size_t)&MSG_ReadBitAngle }, - { 0x01D298A0, "MSG_CurrentBit", (size_t)&MSG_CurrentBit }, - { 0x01D298D0, "MSG_IsBitReading", (size_t)&MSG_IsBitReading }, // NOXREF - { 0x01D298E0, "MSG_StartBitReading", (size_t)&MSG_StartBitReading }, - { 0x01D29930, "MSG_EndBitReading", (size_t)&MSG_EndBitReading }, - { 0x01D29970, "MSG_ReadOneBit", (size_t)&MSG_ReadOneBit }, - { 0x01D29A00, "MSG_ReadBits", (size_t)&MSG_ReadBits }, - { 0x01D29B00, "MSG_PeekBits", (size_t)&MSG_PeekBits }, // NOXREF - { 0x01D29B40, "MSG_ReadSBits", (size_t)&MSG_ReadSBits }, - { 0x01D29B70, "MSG_ReadBitString", (size_t)&MSG_ReadBitString }, // NOXREF - { 0x01D29BB0, "MSG_ReadBitData", (size_t)&MSG_ReadBitData }, - { 0x01D29BE0, "MSG_ReadBitCoord", (size_t)&MSG_ReadBitCoord }, // NOXREF - { 0x01D29C70, "MSG_WriteBitCoord", (size_t)&MSG_WriteBitCoord }, - { 0x01D29D00, "MSG_ReadBitVec3Coord", (size_t)&MSG_ReadBitVec3Coord }, // NOXREF - { 0x01D29D50, "MSG_WriteBitVec3Coord", (size_t)&MSG_WriteBitVec3Coord }, - { 0x01D29E30, "MSG_ReadCoord", (size_t)&MSG_ReadCoord }, // NOXREF - { 0x01D29E60, "MSG_WriteCoord", (size_t)&MSG_WriteCoord }, - { 0x01D29E80, "MSG_ReadVec3Coord", (size_t)&MSG_ReadVec3Coord }, // NOXREF - { 0x01D29EC0, "MSG_WriteVec3Coord", (size_t)&MSG_WriteVec3Coord }, // NOXREF - { 0x01D29F00, "MSG_BeginReading", (size_t)&MSG_BeginReading }, - { 0x01D29F10, "MSG_ReadChar", (size_t)&MSG_ReadChar }, - { 0x01D29F50, "MSG_ReadByte", (size_t)&MSG_ReadByte }, - { 0x01D29F90, "MSG_ReadShort", (size_t)&MSG_ReadShort }, - { 0x01D29FE0, "MSG_ReadWord", (size_t)&MSG_ReadWord }, // NOXREF - { 0x01D2A030, "MSG_ReadLong", (size_t)&MSG_ReadLong }, - { 0x01D2A090, "MSG_ReadFloat", (size_t)&MSG_ReadFloat }, - { 0x01D2A0E0, "MSG_ReadBuf", (size_t)&MSG_ReadBuf }, - { 0x01D2A130, "MSG_ReadString", (size_t)&MSG_ReadString }, - { 0x01D2A170, "MSG_ReadStringLine", (size_t)&MSG_ReadStringLine }, - { 0x01D2A1B0, "MSG_ReadAngle", (size_t)&MSG_ReadAngle }, // NOXREF - { 0x01D2A1E0, "MSG_ReadHiresAngle", (size_t)&MSG_ReadHiresAngle }, // NOXREF - { 0x01D2A210, "MSG_ReadUsercmd", (size_t)&MSG_ReadUsercmd }, - -#endif // Common_MSG_region - -#ifndef Common_SZ_region - - { 0x01D2A260, "SZ_Alloc", (size_t)&SZ_Alloc }, - { 0x01D2A2A0, "SZ_Clear", (size_t)&SZ_Clear }, - { 0x01D2A2C0, "SZ_GetSpace", (size_t)&SZ_GetSpace }, - { 0x01D2A380, "SZ_Write", (size_t)&SZ_Write }, - { 0x01D2A3B0, "SZ_Print", (size_t)&SZ_Print }, - -#endif // Common_SZ_region - -#ifndef Common_COM_region - - { 0x01D08E50, "build_number", (size_t)&build_number }, - { 0x01D289E0, "Info_Serverinfo", (size_t)&Info_Serverinfo }, - { 0x01D28FF0, "COM_Nibble", (size_t)&COM_Nibble }, - { 0x01D29030, "COM_HexConvert", (size_t)&COM_HexConvert }, - //{ 0x01D29080, "COM_BinPrintf", (size_t)&COM_BinPrintf }, // NOXREF - { 0x01D29100, "COM_ExplainDisconnection", (size_t)&COM_ExplainDisconnection }, - { 0x01D29170, "COM_ExtendedExplainDisconnection", (size_t)&COM_ExtendedExplainDisconnection }, // NOXREF - { 0x01D2A410, "COM_SkipPath", (size_t)&COM_SkipPath }, // NOXREF - { 0x01D2A440, "COM_StripExtension", (size_t)&COM_StripExtension }, - { 0x01D2A4A0, "COM_FileExtension", (size_t)&COM_FileExtension }, - { 0x01D2A4F0, "COM_FileBase", (size_t)&COM_FileBase }, - { 0x01D2A580, "COM_DefaultExtension", (size_t)&COM_DefaultExtension }, - { 0x01D2A5D0, "COM_UngetToken", (size_t)&COM_UngetToken }, - { 0x01D2A5E0, "COM_Parse", (size_t)&COM_Parse }, - { 0x01D2A730, "COM_ParseLine", (size_t)&COM_ParseLine }, - { 0x01D2A7A0, "COM_TokenWaiting", (size_t)&COM_TokenWaiting }, // NOXREF - { 0x01D2A830, "COM_CheckParm", (size_t)&COM_CheckParm }, - { 0x01D2A880, "COM_InitArgv", (size_t)&COM_InitArgv }, - { 0x01D2A960, "COM_Init", (size_t)&COM_Init }, - { 0x01D2AA00, "va", (size_t)&va }, - { 0x01D2AA40, "vstr", (size_t)&vstr }, // NOXREF - { 0x01D2AAA0, "memsearch", (size_t)&memsearch }, // NOXREF - { 0x01D2AAD0, "COM_WriteFile", (size_t)&COM_WriteFile }, // NOXREF - { 0x01D2AB70, "COM_FixSlashes", (size_t)&COM_FixSlashes }, - { 0x01D2AB90, "COM_CreatePath", (size_t)&COM_CreatePath }, - { 0x01D2ABD0, "COM_CopyFile", (size_t)&COM_CopyFile }, // NOXREF - { 0x01D2AC70, "COM_ExpandFilename", (size_t)&COM_ExpandFilename }, // NOXREF - { 0x01D2ACD0, "COM_FileSize", (size_t)&COM_FileSize }, - { 0x01D2AD10, "COM_LoadFile", (size_t)&COM_LoadFile }, - { 0x01D2AE70, "COM_FreeFile", (size_t)&COM_FreeFile }, - { 0x01D2AEA0, "COM_CopyFileChunk", (size_t)&COM_CopyFileChunk }, - //{ 0x01D2AF40, "COM_LoadFileLimit", (size_t)&COM_LoadFileLimit }, // NOXREF - { 0x01D2B020, "COM_LoadHunkFile", (size_t)&COM_LoadHunkFile }, - { 0x01D2B040, "COM_LoadTempFile", (size_t)&COM_LoadTempFile }, - { 0x01D2B060, "COM_LoadCacheFile", (size_t)&COM_LoadCacheFile }, - { 0x01D2B080, "COM_LoadStackFile", (size_t)&COM_LoadStackFile }, // NOXREF - { 0x01D2B0B0, "COM_Shutdown", (size_t)&COM_Shutdown }, - { 0x01D2B0C0, "COM_AddAppDirectory", (size_t)&COM_AddAppDirectory }, // NOXREF - { 0x01D2B0E0, "COM_AddDefaultDir", (size_t)&COM_AddDefaultDir }, - { 0x01D2B100, "COM_StripTrailingSlash", (size_t)&COM_StripTrailingSlash }, - { 0x01D2B130, "COM_ParseDirectoryFromCmd", (size_t)&COM_ParseDirectoryFromCmd }, - { 0x01D2B1C0, "COM_SetupDirectories", (size_t)&COM_SetupDirectories }, - //{ 0x01D2B3D0, "COM_CheckPrintMap", (size_t)&COM_CheckPrintMap }, // Totally not exists on Linux (it is inlined), but present and used on Windows, anyway just commented it out - { 0x01D2B250, "COM_ListMaps", (size_t)&COM_ListMaps }, - { 0x01D2B410, "COM_Log", (size_t)&COM_Log }, - { 0x01D2B480, "COM_LoadFileForMe", (size_t)&COM_LoadFileForMe }, - { 0x01D2B4A0, "COM_CompareFileTime", (size_t)&COM_CompareFileTime }, - { 0x01D2B500, "COM_GetGameDir", (size_t)&COM_GetGameDir }, - { 0x01D2B530, "COM_EntsForPlayerSlots", (size_t)&COM_EntsForPlayerSlots }, - { 0x01D2B590, "COM_NormalizeAngles", (size_t)&COM_NormalizeAngles }, - { 0x01D2B610, "COM_Munge", (size_t)&COM_Munge }, - { 0x01D2B6A0, "COM_UnMunge", (size_t)&COM_UnMunge }, - { 0x01D2B730, "COM_Munge2", (size_t)&COM_Munge2 }, - { 0x01D2B7C0, "COM_UnMunge2", (size_t)&COM_UnMunge2 }, - { 0x01D2B850, "COM_Munge3", (size_t)&COM_Munge3 }, - { 0x01D2B8E0, "COM_UnMunge3", (size_t)&COM_UnMunge3 }, // NOXREF - { 0x01D2B970, "COM_GetApproxWavePlayLength", (size_t)&COM_GetApproxWavePlayLength }, - -#endif // Common_COM_region - -#ifndef Delta_region - - { 0x01D351D0, "DELTA_FindField", (size_t)&DELTA_FindField }, - { 0x01D35240, "DELTA_FindFieldIndex", (size_t)&DELTA_FindFieldIndex }, - { 0x01D352A0, "DELTA_SetField", (size_t)&DELTA_SetField }, - { 0x01D352C0, "DELTA_UnsetField", (size_t)&DELTA_UnsetField }, - { 0x01D352E0, "DELTA_SetFieldByIndex", (size_t)&DELTA_SetFieldByIndex }, - { 0x01D35300, "DELTA_UnsetFieldByIndex", (size_t)&DELTA_UnsetFieldByIndex }, - { 0x01D35320, "DELTA_ClearFlags", (size_t)&DELTA_ClearFlags }, - { 0x01D35340, "DELTA_TestDelta", (size_t)&DELTA_TestDelta }, - { 0x01D355B0, "DELTA_CountSendFields", (size_t)&DELTA_CountSendFields }, - { 0x01D355E0, "DELTA_MarkSendFields", (size_t)&DELTA_MarkSendFields }, - { 0x01D35830, "DELTA_SetSendFlagBits", (size_t)&DELTA_SetSendFlagBits }, - { 0x01D358B0, "DELTA_WriteMarkedFields", (size_t)&DELTA_WriteMarkedFields }, - { 0x01D35C10, "DELTA_CheckDelta", (size_t)&DELTA_CheckDelta }, - { 0x01D35C40, "DELTA_WriteDelta", (size_t)&DELTA_WriteDelta }, - { 0x01D35C80, "_DELTA_WriteDelta", (size_t)&_DELTA_WriteDelta }, - { 0x01D35D00, "DELTA_ParseDelta", (size_t)&DELTA_ParseDelta }, - - { 0x01D36420, "DELTA_AddEncoder", (size_t)&DELTA_AddEncoder }, - { 0x01D36460, "DELTA_ClearEncoders", (size_t)&DELTA_ClearEncoders }, - { 0x01D364A0, "DELTA_LookupEncoder", (size_t)&DELTA_LookupEncoder }, - { 0x01D364E0, "DELTA_CountLinks", (size_t)&DELTA_CountLinks }, - { 0x01D36500, "DELTA_ReverseLinks", (size_t)&DELTA_ReverseLinks }, - { 0x01D36520, "DELTA_ClearLinks", (size_t)&DELTA_ClearLinks }, - { 0x01D36550, "DELTA_BuildFromLinks", (size_t)&DELTA_BuildFromLinks }, - { 0x01D365F0, "DELTA_FindOffset", (size_t)&DELTA_FindOffset }, - { 0x01D36640, "DELTA_ParseType", (size_t)&DELTA_ParseType }, - { 0x01D36800, "DELTA_ParseField", (size_t)&DELTA_ParseField }, - { 0x01D36A10, "DELTA_FreeDescription", (size_t)&DELTA_FreeDescription }, - { 0x01D36A50, "DELTA_AddDefinition", (size_t)&DELTA_AddDefinition }, - { 0x01D36AB0, "DELTA_ClearDefinitions", (size_t)&DELTA_ClearDefinitions }, - { 0x01D36AF0, "DELTA_FindDefinition", (size_t)&DELTA_FindDefinition }, - { 0x01D36B40, "DELTA_SkipDescription", (size_t)&DELTA_SkipDescription }, - { 0x01D36BA0, "DELTA_ParseOneField", (size_t)&DELTA_ParseOneField }, - { 0x01D36C50, "DELTA_ParseDescription", (size_t)&DELTA_ParseDescription }, - { 0x01D36EA0, "DELTA_Load", (size_t)&DELTA_Load }, - { 0x01D36EF0, "DELTA_RegisterDescription", (size_t)&DELTA_RegisterDescription }, - { 0x01D36F30, "DELTA_ClearRegistrations", (size_t)&DELTA_ClearRegistrations }, - { 0x01D36FC0, "DELTA_ClearStats", (size_t)&DELTA_ClearStats }, - { 0x01D36FF0, "DELTA_ClearStats_f", (size_t)&DELTA_ClearStats_f }, - { 0x01D36F80, "DELTA_LookupRegistration", (size_t)&DELTA_LookupRegistration }, - { 0x01D37020, "DELTA_PrintStats", (size_t)&DELTA_PrintStats }, - { 0x01D37090, "DELTA_DumpStats_f", (size_t)&DELTA_DumpStats_f }, - { 0x01D370C0, "DELTA_Init", (size_t)&DELTA_Init }, - { 0x01D37160, "DELTA_Shutdown", (size_t)&DELTA_Shutdown }, - -#endif // Delta_region - -#ifndef Sv_Main_region - -// { 0x01D87E40, "SV_LookupDelta", (size_t)&SV_LookupDelta }, -// { 0x01D87E90, "SV_DownloadingModules", (size_t)&SV_DownloadingModules }, // NOXREF -// { 0x01D87F70, "SV_GatherStatistics", (size_t)&SV_GatherStatistics }, -// { 0x01D88190, "SV_DeallocateDynamicData", (size_t)&SV_DeallocateDynamicData }, -// { 0x01D881D0, "SV_ReallocateDynamicData", (size_t)&SV_ReallocateDynamicData }, -// { 0x01D88250, "SV_AllocClientFrames", (size_t)&SV_AllocClientFrames }, -// { 0x01D882B0, "SV_IsPlayerIndex", (size_t)&SV_IsPlayerIndex_wrapped }, -// { 0x01D882D0, "SV_ClearPacketEntities", (size_t)&SV_ClearPacketEntities }, -// { 0x01D88310, "SV_AllocPacketEntities", (size_t)&SV_AllocPacketEntities }, -// { 0x01D88370, "SV_ClearFrames", (size_t)&SV_ClearFrames }, -// { 0x01D883E0, "SV_Serverinfo_f", (size_t)&SV_Serverinfo_f }, -// { 0x01D884C0, "SV_Localinfo_f", (size_t)&SV_Localinfo_f }, -// { 0x01D88550, "SV_User_f", (size_t)&SV_User_f }, -// { 0x01D88640, "SV_Users_f", (size_t)&SV_Users_f }, -// { 0x01D88700, "SV_CountPlayers", (size_t)&SV_CountPlayers }, -// { 0x01D88740, "SV_CountProxies", (size_t)&SV_CountProxies }, -// { 0x01D88790, "SV_FindModelNumbers", (size_t)&SV_FindModelNumbers }, -// { 0x01D887D0, "SV_StartParticle", (size_t)&SV_StartParticle }, -// { 0x01D88880, "SV_StartSound", (size_t)&SV_StartSound }, -// { 0x01D88960, "SV_BuildSoundMsg", (size_t)&SV_BuildSoundMsg }, -// { 0x01D88BD0, "SV_HashString", (size_t)&SV_HashString }, -// { 0x01D88C10, "SV_LookupSoundIndex", (size_t)&SV_LookupSoundIndex }, -// { 0x01D88CD0, "SV_BuildHashedSoundLookupTable", (size_t)&SV_BuildHashedSoundLookupTable }, -// { 0x01D88D20, "SV_AddSampleToHashedLookupTable", (size_t)&SV_AddSampleToHashedLookupTable }, -// { 0x01D88DA0, "SV_ValidClientMulticast", (size_t)&SV_ValidClientMulticast }, -// { 0x01D88E40, "SV_Multicast", (size_t)&SV_Multicast }, -// { 0x01D88FA0, "SV_WriteMovevarsToClient", (size_t)&SV_WriteMovevarsToClient }, -// { 0x01D89110, "SV_WriteDeltaDescriptionsToClient", (size_t)&SV_WriteDeltaDescriptionsToClient }, -// { 0x01D891B0, "SV_SetMoveVars", (size_t)&SV_SetMoveVars }, -// { 0x01D892F0, "SV_QueryMovevarsChanged", (size_t)&SV_QueryMovevarsChanged }, -// { 0x01D89590, "SV_SendServerinfo", (size_t)&SV_SendServerinfo }, -// { 0x01D897C0, "SV_SendResources", (size_t)&SV_SendResources }, -// { 0x01D89920, "SV_WriteClientdataToMessage", (size_t)&SV_WriteClientdataToMessage }, -// { 0x01D89BF0, "SV_WriteSpawn", (size_t)&SV_WriteSpawn }, -// { 0x01D89F10, "SV_SendUserReg", (size_t)&SV_SendUserReg }, -// { 0x01D89F80, "SV_New_f", (size_t)&SV_New_f }, -// { 0x01D8A210, "SV_SendRes_f", (size_t)&SV_SendRes_f }, -// { 0x01D8A2C0, "SV_Spawn_f", (size_t)&SV_Spawn_f }, -// { 0x01D8A3F0, "SV_CheckUpdateRate", (size_t)&SV_CheckUpdateRate }, - { 0x01D8A510, "SV_RejectConnection", (size_t)&SV_RejectConnection }, -// { 0x01D8A5A0, "SV_RejectConnectionForPassword", (size_t)&SV_RejectConnectionForPassword }, -// { 0x01D8A610, "SV_GetFragmentSize", (size_t)&SV_GetFragmentSize }, - { 0x01D8A680, "SV_FilterUser", (size_t)&SV_FilterUser }, -// { 0x01D8A760, "SV_CheckProtocol", (size_t)&SV_CheckProtocol }, - { 0x01D8A7E0, "SV_CheckChallenge", (size_t)&SV_CheckChallenge }, - { 0x01D8A8D0, "SV_CheckIPRestrictions", (size_t)&SV_CheckIPRestrictions }, - { 0x01D8A980, "SV_CheckIPConnectionReuse", (size_t)&SV_CheckIPConnectionReuse }, - { 0x01D8AA40, "SV_FinishCertificateCheck", (size_t)&SV_FinishCertificateCheck }, - { 0x01D8AB10, "SV_CheckKeyInfo", (size_t)&SV_CheckKeyInfo }, - { 0x01D8AC30, "SV_CheckForDuplicateSteamID", (size_t)&SV_CheckForDuplicateSteamID }, - { 0x01D8ACE0, "SV_CheckForDuplicateNames", (size_t)&SV_CheckForDuplicateNames }, - { 0x01D8AE10, "SV_CheckUserInfo", (size_t)&SV_CheckUserInfo }, -// { 0x01D8B080, "SV_FindEmptySlot", (size_t)&SV_FindEmptySlot }, - { 0x01D8B100, "SV_ConnectClient", (size_t)&SV_ConnectClient }, -// { 0x01D8B8E0, "SVC_Ping", (size_t)&SVC_Ping }, - { 0x01D8B930, "SVC_GetChallenge", (size_t)&SVC_GetChallenge }, - { 0x01D8BB20, "SVC_ServiceChallenge", (size_t)&SVC_ServiceChallenge }, -// { 0x01D8BCB0, "SV_ResetModInfo", (size_t)&SV_ResetModInfo }, - //{ 0x01D8BE40, "SV_GetFakeClientCount", (size_t)&SV_GetFakeClientCount },//NOXREF - //{ 0x01D8BE70, "SV_GetModInfo", (size_t)&SV_GetModInfo }, //NOXREF - //{ 0x01D8BF40, "RequireValidChallenge", (size_t)&RequireValidChallenge }, //NOXREF - //{ 0x01D8BF60, "ValidInfoChallenge", (size_t)&ValidInfoChallenge }, //NOXREF - //{ 0x01D8BFB0, "GetChallengeNr", (size_t)&GetChallengeNr }, //NOXREF - //{ 0x01D8C0C0, "CheckChallengeNr", (size_t)&CheckChallengeNr }, //NOXREF - //{ 0x01D8C180, "ReplyServerChallenge", (size_t)&ReplyServerChallenge }, //NOXREF - //{ 0x01D8C200, "ValidChallenge", (size_t)&ValidChallenge }, //NOXREF - //{ 0x01D8C260, "SVC_InfoString", (size_t)&SVC_InfoString }, //NOXREF - //{ 0x01D8C720, "SVC_Info", (size_t)&SVC_Info }, //NOXREF - //{ 0x01D8CA40, "SVC_PlayerInfo", (size_t)&SVC_PlayerInfo }, //NOXREF - //{ 0x01D8CBA0, "SVC_RuleInfo", (size_t)&SVC_RuleInfo }, //NOXREF -// { 0x01D8CCC0, "SVC_GameDllQuery", (size_t)&SVC_GameDllQuery }, -// { 0x01D8CD70, "SV_FlushRedirect", (size_t)&SV_FlushRedirect }, -// { 0x01D8CE70, "SV_BeginRedirect", (size_t)&SV_BeginRedirect }, -// { 0x01D8CEA0, "SV_EndRedirect", (size_t)&SV_EndRedirect }, -// { 0x01D8CEB0, "SV_ResetRcon_f", (size_t)&SV_ResetRcon_f }, -// { 0x01D8CED0, "SV_AddFailedRcon", (size_t)&SV_AddFailedRcon }, -// { 0x01D8D1F0, "SV_CheckRconFailure", (size_t)&SV_CheckRconFailure }, -// { 0x01D8D250, "SV_Rcon_Validate", (size_t)&SV_Rcon_Validate }, -// { 0x01D8D370, "SV_Rcon", (size_t)&SV_Rcon }, -// { 0x01D8D560, "SV_ConnectionlessPacket", (size_t)&SV_ConnectionlessPacket }, -// { 0x01D8D750, "SV_CheckRate", (size_t)&SV_CheckRate }, -// { 0x01D8D810, "SV_ProcessFile", (size_t)&SV_ProcessFile }, -// { 0x01D8D960, "SV_FilterPacket", (size_t)&SV_FilterPacket }, -// { 0x01D8DA30, "SV_SendBan", (size_t)&SV_SendBan }, -// { 0x01D8DAB0, "SV_ReadPackets", (size_t)&SV_ReadPackets }, - //{ 0x, "ntohl", (size_t)&ntohl }, - //{ 0x, "htons", (size_t)&htons }, -// { 0x01D8DCC0, "SV_CheckTimeouts", (size_t)&SV_CheckTimeouts }, -// { 0x01D8DD50, "SV_CalcPing", (size_t)&SV_CalcPing }, -// { 0x01D8DE20, "SV_FullClientUpdate", (size_t)&SV_FullClientUpdate }, -// { 0x01D8DEF0, "SV_EmitEvents", (size_t)&SV_EmitEvents }, -// { 0x01D8E0F0, "SV_AddToFatPVS", (size_t)&SV_AddToFatPVS }, -// { 0x01D8E1B0, "SV_FatPVS", (size_t)&SV_FatPVS }, -// { 0x01D8E200, "SV_AddToFatPAS", (size_t)&SV_AddToFatPAS }, -// { 0x01D8E2D0, "SV_FatPAS", (size_t)&SV_FatPAS }, -// { 0x01D8E320, "SV_PointLeafnum", (size_t)&SV_PointLeafnum }, - //{ 0x, "TRACE_DELTA", (size_t)&TRACE_DELTA }, //NOXREF -// { 0x01D8E370, "SV_SetCallback", (size_t)&SV_SetCallback }, -// { 0x01D8E3C0, "SV_SetNewInfo", (size_t)&SV_SetNewInfo }, -// { 0x01D8E3E0, "SV_WriteDeltaHeader", (size_t)&SV_WriteDeltaHeader }, -// { 0x01D8E4E0, "SV_InvokeCallback", (size_t)&SV_InvokeCallback }, -// { 0x01D8E520, "SV_FindBestBaseline", (size_t)&SV_FindBestBaseline }, -// { 0x01D8E650, "SV_CreatePacketEntities", (size_t)&SV_CreatePacketEntities }, -// { 0x01D8E9A0, "SV_EmitPacketEntities", (size_t)&SV_EmitPacketEntities }, -// { 0x01D8E9E0, "SV_ShouldUpdatePing", (size_t)&SV_ShouldUpdatePing }, - //{ 0x01D8EA40, "SV_HasEventsInQueue", (size_t)&SV_HasEventsInQueue }, //NOXREF -// { 0x01D8EA70, "SV_GetNetInfo", (size_t)&SV_GetNetInfo }, -// { 0x01D8EB00, "SV_CheckVisibility", (size_t)&SV_CheckVisibility }, -// { 0x01D8EBF0, "SV_EmitPings", (size_t)&SV_EmitPings }, -// { 0x01D8EC90, "SV_WriteEntitiesToClient", (size_t)&SV_WriteEntitiesToClient }, -// { 0x01D8EE90, "SV_CleanupEnts", (size_t)&SV_CleanupEnts }, -// { 0x01D8EEC0, "SV_SendClientDatagram", (size_t)&SV_SendClientDatagram }, -// { 0x01D8EFC0, "SV_UpdateToReliableMessages", (size_t)&SV_UpdateToReliableMessages }, -// { 0x01D8F230, "SV_SkipUpdates", (size_t)&SV_SkipUpdates }, -// { 0x01D8F280, "SV_SendClientMessages", (size_t)&SV_SendClientMessages }, -// { 0x01D8F470, "SV_ExtractFromUserinfo", (size_t)&SV_ExtractFromUserinfo }, -// { 0x01D8F870, "SV_ModelIndex", (size_t)&SV_ModelIndex }, -// { 0x01D8F8E0, "SV_AddResource", (size_t)&SV_AddResource }, -// { 0x01D8F950, "SV_CreateGenericResources", (size_t)&SV_CreateGenericResources }, -// { 0x01D8FC30, "SV_CreateResourceList", (size_t)&SV_CreateResourceList }, -// { 0x01D8FDC0, "SV_ClearCaches", (size_t)&SV_ClearCaches }, -// { 0x01D8FE00, "SV_PropagateCustomizations", (size_t)&SV_PropagateCustomizations }, -// { 0x01D8FF00, "SV_WriteVoiceCodec", (size_t)&SV_WriteVoiceCodec }, -// { 0x01D8FF30, "SV_CreateBaseline", (size_t)&SV_CreateBaseline }, -// { 0x01D90170, "SV_BroadcastCommand", (size_t)&SV_BroadcastCommand }, -// { 0x01D90260, "SV_BuildReconnect", (size_t)&SV_BuildReconnect }, - //{ 0x01D90280, "SV_ReconnectAllClients", (size_t)&SV_ReconnectAllClients }, //NOXREF -// { 0x01D903D0, "SetCStrikeFlags", (size_t)&SetCStrikeFlags }, -// { 0x01D904E0, "SV_ActivateServer", (size_t)&SV_ActivateServer }, -// { 0x01D90790, "SV_ServerShutdown", (size_t)&SV_ServerShutdown }, -// { 0x01D907C0, "SV_SpawnServer", (size_t)&SV_SpawnServer }, -// { 0x01D90E70, "SV_LoadEntities", (size_t)&SV_LoadEntities }, -// { 0x01D90E90, "SV_ClearEntities", (size_t)&SV_ClearEntities }, -// { 0x01D90ED0, "RegUserMsg", (size_t)&RegUserMsg }, -// { 0x01D90F80, "StringToFilter", (size_t)&StringToFilter }, -// { 0x01D91020, "SV_StringToUserID", (size_t)&SV_StringToUserID }, -// { 0x01D910C0, "SV_BanId_f", (size_t)&SV_BanId_f }, -// { 0x01D915C0, "Host_Kick_f", (size_t)&Host_Kick_f }, -// { 0x01D91990, "SV_RemoveId_f", (size_t)&SV_RemoveId_f }, -// { 0x01D91B90, "SV_WriteId_f", (size_t)&SV_WriteId_f }, -// { 0x01D91C60, "SV_ListId_f", (size_t)&SV_ListId_f }, -// { 0x01D91D00, "SV_AddIP_f", (size_t)&SV_AddIP_f }, -// { 0x01D91F00, "SV_RemoveIP_f", (size_t)&SV_RemoveIP_f }, -// { 0x01D91FD0, "SV_ListIP_f", (size_t)&SV_ListIP_f }, -// { 0x01D920B0, "SV_WriteIP_f", (size_t)&SV_WriteIP_f }, -// { 0x01D92190, "SV_KickPlayer", (size_t)&SV_KickPlayer }, -// { 0x01D92300, "SV_InactivateClients", (size_t)&SV_InactivateClients }, -// { 0x01D923A0, "SV_FailDownload", (size_t)&SV_FailDownload }, -// { 0x01D923E0, "Q_stristr", (size_t)&Q_stristr }, -// { 0x01D92480, "IsSafeFileToDownload", (size_t)&IsSafeFileToDownload }, -// { 0x01D92710, "SV_BeginFileDownload_f", (size_t)&SV_BeginFileDownload_f }, - { 0x01D92940, "SV_SetMaxclients", (size_t)&SV_SetMaxclients }, -// { 0x01D92B00, "SV_HandleRconPacket", (size_t)&SV_HandleRconPacket }, -// { 0x01D92B70, "SV_CheckCmdTimes", (size_t)&SV_CheckCmdTimes }, -// { 0x01D92C60, "SV_CheckForRcon", (size_t)&SV_CheckForRcon }, -// { 0x01D92CC0, "SV_IsSimulating", (size_t)&SV_IsSimulating }, -// { 0x01D92D00, "SV_CheckMapDifferences", (size_t)&SV_CheckMapDifferences }, -// { 0x01D92D80, "SV_Frame", (size_t)&SV_Frame }, -// { 0x01D92E00, "SV_Drop_f", (size_t)&SV_Drop_f }, -// { 0x01D92E40, "SV_RegisterDelta", (size_t)&SV_RegisterDelta }, -// { 0x01D92EC0, "SV_InitDeltas", (size_t)&SV_InitDeltas }, -// { 0x01D93010, "SV_InitEncoders", (size_t)&SV_InitEncoders }, -// { 0x01D93050, "SV_Init", (size_t)&SV_Init }, -// { 0x01D93600, "SV_Shutdown", (size_t)&SV_Shutdown }, - { 0x01D93650, "SV_CompareUserID", (size_t)&SV_CompareUserID }, - { 0x01D936D0, "SV_GetIDString", (size_t)&SV_GetIDString }, - { 0x01D938E0, "SV_GetClientIDString", (size_t)&SV_GetClientIDString }, -// { 0x01D93950, "GetGameAppID", (size_t)&GetGameAppID }, -// { 0x01D939C0, "IsGameSubscribed", (size_t)&IsGameSubscribed }, -// { 0x01D93A10, "BIsValveGame", (size_t)&BIsValveGame }, //NOXREF - -#endif // Sv_Main_region - -#ifndef Zone_region - - { 0x01DBB120, "Z_ClearZone", (size_t)&Z_ClearZone }, - { 0x01DBB170, "Z_Free", (size_t)&Z_Free }, - { 0x01DBB220, "Z_Malloc", (size_t)&Z_Malloc }, - { 0x01DBB260, "Z_TagMalloc", (size_t)&Z_TagMalloc }, - { 0x01DBB310, "Z_Print", (size_t)&Z_Print }, // NOXREF - { 0x01DBB3C0, "Z_CheckHeap", (size_t)&Z_CheckHeap }, - - { 0x01DBB440, "Hunk_Check", (size_t)&Hunk_Check }, - { 0x01DBB4B0, "Hunk_Print", (size_t)&Hunk_Print }, // NOXREF - { 0x01DBB6B0, "Hunk_AllocName", (size_t)&Hunk_AllocName }, - { 0x01DBB750, "Hunk_Alloc", (size_t)&Hunk_Alloc }, - { 0x01DBB770, "Hunk_LowMark", (size_t)&Hunk_LowMark }, - { 0x01DBB780, "Hunk_FreeToLowMark", (size_t)&Hunk_FreeToLowMark }, - { 0x01DBB7B0, "Hunk_HighMark", (size_t)&Hunk_HighMark }, - { 0x01DBB7E0, "Hunk_FreeToHighMark", (size_t)&Hunk_FreeToHighMark }, - { 0x01DBB830, "Hunk_HighAllocName", (size_t)&Hunk_HighAllocName }, - { 0x01DBB900, "Hunk_TempAlloc", (size_t)&Hunk_TempAlloc }, - - { 0x01DBB960, "Cache_Move", (size_t)&Cache_Move }, - { 0x01DBB9D0, "Cache_FreeLow", (size_t)&Cache_FreeLow }, - { 0x01DBBA00, "Cache_FreeHigh", (size_t)&Cache_FreeHigh }, - { 0x01DBBA60, "Cache_UnlinkLRU", (size_t)&Cache_UnlinkLRU }, - { 0x01DBBAA0, "Cache_MakeLRU", (size_t)&Cache_MakeLRU }, - { 0x01DBBAF0, "Cache_TryAlloc", (size_t)&Cache_TryAlloc }, - { 0x01DBBC30, "Cache_Force_Flush", (size_t)&Cache_Force_Flush }, - { 0x01DBBC60, "Cache_Flush", (size_t)&Cache_Flush }, - { 0x01DBBD60, "CacheSystemCompare", (size_t)&CacheSystemCompare }, // NOXREF - { 0x01DBBC90, "Cache_Print", (size_t)&Cache_Print }, // NOXREF - //{ 0x, "ComparePath1", (size_t)&ComparePath1 }, // NOXREF // not yet located on windows - //{ 0x, "CommatizeNumber", (size_t)&CommatizeNumber }, // NOXREF // not yet located on windows - //{ 0x, "Cache_Report", (size_t)&Cache_Report }, // NOXREF // not yet located on windows - //{ 0x, "Cache_Compact", (size_t)&Cache_Compact }, // NOXREF // not yet located on windows - { 0x01DBBED0, "Cache_Init", (size_t)&Cache_Init }, - { 0x01DBBF00, "Cache_Free", (size_t)&Cache_Free }, - { 0x01DBBF50, "Cache_TotalUsed", (size_t)&Cache_TotalUsed }, // NOXREF - { 0x01DBBF70, "Cache_Check", (size_t)&Cache_Check }, - { 0x01DBBFA0, "Cache_Alloc", (size_t)&Cache_Alloc }, - { 0x01DBC040, "Memory_Init", (size_t)&Memory_Init }, - //{ 0x01DBC0E0, "Cache_Print_Sounds_And_Totals", (size_t)&Cache_Print_Models_And_Totals }, // NOXREF - //{ 0x01DBC1F0, "Cache_Print_Sounds_And_Totals", (size_t)&Cache_Print_Sounds_And_Totals }, // NOXREF - -#endif // Zone_region - -#ifndef FileSystem_Internal_region - - { 0x01D3E2E0, "FS_RemoveAllSearchPaths", (size_t)&FS_RemoveAllSearchPaths }, // NOXREF - { 0x01D3E2F0, "FS_AddSearchPath", (size_t)&FS_AddSearchPath }, - { 0x01D3E310, "FS_RemoveSearchPath", (size_t)&FS_RemoveSearchPath }, // NOXREF - { 0x01D3E330, "FS_RemoveFile", (size_t)&FS_RemoveFile }, - { 0x01D3E350, "FS_CreateDirHierarchy", (size_t)&FS_CreateDirHierarchy }, - { 0x01D3E370, "FS_FileExists", (size_t)&FS_FileExists }, - { 0x01D3E390, "FS_IsDirectory", (size_t)&FS_IsDirectory }, // NOXREF - { 0x01D3E3B0, "FS_Open", (size_t)&FS_Open }, - { 0x01D3E3D0, "FS_OpenPathID", (size_t)&FS_OpenPathID }, - { 0x01D3E3F0, "FS_Close", (size_t)&FS_Close }, - { 0x01D3E410, "FS_Seek", (size_t)&FS_Seek }, - { 0x01D3E430, "FS_Tell", (size_t)&FS_Tell }, - { 0x01D3E450, "FS_Size", (size_t)&FS_Size }, - { 0x01D3E470, "FS_FileSize", (size_t)&FS_FileSize }, - { 0x01D3E490, "FS_GetFileTime", (size_t)&FS_GetFileTime }, - { 0x01D3E4B0, "FS_FileTimeToString", (size_t)&FS_FileTimeToString }, // NOXREF - { 0x01D3E4D0, "FS_IsOk", (size_t)&FS_IsOk }, - { 0x01D3E4F0, "FS_Flush", (size_t)&FS_Flush }, - { 0x01D3E510, "FS_EndOfFile", (size_t)&FS_EndOfFile }, - { 0x01D3E530, "FS_Read", (size_t)&FS_Read }, - { 0x01D3E550, "FS_Write", (size_t)&FS_Write }, - { 0x01D3E570, "FS_ReadLine", (size_t)&FS_ReadLine }, - { 0x01D3E590, "FS_FPrintf", (size_t)&FS_FPrintf }, - { 0x01D3E5E0, "FS_FindFirst", (size_t)&FS_FindFirst }, - { 0x01D3E600, "FS_FindNext", (size_t)&FS_FindNext }, - { 0x01D3E620, "FS_FindIsDirectory", (size_t)&FS_FindIsDirectory }, // NOXREF - { 0x01D3E640, "FS_FindClose", (size_t)&FS_FindClose }, - { 0x01D3E660, "FS_GetLocalCopy", (size_t)&FS_GetLocalCopy }, - { 0x01D3E680, "FS_GetLocalPath", (size_t)&FS_GetLocalPath }, - { 0x01D3E6A0, "FS_ParseFile", (size_t)&FS_ParseFile }, // NOXREF - { 0x01D3E6E0, "FS_FullPathToRelativePath", (size_t)&FS_FullPathToRelativePath }, // NOXREF - { 0x01D3E700, "FS_GetCurrentDirectory", (size_t)&FS_GetCurrentDirectory }, // NOXREF - { 0x01D3E720, "FS_PrintOpenedFiles", (size_t)&FS_PrintOpenedFiles }, // NOXREF - { 0x01D3E730, "FS_SetWarningFunc", (size_t)&FS_SetWarningFunc }, // NOXREF - { 0x01D3E750, "FS_SetWarningLevel", (size_t)&FS_SetWarningLevel }, // NOXREF - { 0x01D3E770, "FS_GetCharacter", (size_t)&FS_GetCharacter }, // NOXREF - { 0x01D3E790, "FS_LogLevelLoadStarted", (size_t)&FS_LogLevelLoadStarted }, - { 0x01D3E7B0, "FS_LogLevelLoadFinished", (size_t)&FS_LogLevelLoadFinished }, - { 0x01D3E7D0, "FS_SetVBuf", (size_t)&FS_SetVBuf }, - { 0x01D3E800, "FS_GetInterfaceVersion", (size_t)&FS_GetInterfaceVersion }, - { 0x01D3E820, "FS_GetReadBuffer", (size_t)&FS_GetReadBuffer }, - { 0x01D3E840, "FS_ReleaseReadBuffer", (size_t)&FS_ReleaseReadBuffer }, - { 0x01D3E860, "FS_Unlink", (size_t)&FS_Unlink }, - { 0x01D3E8A0, "FS_Rename", (size_t)&FS_Rename }, - { 0x01D3E940, "FS_LoadLibrary", (size_t)&FS_LoadLibrary }, - -#endif // FileSystem_Internal_region - -#ifndef FileSystem_region - - { 0x01D3D340, "GetBaseDirectory", (size_t)&GetBaseDirectory }, - { 0x01D3D355, "_Z20GetFileSystemFactoryv", (size_t)&GetFileSystemFactory }, // NOXREF - //{ 0x01D3E250, "FileSystem_LoadDLL", (size_t)&FileSystem_LoadDLL }, // Totally not exists on Linux (it is inlined), but present and used on Windows, anyway just commented it out - //{ 0x01D3E2C0, "FileSystem_UnloadDLL", (size_t)&FileSystem_UnloadDLL }, // Totally not exists on Linux (it is inlined), but present and used on Windows, anyway just commented it out - { 0x01D3D360, "BEnabledHDAddon", (size_t)&BEnabledHDAddon }, - { 0x01D3D390, "BEnableAddonsFolder", (size_t)&BEnableAddonsFolder }, - - { 0x01D3D3C0, "Host_SetHDModels_f", (size_t)&Host_SetHDModels_f }, - { 0x01D3D440, "Host_SetAddonsFolder_f", (size_t)&Host_SetAddonsFolder_f }, - { 0x01D3D4C0, "Host_SetVideoLevel_f", (size_t)&Host_SetVideoLevel_f }, - { 0x01D3D510, "Host_GetVideoLevel", (size_t)&Host_GetVideoLevel }, - - { 0x01D3D530, "_Z26CheckLiblistForFallbackDirPKcbS0_b", (size_t)&CheckLiblistForFallbackDir }, - { 0x01D3DA60, "FileSystem_SetGameDirectory", (size_t)&FileSystem_SetGameDirectory }, - { 0x01D3E130, "FileSystem_AddFallbackGameDir", (size_t)&FileSystem_AddFallbackGameDir }, - { 0x01D3E200, "_Z15FileSystem_InitPcPv", (size_t)&FileSystem_Init }, - { 0x01D3E2B0, "_Z19FileSystem_Shutdownv", (size_t)&FileSystem_Shutdown }, - -#endif // FileSystem_region - -#ifndef Unicode_StrTools_region - - { 0x01DA8F00, "_Z16Q_IsValidUChar32w", (size_t)&Q_IsValidUChar32 }, - { 0x01DA97D0, "_Z15Q_UTF8ToUChar32PKcRwRb", (size_t)&Q_UTF8ToUChar32 }, - { 0x01DA9910, "Q_UnicodeValidate", (size_t)&Q_UnicodeValidate }, - { 0x01DA99A0, "Q_UnicodeAdvance", (size_t)&Q_UnicodeAdvance }, - { 0x01DA9EA0, "Q_UnicodeRepair", (size_t)&Q_UnicodeRepair }, - { 0x01DA9E70, "V_UTF8ToUChar32", (size_t)&V_UTF8ToUChar32 }, - -#endif // Unicode_StrTools_region - -#ifndef Cmd_region - - { 0x01D26CD0, "Cmd_Wait_f", (size_t)&Cmd_Wait_f }, - { 0x01D26CE0, "Cbuf_Init", (size_t)&Cbuf_Init }, - { 0x01D26D00, "Cbuf_AddText", (size_t)&Cbuf_AddText }, - { 0x01D26D50, "Cbuf_InsertText", (size_t)&Cbuf_InsertText }, - { 0x01D26DE0, "Cbuf_InsertTextLines", (size_t)&Cbuf_InsertTextLines }, - { 0x01D26E80, "Cbuf_Execute", (size_t)&Cbuf_Execute }, - { 0x01D26F60, "Cmd_StuffCmds_f", (size_t)&Cmd_StuffCmds_f }, - { 0x01D270F0, "Cmd_Exec_f", (size_t)&Cmd_Exec_f }, - { 0x01D273A0, "Cmd_Echo_f", (size_t)&Cmd_Echo_f }, - { 0x01D273E0, "CopyString", (size_t)&CopyString }, - { 0x01D27410, "Cmd_Alias_f", (size_t)&Cmd_Alias_f }, - { 0x01D276A0, "Cmd_GetFirstCmd", (size_t)&Cmd_GetFirstCmd }, - { 0x01D276B0, "Cmd_Init", (size_t)&Cmd_Init }, - { 0x01D27720, "Cmd_Shutdown", (size_t)&Cmd_Shutdown }, - { 0x01D27750, "Cmd_Argc", (size_t)&Cmd_Argc }, - { 0x01D27760, "Cmd_Argv", (size_t)&Cmd_Argv }, - { 0x01D27790, "Cmd_Args", (size_t)&Cmd_Args }, - { 0x01D277A0, "Cmd_TokenizeString", (size_t)&Cmd_TokenizeString }, - { 0x01D27880, "Cmd_FindCmd", (size_t)&Cmd_FindCmd }, // NOXREF - { 0x01D278C0, "Cmd_FindCmdPrev", (size_t)&Cmd_FindCmdPrev }, // NOXREF - { 0x01D27900, "Cmd_AddCommand", (size_t)&Cmd_AddCommand }, - { 0x01D27A10, "Cmd_AddMallocCommand", (size_t)&Cmd_AddMallocCommand }, - { 0x01D27AB0, "Cmd_AddHUDCommand", (size_t)&Cmd_AddHUDCommand }, // NOXREF - { 0x01D27AD0, "Cmd_AddWrapperCommand", (size_t)&Cmd_AddWrapperCommand }, // NOXREF - { 0x01D27AF0, "Cmd_AddGameCommand", (size_t)&Cmd_AddGameCommand }, - { 0x01D27B10, "Cmd_RemoveMallocedCmds", (size_t)&Cmd_RemoveMallocedCmds }, - { 0x01D27B50, "Cmd_RemoveHudCmds", (size_t)&Cmd_RemoveHudCmds }, // NOXREF - { 0x01D27B60, "Cmd_RemoveGameCmds", (size_t)&Cmd_RemoveGameCmds }, - { 0x01D27B70, "Cmd_RemoveWrapperCmds", (size_t)&Cmd_RemoveWrapperCmds }, - { 0x01D27B80, "Cmd_Exists", (size_t)&Cmd_Exists }, - { 0x01D27BC0, "Cmd_CompleteCommand", (size_t)&Cmd_CompleteCommand }, // NOXREF - { 0x01D27D10, "Cmd_ExecuteString", (size_t)&Cmd_ExecuteString }, - { 0x01D27DF0, "Cmd_ForwardToServerInternal", (size_t)&Cmd_ForwardToServerInternal }, - { 0x01D27F40, "Cmd_ForwardToServer", (size_t)&Cmd_ForwardToServer }, - { 0x01D27F90, "Cmd_ForwardToServerUnreliable", (size_t)&Cmd_ForwardToServerUnreliable }, - { 0x01D27FA0, "Cmd_CheckParm", (size_t)&Cmd_CheckParm }, // NOXREF - { 0x01D28000, "Cmd_CmdList_f", (size_t)&Cmd_CmdList_f }, - -#endif // Cmd_region - -#ifndef Cvar_region - - { 0x01D2D760, "Cvar_Init", (size_t)&Cvar_Init }, - { 0x01D2D770, "Cvar_Shutdown", (size_t)&Cvar_Shutdown }, - { 0x01D2D780, "Cvar_FindVar", (size_t)&Cvar_FindVar }, - { 0x01D2D7C0, "Cvar_FindPrevVar", (size_t)&Cvar_FindPrevVar }, // NOXREF - { 0x01D2D800, "Cvar_VariableValue", (size_t)&Cvar_VariableValue }, - { 0x01D2D830, "Cvar_VariableInt", (size_t)&Cvar_VariableInt }, // NOXREF - { 0x01D2D860, "Cvar_VariableString", (size_t)&Cvar_VariableString }, - { 0x01D2D880, "Cvar_CompleteVariable", (size_t)&Cvar_CompleteVariable }, // NOXREF - { 0x01D2D9C0, "Cvar_DirectSet", (size_t)&Cvar_DirectSet }, - { 0x01D2DC30, "Cvar_Set", (size_t)&Cvar_Set }, - { 0x01D2DC70, "Cvar_SetValue", (size_t)&Cvar_SetValue }, - { 0x01D2DD20, "Cvar_RegisterVariable", (size_t)&Cvar_RegisterVariable }, - { 0x01D2DE10, "Cvar_RemoveHudCvars", (size_t)&Cvar_RemoveHudCvars }, // NOXREF - { 0x01D2DE70, "Cvar_IsMultipleTokens", (size_t)&Cvar_IsMultipleTokens }, - { 0x01D2DED0, "Cvar_Command", (size_t)&Cvar_Command }, - { 0x01D2DFA0, "Cvar_WriteVariables", (size_t)&Cvar_WriteVariables }, // NOXREF - { 0x01D2DFE0, "Cmd_CvarListPrintCvar", (size_t)&Cmd_CvarListPrintCvar }, - { 0x01D2E0F0, "Cmd_CvarList_f", (size_t)&Cmd_CvarList_f }, - { 0x01D2E330, "Cvar_CountServerVariables", (size_t)&Cvar_CountServerVariables }, // NOXREF - { 0x01D2E350, "Cvar_UnlinkExternals", (size_t)&Cvar_UnlinkExternals }, - { 0x01D2E380, "Cvar_CmdInit", (size_t)&Cvar_CmdInit }, - -#endif // Cvar_region - -#ifndef Info_region - - { 0x01D4B610, "Info_ValueForKey", (size_t)&Info_ValueForKey }, - { 0x01D4B6E0, "Info_RemoveKey", (size_t)&Info_RemoveKey }, - { 0x01D4B7D0, "Info_RemovePrefixedKeys", (size_t)&Info_RemovePrefixedKeys }, - { 0x01D4B860, "Info_IsKeyImportant", (size_t)&Info_IsKeyImportant }, - { 0x01D4B980, "Info_FindLargestKey", (size_t)&Info_FindLargestKey }, - { 0x01D4BA80, "Info_SetValueForStarKey", (size_t)&Info_SetValueForStarKey }, - { 0x01D4BCF0, "Info_SetValueForKey", (size_t)&Info_SetValueForKey }, - { 0x01D4BD30, "Info_Print", (size_t)&Info_Print }, - { 0x01D4BE10, "Info_IsValid", (size_t)&Info_IsValid }, - -#endif // Info_region - -#ifndef SysDll_region - - //{ 0x, "Sys_PageIn", (size_t)&Sys_PageIn }, -// { 0x01D9ECF0, "Sys_FindFirst", (size_t)&Sys_FindFirst }, -// { 0x01D9ED50, "Sys_FindFirstPathID", (size_t)&Sys_FindFirstPathID }, -// { 0x01D9ED90, "Sys_FindNext", (size_t)&Sys_FindNext }, -// { 0x01D9EDC0, "Sys_FindClose", (size_t)&Sys_FindClose }, - //{ 0x01D9EDE0, "glob_match_after_star", (size_t)&glob_match_after_star }, - //{ 0x01D9EF50, "glob_match", (size_t)&glob_match }, - //{ 0x01D9EFD0, "Sys_MakeCodeWriteable", (size_t)&Sys_MakeCodeWriteable }, - //{ 0x, "Sys_SetFPCW", (size_t)&Sys_SetFPCW }, - //{ 0x, "Sys_PushFPCW_SetHigh", (size_t)&Sys_PushFPCW_SetHigh }, - //{ 0x, "Sys_PopFPCW", (size_t)&Sys_PopFPCW }, - //{ 0x, "MaskExceptions", (size_t)&MaskExceptions }, - //{ 0x, "Sys_Init", (size_t)&Sys_Init }, // NOXREF - //{ 0x, "Sys_Sleep", (size_t)&Sys_Sleep }, - //{ 0x, "Sys_DebugOutStraight", (size_t)&Sys_DebugOutStraight }, - //{ 0x01D9F0E0, "Sys_Error", (size_t)&Sys_Error }, - //{ 0x01D9F1F0, "Sys_Warning", (size_t)&Sys_Warning }, -// { 0x01D9F230, "Sys_Printf", (size_t)&Sys_Printf }, -// { 0x01D9F4A0, "Sys_Quit", (size_t)&Sys_Quit }, - { 0x01D9F2A0, "Sys_FloatTime", (size_t)&Sys_FloatTime }, -// { 0x01D9F460, "Dispatch_Substate", (size_t)&Dispatch_Substate }, -// { 0x01D9F470, "GameSetSubState", (size_t)&GameSetSubState }, -// { 0x01D9F4A0, "GameSetState", (size_t)&GameSetState }, - //{ 0x, "GameSetBackground", (size_t)&GameSetBackground }, -// { 0x01D9F7B0, "Voice_GetClientListening", (size_t)&Voice_GetClientListening }, -// { 0x01D9F810, "Voice_SetClientListening", (size_t)&Voice_SetClientListening }, -// { 0x01D9F890, "GetDispatch", (size_t)&GetDispatch }, -// { 0x01D9F8D0, "FindAddressInTable", (size_t)&FindAddressInTable }, -// { 0x01D9F910, "FindNameInTable", (size_t)&FindNameInTable }, - //{ 0x, "ConvertNameToLocalPlatform", (size_t)&ConvertNameToLocalPlatform }, -// { 0x01D9FAA0, "FunctionFromName", (size_t)&FunctionFromName }, -// { 0x01D9FB00, "NameForFunction", (size_t)&NameForFunction }, -// { 0x01D9FB50, "GetEntityInit", (size_t)&GetEntityInit }, -// { 0x01D9FB70, "GetIOFunction", (size_t)&GetIOFunction }, -// { 0x01D9FB90, "DLL_SetModKey", (size_t)&DLL_SetModKey }, -// { 0x01D9FE50, "LoadEntityDLLs", (size_t)&LoadEntityDLLs }, -// { 0x01DA02D0, "LoadThisDll", (size_t)&LoadThisDll }, -// { 0x01DA0390, "ReleaseEntityDlls", (size_t)&ReleaseEntityDlls }, - //{ 0x01DA0410, "EngineFprintf", (size_t)&EngineFprintf }, -// { 0x01DA0420, "AlertMessage", (size_t)&AlertMessage }, - //{ 0x01DA0640, "Sys_SplitPath", (size_t)&Sys_SplitPath }, -// { 0x01D2BD90, "Con_Debug_f", (size_t)&Con_Debug_f }, -// { 0x01D2BDD0, "Con_Init", (size_t)&Con_Init }, -// { 0x01D2BFC0, "Con_DebugLog", (size_t)&Con_DebugLog }, -// { 0x01D2C020, "Con_Printf", (size_t)&Con_Printf }, -// { 0x01D2C1E0, "Con_SafePrintf", (size_t)&Con_SafePrintf }, -// { 0x01D2C140, "Con_DPrintf", (size_t)&Con_DPrintf }, - -#ifdef _WIN32 - { 0x01DA0A70, "Sys_InitHardwareTimer", (size_t)&Sys_InitHardwareTimer }, -#endif //_WIN32 - -#endif // SysDll_region - -#ifndef Sys_Dll2_region - - { 0x01DA0670, "GetCurrentSteamAppName", (size_t)&GetCurrentSteamAppName }, - //{ 0x01DA0760, "SetRateRegistrySetting", (size_t)&SetRateRegistrySetting }, // NOXREF - //{ 0x01DA0780, "GetRateRegistrySetting", (size_t)&GetRateRegistrySetting }, // NOXREF - { 0x01DA07A0, "F", (size_t)&F }, - { 0x01DA0820, "Sys_GetCDKey", (size_t)&Sys_GetCDKey }, - //{ 0x01DA0930, "_Z19Legacy_ErrorMessageiPKc", (size_t)&Legacy_ErrorMessage }, // NOXREF - { 0x01DA0940, "_Z17Legacy_Sys_PrintfPcz", (size_t)&Legacy_Sys_Printf }, - //{ 0x01DA0980, "_Z30Legacy_MP3subsys_Suspend_Audiov", (size_t)&Legacy_MP3subsys_Suspend_Audio }, // NOXREF - //{ 0x01DA0990, "_Z29Legacy_MP3subsys_Resume_Audiov", (size_t)&Legacy_MP3subsys_Resume_Audio }, // NOXREF -#ifndef _WIN32 - { 0x0, "_Z19Sys_SetupLegacyAPIsv", (size_t)&Sys_SetupLegacyAPIs }, -#endif - //{ 0x01DA09C0, "_Z11Sys_IsWin95v", (size_t)&Sys_IsWin95 }, // NOXREF - //{ 0x01DA09D0, "_Z11Sys_IsWin98v", (size_t)&Sys_IsWin98 }, // NOXREF -#ifdef _WIN32 - { 0x01DA09E0, "_Z18Sys_CheckOSVersionv", (size_t)&Sys_CheckOSVersion }, -#endif - //{ 0x, "Sys_Init", (size_t)&Sys_Init }, // NOXREF - //{ 0x, "Sys_Shutdown", (size_t)&Sys_Shutdown }, // NOXREF - { 0x01DA0B70, "_Z12Sys_InitArgvPc", (size_t)&Sys_InitArgv }, - //{ 0x, "Sys_ShutdownArgv", (size_t)&Sys_ShutdownArgv }, // NOXREF - { 0x01DA0C20, "_Z14Sys_InitMemoryv", (size_t)&Sys_InitMemory }, - { 0x01DA0D50, "Sys_ShutdownMemory", (size_t)&Sys_ShutdownMemory }, - { 0x01DA0D70, "_Z25Sys_InitLauncherInterfacev", (size_t)&Sys_InitLauncherInterface }, - //{ 0x, "Sys_ShutdownLauncherInterface", (size_t)&Sys_ShutdownLauncherInterface }, // NOXREF - { 0x01DA0DA0, "_Z22Sys_InitAuthenticationv", (size_t)&Sys_InitAuthentication }, - //{ 0x, "Sys_ShutdownAuthentication", (size_t)&Sys_ShutdownAuthentication }, // NOXREF - { 0x01DA0DC0, "_Z21Sys_ShowProgressTicksPc", (size_t)&Sys_ShowProgressTicks }, - { 0x01DA0ED0, "_Z12Sys_InitGamePcS_Pvi", (size_t)&Sys_InitGame }, - { 0x01DA0FE0, "_Z16Sys_ShutdownGamev", (size_t)&Sys_ShutdownGame }, - { 0x01DA1060, "_Z13ClearIOStatesv", (size_t)&ClearIOStates }, - //{ 0x01DA13E0, "_Z22BuildMapCycleListHintsPPc", (size_t)&BuildMapCycleListHints }, // NOXREF - - { 0x01DA16B0, "_ZN19CDedicatedServerAPI4InitEPcS0_PFP14IBaseInterfacePKcPiES7_", mfunc_ptr_cast(&CDedicatedServerAPI::Init_noVirt) }, - { 0x01DA1800, "_ZN19CDedicatedServerAPI8ShutdownEv", mfunc_ptr_cast(&CDedicatedServerAPI::Shutdown_noVirt) }, - { 0x01DA1860, "_ZN19CDedicatedServerAPI8RunFrameEv", mfunc_ptr_cast(&CDedicatedServerAPI::RunFrame_noVirt) }, - { 0x01DA1880, "_ZN19CDedicatedServerAPI14AddConsoleTextEPc", mfunc_ptr_cast(&CDedicatedServerAPI::AddConsoleText_noVirt) }, - { 0x01DA18A0, "_ZN19CDedicatedServerAPI12UpdateStatusEPfPiS1_Pc", mfunc_ptr_cast(&CDedicatedServerAPI::UpdateStatus_noVirt) }, - -#endif // Sys_Dll2_region - -#ifndef CModel_region - - { 0x01D281B0, "Mod_Init", (size_t)&Mod_Init }, - { 0x01D281D0, "Mod_DecompressVis", (size_t)&Mod_DecompressVis }, - { 0x01D28210, "Mod_LeafPVS", (size_t)&Mod_LeafPVS }, - { 0x01D28270, "CM_DecompressPVS", (size_t)&CM_DecompressPVS }, - { 0x01D282E0, "CM_LeafPVS", (size_t)&CM_LeafPVS }, - { 0x01D28310, "CM_LeafPAS", (size_t)&CM_LeafPAS }, - { 0x01D28340, "CM_FreePAS", (size_t)&CM_FreePAS }, - { 0x01D28380, "CM_CalcPAS", (size_t)&CM_CalcPAS }, - { 0x01D28580, "CM_HeadnodeVisible", (size_t)&CM_HeadnodeVisible }, - -#endif // CModel_region - -#ifndef Model_region - - { 0x01D50B80, "SW_Mod_Init", (size_t)&SW_Mod_Init }, - { 0x01D50B90, "Mod_Extradata", (size_t)&Mod_Extradata }, - { 0x01D50BF0, "Mod_PointInLeaf", (size_t)&Mod_PointInLeaf }, - { 0x01D50C80, "Mod_ClearAll", (size_t)&Mod_ClearAll }, - { 0x01D50CC0, "Mod_FillInCRCInfo", (size_t)&Mod_FillInCRCInfo }, - { 0x01D50CE0, "Mod_FindName", (size_t)&Mod_FindName }, - //{ 0x01D50DF0, "Mod_ValidateCRC", (size_t)&Mod_ValidateCRC }, // NOXREF - //{ 0x01D50E50, "Mod_NeedCRC", (size_t)&Mod_NeedCRC }, // NOXREF - { 0x01D50E90, "Mod_LoadModel", (size_t)&Mod_LoadModel }, - //{ 0x01D51100, "Mod_MarkClient", (size_t)&Mod_MarkClient }, // NOXREF - { 0x01D51110, "Mod_ForName", (size_t)&Mod_ForName }, - { 0x01D51150, "Mod_AdInit", (size_t)&Mod_AdInit }, - { 0x01D511F0, "Mod_AdSwap", (size_t)&Mod_AdSwap }, - { 0x01D51280, "Mod_LoadTextures", (size_t)&Mod_LoadTextures }, - { 0x01D517C0, "Mod_LoadLighting", (size_t)&Mod_LoadLighting }, - { 0x01D51810, "Mod_LoadVisibility", (size_t)&Mod_LoadVisibility }, - { 0x01D51860, "Mod_LoadEntities", (size_t)&Mod_LoadEntities }, - { 0x01D51930, "Mod_LoadVertexes", (size_t)&Mod_LoadVertexes }, - { 0x01D519E0, "Mod_LoadSubmodels", (size_t)&Mod_LoadSubmodels }, - { 0x01D51B10, "Mod_LoadEdges", (size_t)&Mod_LoadEdges }, - { 0x01D51BA0, "Mod_LoadTexinfo", (size_t)&Mod_LoadTexinfo }, - { 0x01D51D60, "CalcSurfaceExtents", (size_t)&CalcSurfaceExtents }, - { 0x01D51F10, "Mod_LoadFaces", (size_t)&Mod_LoadFaces }, - { 0x01D52140, "Mod_SetParent", (size_t)&Mod_SetParent }, - { 0x01D52180, "Mod_LoadNodes", (size_t)&Mod_LoadNodes }, - { 0x01D52330, "Mod_LoadLeafs", (size_t)&Mod_LoadLeafs }, - { 0x01D52490, "Mod_LoadClipnodes", (size_t)&Mod_LoadClipnodes }, - { 0x01D52630, "Mod_MakeHull0", (size_t)&Mod_MakeHull0 }, - { 0x01D52720, "Mod_LoadMarksurfaces", (size_t)&Mod_LoadMarksurfaces }, - { 0x01D527E0, "Mod_LoadSurfedges", (size_t)&Mod_LoadSurfedges }, - { 0x01D52860, "Mod_LoadPlanes", (size_t)&Mod_LoadPlanes }, - { 0x01D52970, "RadiusFromBounds", (size_t)&RadiusFromBounds }, - { 0x01D52A00, "Mod_LoadBrushModel", (size_t)&Mod_LoadBrushModel }, - //{ 0x01D52C30, "Mod_LoadAliasFrame", (size_t)&Mod_LoadAliasFrame }, - //{ 0x01D52CE0, "Mod_LoadAliasGroup", (size_t)&Mod_LoadAliasGroup }, - //{ 0x01D52DF0, "Mod_LoadAliasSkin", (size_t)&Mod_LoadAliasSkin }, - //{ 0x01D52E60, "Mod_LoadAliasSkinGroup", (size_t)&Mod_LoadAliasSkinGroup }, - //{ 0x01D52F40, "Mod_LoadAliasModel", (size_t)&Mod_LoadAliasModel }, - { 0x01D53410, "Mod_LoadSpriteFrame", (size_t)&Mod_LoadSpriteFrame }, - { 0x01D53510, "Mod_LoadSpriteGroup", (size_t)&Mod_LoadSpriteGroup }, - { 0x01D535E0, "Mod_LoadSpriteModel", (size_t)&Mod_LoadSpriteModel }, - //{ 0x01D53800, "Mod_UnloadSpriteTextures", (size_t)&Mod_UnloadSpriteTextures }, - { 0x01D53820, "Mod_Print", (size_t)&Mod_Print }, - //{ 0x01D538A0, "Mod_ChangeGame", (size_t)&Mod_ChangeGame }, - -#endif // Model_region - -#ifndef Sv_Log_region - - { 0x01D873D0, "Log_Printf", (size_t)&Log_Printf }, - { 0x01D875A0, "Log_PrintServerVars", (size_t)&Log_PrintServerVars }, - { 0x01D87600, "Log_Close", (size_t)&Log_Close }, - { 0x01D87630, "Log_Open", (size_t)&Log_Open }, - { 0x01D87850, "SV_SetLogAddress_f", (size_t)&SV_SetLogAddress_f }, - { 0x01D87990, "SV_AddLogAddress_f", (size_t)&SV_AddLogAddress_f }, - { 0x01D87BC0, "SV_DelLogAddress_f", (size_t)&SV_DelLogAddress_f }, - -#endif // Sv_Log_region - -#ifndef Cl_Null_region - - //{ 0x, "CL_RecordHUDCommand", (size_t)&CL_RecordHUDCommand }, - //{ 0x, "R_DecalRemoveAll", (size_t)&R_DecalRemoveAll }, - //{ 0x, "CL_CheckForResend", (size_t)&CL_CheckForResend }, - //{ 0x, "CL_CheckFile", (size_t)&CL_CheckFile }, - //{ 0x01D17350, "CL_ClearClientState", (size_t)&CL_ClearClientState }, - //{ 0x, "CL_Connect_f", (size_t)&CL_Connect_f }, - //{ 0x, "CL_DecayLights", (size_t)&CL_DecayLights }, - //{ 0x01D17490, "CL_Disconnect", (size_t)&CL_Disconnect }, - //{ 0x01D17660, "CL_Disconnect_f", (size_t)&CL_Disconnect_f }, - //{ 0x, "CL_EmitEntities", (size_t)&CL_EmitEntities }, - //{ 0x, "CL_InitClosest", (size_t)&CL_InitClosest }, - //{ 0x, "CL_Init", (size_t)&CL_Init }, - { 0x01D131E0, "CL_Particle", (size_t)&CL_Particle }, - //{ 0x, "CL_PredictMove", (size_t)&CL_PredictMove }, - //{ 0x, "CL_PrintLogos", (size_t)&CL_PrintLogos }, - //{ 0x, "CL_ReadPackets", (size_t)&CL_ReadPackets }, - //{ 0x, "CL_RequestMissingResources", (size_t)&CL_RequestMissingResources }, - //{ 0x, "CL_Move", (size_t)&CL_Move }, - //{ 0x, "CL_SendConnectPacket", (size_t)&CL_SendConnectPacket }, - //{ 0x01D0FABD, "CL_StopPlayback", (size_t)&CL_StopPlayback }, - //{ 0x, "CL_UpdateSoundFade", (size_t)&CL_UpdateSoundFade }, - //{ 0x, "CL_AdjustClock", (size_t)&CL_AdjustClock }, - //{ 0x01D48910, "CL_Save", (size_t)&CL_Save }, - //{ 0x01D19650, "CL_HudMessage", (size_t)&CL_HudMessage }, - - //{ 0x, "Key_WriteBindings", (size_t)&Key_WriteBindings }, - //{ 0x, "ClientDLL_UpdateClientData", (size_t)&ClientDLL_UpdateClientData }, - //{ 0x, "ClientDLL_HudVidInit", (size_t)&ClientDLL_HudVidInit }, - //{ 0x, "Chase_Init", (size_t)&Chase_Init }, - //{ 0x, "Key_Init", (size_t)&Key_Init }, - //{ 0x, "ClientDLL_Init", (size_t)&ClientDLL_Init }, - //{ 0x, "Con_Shutdown", (size_t)&Con_Shutdown }, - //{ 0x, "DispatchDirectUserMsg", (size_t)&DispatchDirectUserMsg }, - //{ 0x, "CL_ShutDownUsrMessages", (size_t)&CL_ShutDownUsrMessages }, - //{ 0x, "CL_ShutDownClientStatic", (size_t)&CL_ShutDownClientStatic }, - - //{ 0x, "ClientDLL_MoveClient", (size_t)&ClientDLL_MoveClient }, - - //{ 0x, "CL_Shutdown", (size_t)&CL_Shutdown }, - - //{ 0x, "ClientDLL_Frame", (size_t)&ClientDLL_Frame }, - //{ 0x, "ClientDLL_CAM_Think", (size_t)&ClientDLL_CAM_Think }, - //{ 0x, "CL_InitEventSystem", (size_t)&CL_InitEventSystem }, - //{ 0x, "CL_CheckClientState", (size_t)&CL_CheckClientState }, - //{ 0x, "CL_RedoPrediction", (size_t)&CL_RedoPrediction }, - //{ 0x, "CL_SetLastUpdate", (size_t)&CL_SetLastUpdate }, - - //{ 0x, "Con_NPrintf", (size_t)&Con_NPrintf }, - //{ 0x01D805A0, "Sequence_OnLevelLoad", (size_t)&Sequence_OnLevelLoad }, - //{ 0x01D1CDD0, "CL_WriteMessageHistory", (size_t)&CL_WriteMessageHistory }, - //{ 0x, "CL_MoveSpectatorCamera", (size_t)&CL_MoveSpectatorCamera }, - //{ 0x, "CL_AddVoiceToDatagram", (size_t)&CL_AddVoiceToDatagram }, - //{ 0x, "CL_VoiceIdle", (size_t)&CL_VoiceIdle }, - //{ 0x, "PollDInputDevices", (size_t)&PollDInputDevices }, - //{ 0x, "CL_KeepConnectionActive", (size_t)&CL_KeepConnectionActive }, - //{ 0x, "CL_UpdateModuleC", (size_t)&CL_UpdateModuleC }, - //{ 0x, "VGuiWrap2_IsInCareerMatch", (size_t)&VGuiWrap2_IsInCareerMatch }, - //{ 0x, "VguiWrap2_GetCareerUI", (size_t)&VguiWrap2_GetCareerUI }, - //{ 0x, "VGuiWrap2_GetLocalizedStringLength", (size_t)&VGuiWrap2_GetLocalizedStringLength }, - //{ 0x01D07630, "VGuiWrap2_LoadingStarted", (size_t)&VGuiWrap2_LoadingStarted }, - - //{ 0x, "ConstructTutorMessageDecayBuffer", (size_t)&ConstructTutorMessageDecayBuffer }, - //{ 0x, "ProcessTutorMessageDecayBuffer", (size_t)&ProcessTutorMessageDecayBuffer }, - //{ 0x, "GetTimesTutorMessageShown", (size_t)&GetTimesTutorMessageShown }, - //{ 0x, "RegisterTutorMessageShown", (size_t)&RegisterTutorMessageShown }, - //{ 0x, "ResetTutorMessageDecayData", (size_t)&ResetTutorMessageDecayData }, - //{ 0x01D83340, "SetCareerAudioState", (size_t)&SetCareerAudioState }, - -#endif // Cl_Null_region - -#ifndef Snd_Null_region - - //{ 0x0, "S_Init", (size_t)&S_Init }, - //{ 0x0, "S_AmbientOff", (size_t)&S_AmbientOff }, - //{ 0x0, "S_AmbientOn", (size_t)&S_AmbientOn }, - //{ 0x0, "S_Shutdown", (size_t)&S_Shutdown }, - //{ 0x0, "S_TouchSound", (size_t)&S_TouchSound }, - //{ 0x0, "S_ClearBuffer", (size_t)&S_ClearBuffer }, - //{ 0x0, "S_StartStaticSound", (size_t)&S_StartStaticSound }, - //{ 0x0, "S_StartDynamicSound", (size_t)&S_StartDynamicSound }, - //{ 0x0, "S_StopSound", (size_t)&S_StopSound }, - //{ 0x0, "S_PrecacheSound", (size_t)&S_PrecacheSound }, - //{ 0x0, "S_ClearPrecache", (size_t)&S_ClearPrecache }, - //{ 0x0, "S_Update", (size_t)&S_Update }, - //{ 0x0, "S_StopAllSounds", (size_t)&S_StopAllSounds }, - //{ 0x0, "S_BeginPrecaching", (size_t)&S_BeginPrecaching }, - //{ 0x0, "S_EndPrecaching", (size_t)&S_EndPrecaching }, - //{ 0x0, "S_ExtraUpdate", (size_t)&S_ExtraUpdate }, - //{ 0x0, "S_LocalSound", (size_t)&S_LocalSound }, - //{ 0x0, "S_BlockSound", (size_t)&S_BlockSound }, - //{ 0x0, "S_PrintStats", (size_t)&S_PrintStats }, - //{ 0x0, "Voice_RecordStart", (size_t)&Voice_RecordStart }, - //{ 0x0, "Voice_IsRecording", (size_t)&Voice_IsRecording }, - //{ 0x0, "Voice_RegisterCvars", (size_t)&Voice_RegisterCvars }, - //{ 0x01DB65D0, "Voice_Deinit", (size_t)&Voice_Deinit }, - //{ 0x0, "Voice_Idle", (size_t)&Voice_Idle }, - //{ 0x0, "Voice_RecordStop", (size_t)&Voice_RecordStop }, - -#endif // Snd_Null_region - -#ifndef Sv_Steam3_region - - { 0x01D994C0, "_ZN13CSteam3Server19NotifyClientConnectEP8client_sPKvj", (size_t)*(void **)&pNotifyClientConnect }, - { 0x01D98B20, "_ZN13CSteam3Server14OnLogonFailureEP27SteamServerConnectFailure_t", mfunc_ptr_cast(&CSteam3Server::OnLogonFailure) }, - { 0x01D99A10, "_ZN13CSteam3Server24SendUpdatedServerDetailsEv", mfunc_ptr_cast(&CSteam3Server::SendUpdatedServerDetails) }, - { 0x01D98A70, "_ZN13CSteam3Server14OnLogonSuccessEP23SteamServersConnected_t", mfunc_ptr_cast(&CSteam3Server::OnLogonSuccess) }, - { 0x01D98A40, "_ZN13CSteam3Server18OnGSPolicyResponseEP18GSPolicyResponse_t", mfunc_ptr_cast(&CSteam3Server::OnGSPolicyResponse) }, - { 0x01D98AE0, "_ZN13CSteam3Server10GetSteamIDEv", mfunc_ptr_cast(&CSteam3Server::GetSteamID) }, - { 0x01D98F10, "_ZN13CSteam3Server21ClientFindFromSteamIDER8CSteamID", mfunc_ptr_cast(&CSteam3Server::ClientFindFromSteamID) }, - { 0x01D98DF0, "_ZN13CSteam3Server17OnGSClientApproveEP17GSClientApprove_t", mfunc_ptr_cast(&CSteam3Server::OnGSClientApprove) }, - { 0x01D99660, "_ZN13CSteam3Server22NotifyClientDisconnectEP8client_s", mfunc_ptr_cast(&CSteam3Server::NotifyClientDisconnect) }, - { 0x01D98BC0, "_ZN13CSteam3Server20OnGSClientDenyHelperEP8client_s11EDenyReasonPKc", mfunc_ptr_cast(&CSteam3Server::OnGSClientDenyHelper) }, - { 0x01D98B90, "_ZN13CSteam3Server14OnGSClientDenyEP14GSClientDeny_t", mfunc_ptr_cast(&CSteam3Server::OnGSClientDeny) }, - { 0x01D98DC0, "_ZN13CSteam3Server14OnGSClientKickEP14GSClientKick_t", mfunc_ptr_cast(&CSteam3Server::OnGSClientKick) }, - { 0x01D996B0, "_ZN13CSteam3Server19NotifyOfLevelChangeEb", mfunc_ptr_cast(&CSteam3Server::NotifyOfLevelChange) }, - { 0x01D99110, "_ZN13CSteam3Server8ActivateEv", mfunc_ptr_cast(&CSteam3Server::Activate) }, - { 0x01D99770, "_ZN13CSteam3Server8RunFrameEv", mfunc_ptr_cast(&CSteam3Server::RunFrame) }, - { 0x01D99600, "_ZN13CSteam3Server16NotifyBotConnectEP8client_s", mfunc_ptr_cast(&CSteam3Server::NotifyBotConnect) }, - - { 0x01D99550, "ISteamGameServer_CreateUnauthenticatedUserConnection", (size_t)&ISteamGameServer_CreateUnauthenticatedUserConnection }, - { 0x01D99590, "ISteamGameServer_BUpdateUserData", (size_t)&ISteamGameServer_BUpdateUserData }, - { 0x01D995D0, "ISteamApps_BIsSubscribedApp", (size_t)&ISteamApps_BIsSubscribedApp }, - { 0x01D99AB0, "Steam_GetCommunityName", (size_t)&Steam_GetCommunityName }, - { 0x01D99CA0, "Steam_NotifyClientConnect", (size_t)&Steam_NotifyClientConnect }, - { 0x01D99CD0, "Steam_NotifyBotConnect", (size_t)&Steam_NotifyBotConnect }, - { 0x01D99D00, "Steam_NotifyClientDisconnect", (size_t)&Steam_NotifyClientDisconnect }, - { 0x01D99D20, "Steam_NotifyOfLevelChange", (size_t)&Steam_NotifyOfLevelChange }, - { 0x01D99D40, "Steam_Shutdown", (size_t)&Steam_Shutdown }, - { 0x01D99D70, "Steam_Activate", (size_t)&Steam_Activate }, - { 0x01D99DC0, "Steam_RunFrame", (size_t)&Steam_RunFrame }, - { 0x01D99DE0, "Steam_SetCVar", (size_t)&Steam_SetCVar }, - { 0x01D99E10, "Steam_ClientRunFrame", (size_t)&Steam_ClientRunFrame }, - { 0x01D99E20, "Steam_InitClient", (size_t)&Steam_InitClient }, - { 0x01D99E30, "Steam_GSInitiateGameConnection", (size_t)&Steam_GSInitiateGameConnection }, - { 0x01D99E70, "Steam_GSTerminateGameConnection", (size_t)&Steam_GSTerminateGameConnection }, - { 0x01D99E90, "Steam_ShutdownClient", (size_t)&Steam_ShutdownClient }, - { 0x01D99EA0, "Steam_GSGetSteamID", (size_t)&Steam_GSGetSteamID }, - { 0x01D99EB0, "Steam_GSBSecure", (size_t)&Steam_GSBSecure }, - { 0x01D99ED0, "Steam_GSBLoggedOn", (size_t)&Steam_GSBLoggedOn }, - { 0x01D99F00, "Steam_GSBSecurePreference", (size_t)&Steam_GSBSecurePreference }, - { 0x01D99F10, "Steam_Steam3IDtoSteam2", (size_t)&Steam_Steam3IDtoSteam2 }, - { 0x01D99F50, "Steam_StringToSteamID", (size_t)&Steam_StringToSteamID }, - { 0x01D99FD0, "Steam_GetGSUniverse", (size_t)&Steam_GetGSUniverse }, - { 0x01D9A020, "Steam3Server", (size_t)&Steam3Server }, - { 0x01D9A1D0, "Steam3Client", (size_t)&Steam3Client }, - { 0x01D9A1E0, "Master_SetMaster_f", (size_t)&Master_SetMaster_f }, - { 0x01D9A2D0, "Steam_HandleIncomingPacket", (size_t)&Steam_HandleIncomingPacket }, - -#endif // Sv_Steam3_region - -#ifndef Host_region - - { 0x01D43A00, "Host_EndGame", (size_t)&Host_EndGame }, - { 0x01D43AC0, "Host_Error", (size_t)&Host_Error }, - { 0x01D43BA0, "Host_InitLocal", (size_t)&Host_InitLocal }, - { 0x01D43C90, "Info_WriteVars", (size_t)&Info_WriteVars }, // NOXREF - { 0x01D43D70, "Host_WriteConfiguration", (size_t)&Host_WriteConfiguration }, // NOXREF - { 0x01D43FA0, "Host_WriteCustomConfig", (size_t)&Host_WriteCustomConfig }, - { 0x01D44190, "SV_ClientPrintf", (size_t)&SV_ClientPrintf }, - { 0x01D441F0, "SV_BroadcastPrintf", (size_t)&SV_BroadcastPrintf }, - { 0x01D442A0, "Host_ClientCommands", (size_t)&Host_ClientCommands }, - { 0x01D44310, "SV_DropClient", (size_t)&SV_DropClient }, - { 0x01D44510, "Host_ClearClients", (size_t)&Host_ClearClients }, - { 0x01D446B0, "Host_ShutdownServer", (size_t)&Host_ShutdownServer }, - { 0x01D447F0, "SV_ClearClientStates", (size_t)&SV_ClearClientStates }, - { 0x01D44830, "Host_CheckDyanmicStructures", (size_t)&Host_CheckDyanmicStructures }, - { 0x01D44880, "Host_ClearMemory", (size_t)&Host_ClearMemory }, - { 0x01D44900, "Host_FilterTime", (size_t)&Host_FilterTime }, - { 0x01D44B50, "Master_IsLanGame", (size_t)&Master_IsLanGame }, - { 0x01D44B70, "Master_Heartbeat_f", (size_t)&Master_Heartbeat_f }, - { 0x01D44B80, "Host_ComputeFPS", (size_t)&Host_ComputeFPS }, - { 0x01D44BB0, "Host_GetHostInfo", (size_t)&Host_GetHostInfo }, - { 0x01D44C80, "Host_Speeds", (size_t)&Host_Speeds }, - { 0x01D44DC0, "Host_UpdateScreen", (size_t)&Host_UpdateScreen }, - { 0x01D44EB0, "Host_UpdateSounds", (size_t)&Host_UpdateSounds }, - { 0x01D44F30, "Host_CheckConnectionFailure", (size_t)&Host_CheckConnectionFailure }, - { 0x01D44F90, "_Host_Frame", (size_t)&_Host_Frame }, - { 0x01D45150, "Host_Frame", (size_t)&Host_Frame }, - { 0x01D45290, "CheckGore", (size_t)&CheckGore }, - { 0x01D45450, "Host_IsSinglePlayerGame", (size_t)&Host_IsSinglePlayerGame }, - { 0x01D45470, "Host_IsServerActive", (size_t)&Host_IsServerActive }, - { 0x01D45480, "Host_Version", (size_t)&Host_Version }, - { 0x01D456A0, "Host_Init", (size_t)&Host_Init }, - { 0x01D459A0, "Host_Shutdown", (size_t)&Host_Shutdown }, - -#endif // Host_region - -#ifndef Host_Cmd_region - - { 0x01D45AF0, "SV_GetPlayerHulls", (size_t)&SV_GetPlayerHulls }, - { 0x01D45B20, "Host_InitializeGameDLL", (size_t)&Host_InitializeGameDLL }, - { 0x01D45BA0, "Host_Motd_f", (size_t)&Host_Motd_f }, - { 0x01D45D00, "Host_Motd_Write_f", (size_t)&Host_Motd_Write_f }, - { 0x01D45E70, "Host_GetStartTime", (size_t)&Host_GetStartTime }, - { 0x01D45E80, "Host_UpdateStats", (size_t)&Host_UpdateStats }, // UNTESTED Linux - { 0x01D45FB0, "GetStatsString", (size_t)&GetStatsString }, - { 0x01D460B0, "Host_Stats_f", (size_t)&Host_Stats_f }, - { 0x01D460F0, "Host_Quit_f", (size_t)&Host_Quit_f }, - { 0x01D46140, "Host_Quit_Restart_f", (size_t)&Host_Quit_Restart_f }, - { 0x01D46250, "Host_Status_Printf", (size_t)&Host_Status_Printf }, - { 0x01D462F0, "Host_Status_f", (size_t)&Host_Status_f }, - { 0x01D467B0, "Host_Status_Formatted_f", (size_t)&Host_Status_Formatted_f }, - { 0x01D46EC0, "Host_Ping_f", (size_t)&Host_Ping_f }, - { 0x01D46F30, "Host_Map", (size_t)&Host_Map }, - { 0x01D470D0, "Host_Map_f", (size_t)&Host_Map_f }, - { 0x01D473B0, "Host_Career_f", (size_t)&Host_Career_f }, - { 0x01D473D0, "Host_Maps_f", (size_t)&Host_Maps_f }, - { 0x01D47410, "Host_Changelevel_f", (size_t)&Host_Changelevel_f }, - { 0x01D47510, "Host_FindRecentSave", (size_t)&Host_FindRecentSave }, - { 0x01D47600, "Host_Restart_f", (size_t)&Host_Restart_f }, - { 0x01D47690, "Host_Reload_f", (size_t)&Host_Reload_f }, - { 0x01D47710, "Host_Reconnect_f", (size_t)&Host_Reconnect_f }, - { 0x01D477E0, "Host_SaveGameDirectory", (size_t)&Host_SaveGameDirectory }, - { 0x01D47810, "Host_SavegameComment", (size_t)&Host_SavegameComment }, - { 0x01D478B0, "Host_SaveAgeList", (size_t)&Host_SaveAgeList }, - { 0x01D479B0, "Host_ValidSave", (size_t)&Host_ValidSave }, - { 0x01D47A70, "SaveInit", (size_t)&SaveInit }, - { 0x01D47B80, "SaveExit", (size_t)&SaveExit }, - { 0x01D47BC0, "SaveGameSlot", (size_t)&SaveGameSlot }, - { 0x01D47E70, "Host_Savegame_f", (size_t)&Host_Savegame_f }, - { 0x01D47F60, "Host_AutoSave_f", (size_t)&Host_AutoSave_f }, - { 0x01D47FF0, "SaveGame", (size_t)&SaveGame }, - { 0x01D48020, "SaveReadHeader", (size_t)&SaveReadHeader }, - { 0x01D481A0, "SaveReadComment", (size_t)&SaveReadComment }, // NOXREF - { 0x01D481D0, "Host_Loadgame_f", (size_t)&Host_Loadgame_f }, - { 0x01D48220, "LoadGame", (size_t)&LoadGame }, - { 0x01D48250, "Host_Load", (size_t)&Host_Load }, - { 0x01D484C0, "SaveGamestate", (size_t)&SaveGamestate }, - { 0x01D48A00, "EntityInit", (size_t)&EntityInit }, - { 0x01D48A50, "LoadSaveData", (size_t)&LoadSaveData }, - { 0x01D48C70, "ParseSaveTables", (size_t)&ParseSaveTables }, - { 0x01D48DC0, "EntityPatchWrite", (size_t)&EntityPatchWrite }, - { 0x01D48EB0, "EntityPatchRead", (size_t)&EntityPatchRead }, - { 0x01D48F60, "LoadGamestate", (size_t)&LoadGamestate }, - { 0x01D491D0, "EntryInTable", (size_t)&EntryInTable }, - { 0x01D49220, "LandmarkOrigin", (size_t)&LandmarkOrigin }, - { 0x01D49290, "EntityInSolid", (size_t)&EntityInSolid }, - { 0x01D49320, "CreateEntityList", (size_t)&CreateEntityList }, - { 0x01D49570, "LoadAdjacentEntities", (size_t)&LoadAdjacentEntities }, - { 0x01D49730, "FileSize", (size_t)&FileSize }, - { 0x01D49750, "FileCopy", (size_t)&FileCopy }, - { 0x01D497B0, "DirectoryCopy", (size_t)&DirectoryCopy }, - { 0x01D49880, "DirectoryExtract", (size_t)&DirectoryExtract }, - { 0x01D49930, "DirectoryCount", (size_t)&DirectoryCount }, - { 0x01D49970, "Host_ClearSaveDirectory", (size_t)&Host_ClearSaveDirectory }, - { 0x01D49AB0, "Host_ClearGameState", (size_t)&Host_ClearGameState }, - { 0x01D49AD0, "Host_Changelevel2_f", (size_t)&Host_Changelevel2_f }, - { 0x01D49CB0, "Host_Version_f", (size_t)&Host_Version_f }, - { 0x01D49CE0, "Host_FullInfo_f", (size_t)&Host_FullInfo_f }, - { 0x01D49E00, "Host_KillVoice_f", (size_t)&Host_KillVoice_f }, // NOXREF - { 0x01D49E10, "Host_SetInfo_f", (size_t)&Host_SetInfo_f }, - { 0x01D49EB0, "Host_Say", (size_t)&Host_Say }, - { 0x01D4A060, "Host_Say_f", (size_t)&Host_Say_f }, - { 0x01D4A070, "Host_Say_Team_f", (size_t)&Host_Say_Team_f }, - { 0x01D4A080, "Host_Tell_f", (size_t)&Host_Tell_f }, - { 0x01D4A230, "Host_Kill_f", (size_t)&Host_Kill_f }, - { 0x01D4A280, "Host_TogglePause_f", (size_t)&Host_TogglePause_f }, - { 0x01D4A320, "Host_Pause_f", (size_t)&Host_Pause_f }, - { 0x01D4A380, "Host_Unpause_f", (size_t)&Host_Unpause_f }, - { 0x01D4A620, "Host_Interp_f", (size_t)&Host_Interp_f }, - { 0x01D4A650, "Host_NextDemo", (size_t)&Host_NextDemo }, - { 0x01D4A700, "Host_Startdemos_f", (size_t)&Host_Startdemos_f }, - { 0x01D4A7C0, "Host_Demos_f", (size_t)&Host_Demos_f }, - { 0x01D4A7F0, "Host_Stopdemo_f", (size_t)&Host_Stopdemo_f }, - { 0x01D4A810, "Host_EndSection", (size_t)&Host_EndSection }, // NOXREF - { 0x01D4A910, "Host_Soundfade_f", (size_t)&Host_Soundfade_f }, - { 0x01D4AA10, "Host_KillServer_f", (size_t)&Host_KillServer_f }, - { 0x01D4AA50, "Host_VoiceRecordStart_f", (size_t)&Host_VoiceRecordStart_f }, - { 0x01D4AAA0, "Host_VoiceRecordStop_f", (size_t)&Host_VoiceRecordStop_f }, - { 0x01D4AC90, "Host_Crash_f", (size_t)&Host_Crash_f }, // NOXREF - { 0x01D4ACA0, "Host_InitCommands", (size_t)&Host_InitCommands }, - { 0x01D4B060, "SV_CheckBlendingInterface", (size_t)&SV_CheckBlendingInterface }, - { 0x01D4B0D0, "SV_CheckSaveGameCommentInterface", (size_t)&SV_CheckSaveGameCommentInterface }, - -#endif // Host_Cmd_region - -#ifndef Pmove_region - - { 0x01D5B490, "PM_AddToTouched", (size_t)&PM_AddToTouched }, - { 0x01D5B530, "PM_StuckTouch", (size_t)&PM_StuckTouch }, - { 0x01D5B590, "PM_Init", (size_t)&PM_Init }, - -#endif // Pmove_region - -#ifndef Pmovetst_region - - { 0x01D5B8F0, "PM_TraceModel", (size_t)&PM_TraceModel }, - { 0x01D5B990, "PM_GetModelBounds", (size_t)&PM_GetModelBounds }, - { 0x01D5B9C0, "PM_GetModelType", (size_t)&PM_GetModelType }, - { 0x01D5B9D0, "PM_InitBoxHull", (size_t)&PM_InitBoxHull }, - { 0x01D5BA60, "PM_HullForBox", (size_t)&PM_HullForBox }, - { 0x01D5BAB0, "PM_HullPointContents", (size_t)&PM_HullPointContents }, - { 0x01D5BB50, "PM_LinkContents", (size_t)&PM_LinkContents }, - { 0x01D5BC10, "PM_PointContents", (size_t)&PM_PointContents }, - { 0x01D5BCA0, "PM_WaterEntity", (size_t)&PM_WaterEntity }, - { 0x01D5BD10, "PM_TruePointContents", (size_t)&PM_TruePointContents }, - { 0x01D5BD40, "PM_HullForStudioModel", (size_t)&PM_HullForStudioModel }, - { 0x01D5BDF0, "PM_HullForBsp", (size_t)&PM_HullForBsp }, - { 0x01D5BEA0, "_PM_TestPlayerPosition", (size_t)&_PM_TestPlayerPosition }, - { 0x01D5C190, "PM_TestPlayerPosition", (size_t)&PM_TestPlayerPosition }, - { 0x01D5C1B0, "PM_TestPlayerPositionEx", (size_t)&PM_TestPlayerPositionEx }, - { 0x01D5C1D0, "_PM_PlayerTrace", (size_t)&_PM_PlayerTrace }, - { 0x01D5C890, "PM_PlayerTrace", (size_t)&PM_PlayerTrace }, - { 0x01D5C8F0, "PM_PlayerTraceEx", (size_t)&PM_PlayerTraceEx }, - { 0x01D5C9C8, "PM_TraceLine", (size_t)&PM_TraceLine }, - { 0x01D5CA60, "PM_TraceLineEx", (size_t)&PM_TraceLineEx }, - { 0x01D5CB20, "PM_RecursiveHullCheck", (size_t)&PM_RecursiveHullCheck }, - -#endif // Pmovetst_region - -#ifndef Pr_Edict_region - - { 0x01D61510, "ED_ClearEdict", (size_t)&ED_ClearEdict }, - { 0x01D61550, "ED_Alloc", (size_t)&ED_Alloc }, - { 0x01D61610, "ED_Free", (size_t)&ED_Free }, - { 0x01D616D0, "ED_Count", (size_t)&ED_Count }, // NOXREF - { 0x01D61770, "ED_NewString", (size_t)&ED_NewString }, - { 0x01D617D0, "ED_ParseEdict", (size_t)&ED_ParseEdict }, - { 0x01D61A70, "ED_LoadFromFile", (size_t)&ED_LoadFromFile }, - { 0x01D61B80, "PR_Init", (size_t)&PR_Init }, // NOXREF - { 0x01D61B90, "EDICT_NUM", (size_t)&EDICT_NUM }, - { 0x01D61BD0, "NUM_FOR_EDICT", (size_t)&NUM_FOR_EDICT }, - { 0x01D61C10, "SuckOutClassname", (size_t)&SuckOutClassname }, - { 0x01D61CD0, "ReleaseEntityDLLFields", (size_t)&ReleaseEntityDLLFields }, - { 0x01D61CF0, "InitEntityDLLFields", (size_t)&InitEntityDLLFields }, - { 0x01D61D00, "PvAllocEntPrivateData", (size_t)&PvAllocEntPrivateData }, - { 0x01D61D30, "PvEntPrivateData", (size_t)&PvEntPrivateData }, - { 0x01D61D50, "FreeEntPrivateData", (size_t)&FreeEntPrivateData }, - { 0x01D61D90, "FreeAllEntPrivateData", (size_t)&FreeAllEntPrivateData }, - { 0x01D61DD0, "PEntityOfEntOffset", (size_t)&PEntityOfEntOffset }, - { 0x01D61DE0, "EntOffsetOfPEntity", (size_t)&EntOffsetOfPEntity }, - { 0x01D61DF0, "IndexOfEdict", (size_t)&IndexOfEdict }, - { 0x01D61E40, "PEntityOfEntIndex", (size_t)&PEntityOfEntIndex }, - { 0x01D61E80, "SzFromIndex", (size_t)&SzFromIndex }, - { 0x01D61E90, "GetVarsOfEnt", (size_t)&GetVarsOfEnt }, - { 0x01D61EA0, "FindEntityByVars", (size_t)&FindEntityByVars }, - { 0x01D61EE0, "CVarGetFloat", (size_t)&CVarGetFloat }, - { 0x01D61F00, "CVarGetString", (size_t)&CVarGetString }, - { 0x01D61F20, "CVarGetPointer", (size_t)&CVarGetPointer }, - { 0x01D61F40, "CVarSetFloat", (size_t)&CVarSetFloat }, - { 0x01D61F60, "CVarSetString", (size_t)&CVarSetString }, - { 0x01D61F80, "CVarRegister", (size_t)&CVarRegister }, - { 0x01D61FA0, "AllocEngineString", (size_t)&AllocEngineString }, - { 0x01D61FC0, "SaveSpawnParms", (size_t)&SaveSpawnParms }, - { 0x01D61FF0, "GetModelPtr", (size_t)&GetModelPtr }, - -#endif // Pr_Edict_region - -#ifndef Pr_Cmds_region - -// { 0x01D5CF00, "PF_makevectors_I", (size_t)&PF_makevectors_I }, -// { 0x01D5CF20, "PF_Time", (size_t)&PF_Time }, -// { 0x01D5CF40, "PF_setorigin_I", (size_t)&PF_setorigin_I }, -// { 0x01D5CF80, "SetMinMaxSize", (size_t)&SetMinMaxSize }, -// { 0x01D5D030, "PF_setsize_I", (size_t)&PF_setsize_I }, -// { 0x01D5D050, "PF_setmodel_I", (size_t)&PF_setmodel_I }, -// { 0x01D5D0F0, "PF_modelindex", (size_t)&PF_modelindex }, -// { 0x01D5D110, "ModelFrames", (size_t)&ModelFrames }, -// { 0x01D5D150, "PF_bprint", (size_t)&PF_bprint }, -// { 0x01D5D170, "PF_sprint", (size_t)&PF_sprint }, -// { 0x01D5D1D0, "ServerPrint", (size_t)&ServerPrint }, -// { 0x01D5D1F0, "ClientPrintf", (size_t)&ClientPrintf }, -// { 0x01D5D2A0, "PF_vectoyaw_I", (size_t)&PF_vectoyaw_I }, -// { 0x01D5D330, "PF_vectoangles_I", (size_t)&PF_vectoangles_I }, -// { 0x01D5D350, "PF_particle_I", (size_t)&PF_particle_I }, -// { 0x01D5D380, "PF_ambientsound_I", (size_t)&PF_ambientsound_I }, -// { 0x01D5D4C0, "PF_sound_I", (size_t)&PF_sound_I }, -// { 0x01D5D5A0, "PF_traceline_Shared", (size_t)&PF_traceline_Shared }, -// { 0x01D5D600, "PF_traceline_DLL", (size_t)&PF_traceline_DLL }, -// { 0x01D5D6C0, "TraceHull", (size_t)&TraceHull }, -// { 0x01D5D770, "TraceSphere", (size_t)&TraceSphere }, -// { 0x01D5D780, "TraceModel", (size_t)&TraceModel }, -// { 0x01D5D890, "SurfaceAtPoint", (size_t)&SurfaceAtPoint }, -// { 0x01D5DA90, "TraceTexture", (size_t)&TraceTexture }, -// { 0x01D5DCA0, "PF_TraceToss_Shared", (size_t)&PF_TraceToss_Shared }, -// { 0x01D5DCE0, "SV_SetGlobalTrace", (size_t)&SV_SetGlobalTrace }, -// { 0x01D5DD80, "PF_TraceToss_DLL", (size_t)&PF_TraceToss_DLL }, -// { 0x01D5DE40, "TraceMonsterHull", (size_t)&TraceMonsterHull }, -// { 0x01D5DF10, "PF_newcheckclient", (size_t)&PF_newcheckclient }, -// { 0x01D5DFF0, "PF_checkclient_I", (size_t)&PF_checkclient_I }, -// { 0x01D5E110, "PVSNode", (size_t)&PVSNode }, -// { 0x01D5E1D0, "PVSMark", (size_t)&PVSMark }, -// { 0x01D5E250, "PVSFindEntities", (size_t)&PVSFindEntities }, -// { 0x01D5E360, "ValidCmd", (size_t)&ValidCmd }, -// { 0x01D5E390, "PF_stuffcmd_I", (size_t)&PF_stuffcmd_I }, -// { 0x01D5E450, "PF_localcmd_I", (size_t)&PF_localcmd_I }, -// { 0x01D5E480, "PF_localexec_I", (size_t)&PF_localexec_I }, -// { 0x01D5E490, "FindEntityInSphere", (size_t)&FindEntityInSphere }, -// { 0x01D5E5C0, "PF_Spawn_I", (size_t)&PF_Spawn_I }, -// { 0x01D5E5D0, "CreateNamedEntity", (size_t)&CreateNamedEntity }, -// { 0x01D5E640, "PF_Remove_I", (size_t)&PF_Remove_I }, -// { 0x01D5E920, "PF_find_Shared", (size_t)&PF_find_Shared }, -// { 0x01D5E660, "iGetIndex", (size_t)&iGetIndex }, -// { 0x01D5E8C0, "FindEntityByString", (size_t)&FindEntityByString }, -// { 0x01D5E9B0, "GetEntityIllum", (size_t)&GetEntityIllum }, -// { 0x01D5EA50, "PR_IsEmptyString", (size_t)&PR_IsEmptyString }, -// { 0x01D5EA60, "PF_precache_sound_I", (size_t)&PF_precache_sound_I }, -// { 0x01D5EB50, "EV_Precache", (size_t)&EV_Precache }, -// { 0x01D5ECD0, "EV_PlayReliableEvent", (size_t)&EV_PlayReliableEvent }, -// { 0x01D5EE10, "EV_Playback", (size_t)&EV_Playback }, -// { 0x01D5F190, "EV_SV_Playback", (size_t)&EV_SV_Playback }, -// { 0x01D5F210, "PF_precache_model_I", (size_t)&PF_precache_model_I }, -// { 0x01D5F310, "PF_precache_generic_I", (size_t)&PF_precache_generic_I }, -// { 0x01D5F3E0, "PF_IsMapValid_I", (size_t)&PF_IsMapValid_I }, -// { 0x01D5F430, "PF_NumberOfEntities_I", (size_t)&PF_NumberOfEntities_I }, -// { 0x01D5F460, "PF_GetInfoKeyBuffer_I", (size_t)&PF_GetInfoKeyBuffer_I }, -// { 0x01D5F4B0, "PF_InfoKeyValue_I", (size_t)&PF_InfoKeyValue_I }, -// { 0x01D5F4D0, "PF_SetKeyValue_I", (size_t)&PF_SetKeyValue_I }, -// { 0x01D5F530, "PF_RemoveKey_I", (size_t)&PF_RemoveKey_I }, -// { 0x01D5F550, "PF_SetClientKeyValue_I", (size_t)&PF_SetClientKeyValue_I }, -// { 0x01D5F5E0, "PF_walkmove_I", (size_t)&PF_walkmove_I }, -// { 0x01D5F690, "PF_droptofloor_I", (size_t)&PF_droptofloor_I }, -// { 0x01D5F780, "PF_DecalIndex", (size_t)&PF_DecalIndex }, -// { 0x01D5F7D0, "PF_lightstyle_I", (size_t)&PF_lightstyle_I }, -// { 0x01D5F860, "PF_checkbottom_I", (size_t)&PF_checkbottom_I }, -// { 0x01D5F880, "PF_pointcontents_I", (size_t)&PF_pointcontents_I }, -// { 0x01D5F8A0, "PF_aim_I", (size_t)&PF_aim_I }, -// { 0x01D5FB60, "PF_changeyaw_I", (size_t)&PF_changeyaw_I }, -// { 0x01D5FC50, "PF_changepitch_I", (size_t)&PF_changepitch_I }, -// { 0x01D5FD40, "PF_setview_I", (size_t)&PF_setview_I }, -// { 0x01D5FDC0, "PF_crosshairangle_I", (size_t)&PF_crosshairangle_I }, -// { 0x01D5FEC0, "PF_CreateFakeClient_I", (size_t)&PF_CreateFakeClient_I }, -// { 0x01D60070, "PF_RunPlayerMove_I", (size_t)&PF_RunPlayerMove_I }, -// { 0x01D60180, "WriteDest_Parm", (size_t)&WriteDest_Parm }, -// { 0x01D60260, "PF_MessageBegin_I", (size_t)&PF_MessageBegin_I }, -// { 0x01D60350, "PF_MessageEnd_I", (size_t)&PF_MessageEnd_I }, -// { 0x01D605E0, "PF_WriteByte_I", (size_t)&PF_WriteByte_I }, -// { 0x01D60610, "PF_WriteChar_I", (size_t)&PF_WriteChar_I }, -// { 0x01D60640, "PF_WriteShort_I", (size_t)&PF_WriteShort_I }, -// { 0x01D60670, "PF_WriteLong_I", (size_t)&PF_WriteLong_I }, -// { 0x01D606A0, "PF_WriteAngle_I", (size_t)&PF_WriteAngle_I }, -// { 0x01D606D0, "PF_WriteCoord_I", (size_t)&PF_WriteCoord_I }, -// { 0x01D60710, "PF_WriteString_I", (size_t)&PF_WriteString_I }, -// { 0x01D60740, "PF_WriteEntity_I", (size_t)&PF_WriteEntity_I }, -// { 0x01D60770, "PF_makestatic_I", (size_t)&PF_makestatic_I }, -// { 0x01D608C0, "PF_StaticDecal", (size_t)&PF_StaticDecal }, -// { 0x01D60940, "PF_setspawnparms_I", (size_t)&PF_setspawnparms_I }, -// { 0x01D60970, "PF_changelevel_I", (size_t)&PF_changelevel_I }, - { 0x01D609D0, "SeedRandomNumberGenerator", (size_t)&SeedRandomNumberGenerator }, - { 0x01D60A10, "ran1", (size_t)&ran1 }, - { 0x01D60AE0, "fran1", (size_t)&fran1 }, - { 0x01D60B30, "RandomFloat", (size_t)&RandomFloat }, - { 0x01D60B60, "RandomLong", (size_t)&RandomLong }, -// { 0x01D60BC0, "PF_FadeVolume", (size_t)&PF_FadeVolume }, -// { 0x01D60C60, "PF_SetClientMaxspeed", (size_t)&PF_SetClientMaxspeed }, -// { 0x01D60CA0, "PF_GetPlayerUserId", (size_t)&PF_GetPlayerUserId }, -// { 0x01D60CF0, "PF_GetPlayerWONId", (size_t)&PF_GetPlayerWONId }, - { 0x01D60D00, "PF_GetPlayerAuthId", (size_t)&PF_GetPlayerAuthId }, -// { 0x01D60E00, "PF_BuildSoundMsg_I", (size_t)&PF_BuildSoundMsg_I }, -// { 0x01D60E50, "PF_IsDedicatedServer", (size_t)&PF_IsDedicatedServer }, -// { 0x01D60E60, "PF_GetPhysicsInfoString", (size_t)&PF_GetPhysicsInfoString }, -// { 0x01D60EB0, "PF_GetPhysicsKeyValue", (size_t)&PF_GetPhysicsKeyValue }, -// { 0x01D60F10, "PF_SetPhysicsKeyValue", (size_t)&PF_SetPhysicsKeyValue }, -// { 0x01D60F70, "PF_GetCurrentPlayer", (size_t)&PF_GetCurrentPlayer }, -// { 0x01D60FB0, "PF_CanSkipPlayer", (size_t)&PF_CanSkipPlayer }, -// { 0x01D61000, "PF_SetGroupMask", (size_t)&PF_SetGroupMask }, -// { 0x01D61020, "PF_CreateInstancedBaseline", (size_t)&PF_CreateInstancedBaseline }, -// { 0x01D61070, "PF_Cvar_DirectSet", (size_t)&PF_Cvar_DirectSet }, -// { 0x01D61090, "PF_ForceUnmodified", (size_t)&PF_ForceUnmodified }, -// { 0x01D611B0, "PF_GetPlayerStats", (size_t)&PF_GetPlayerStats }, -// //{ 0x01D61230, "QueryClientCvarValueCmd", (size_t)&QueryClientCvarValueCmd }, //NOXREF -// //{ 0x01D612D0, "QueryClientCvarValueCmd2", (size_t)&QueryClientCvarValueCmd2 }, //NOXREF -// { 0x01D61390, "QueryClientCvarValue", (size_t)&QueryClientCvarValue }, -// { 0x01D61410, "QueryClientCvarValue2", (size_t)&QueryClientCvarValue2 }, -// { 0x01D614A0, "hudCheckParm", (size_t)&hudCheckParm }, -// { 0x01D614F0, "EngCheckParm", (size_t)&EngCheckParm }, - -#endif // Pr_Cmds_region - -#ifndef Mathlib_region - - { 0x01D4F570, "anglemod", (size_t)&anglemod }, - //{ 0x, "BOPS_Error", (size_t)&BOPS_Error }, - { 0x01DBEE44, "BoxOnPlaneSide", (size_t)&BoxOnPlaneSide }, - //{ 0x, "InvertMatrix", (size_t)&InvertMatrix }, - { 0x01D4FD10, "AngleVectors", (size_t)&AngleVectors }, - { 0x01D4FE70, "AngleVectorsTranspose", (size_t)&AngleVectorsTranspose }, - { 0x01D4FF90, "AngleMatrix", (size_t)&AngleMatrix }, - //{ 0x, "AngleIMatrix", (size_t)&AngleIMatrix }, - //{ 0x, "NormalizeAngles", (size_t)&NormalizeAngles }, - //{ 0x, "InterpolateAngles", (size_t)&InterpolateAngles }, - { 0x01D502C0, "VectorTransform", (size_t)&VectorTransform }, - { 0x01D50320, "VectorCompare", (size_t)&VectorCompare }, - { 0x01D50350, "VectorMA", (size_t)&VectorMA }, - //{ 0x, "_DotProduct", (size_t)&_DotProduct }, - //{ 0x, "_VectorSubtract", (size_t)&_VectorSubtract }, - //{ 0x, "_VectorAdd", (size_t)&_VectorAdd }, - //{ 0x, "_VectorCopy", (size_t)&_VectorCopy }, - { 0x01D50420, "CrossProduct", (size_t)&CrossProduct }, - { 0x01D50460, "Length", (size_t)&Length }, - { 0x01D504A0, "VectorNormalize", (size_t)&VectorNormalize }, - //{ 0x, "VectorInverse", (size_t)&VectorInverse }, - { 0x01D50550, "VectorScale", (size_t)&VectorScale }, - //{ 0x, "Q_log2", (size_t)&Q_log2 }, - //{ 0x, "VectorMatrix", (size_t)&VectorMatrix }, - { 0x01D50640, "VectorAngles", (size_t)&VectorAngles }, - //{ 0x, "R_ConcatRotations", (size_t)&R_ConcatRotations }, - { 0x01D50850, "R_ConcatTransforms", (size_t)&R_ConcatTransforms }, - //{ 0x, "FloorDivMod", (size_t)&FloorDivMod }, - //{ 0x, "GreatestCommonDivisor", (size_t)&GreatestCommonDivisor }, - //{ 0x, "Invert24To16", (size_t)&Invert24To16 }, - -#endif // Mathlib_region - -#ifndef World_region - - { 0x01DB9050, "ClearLink", (size_t)&ClearLink }, - { 0x01DB9060, "RemoveLink", (size_t)&RemoveLink }, - { 0x01DB9080, "InsertLinkBefore", (size_t)&InsertLinkBefore }, - //{ 0x01DB90A0, "InsertLinkAfter", (size_t)&InsertLinkAfter }, //NOXREF - { 0x01DB90C0, "SV_InitBoxHull", (size_t)&SV_InitBoxHull }, - { 0x01DB9180, "SV_HullForBox", (size_t)&SV_HullForBox }, - //{ 0x01DB91D0, "SV_HullForBeam", (size_t)&SV_HullForBeam }, //NOXREF - { 0x01DB9640, "SV_HullForBsp", (size_t)&SV_HullForBsp }, - { 0x01DB9780, "SV_HullForEntity", (size_t)&SV_HullForEntity }, - { 0x01DB9850, "SV_CreateAreaNode", (size_t)&SV_CreateAreaNode }, - { 0x01DB9970, "SV_ClearWorld", (size_t)&SV_ClearWorld }, - { 0x01DB99B0, "SV_UnlinkEdict", (size_t)&SV_UnlinkEdict }, - { 0x01DB99E0, "SV_TouchLinks", (size_t)&SV_TouchLinks }, - { 0x01DB9BC0, "SV_FindTouchedLeafs", (size_t)&SV_FindTouchedLeafs }, - { 0x01DB9CF0, "SV_LinkEdict", (size_t)&SV_LinkEdict }, - { 0x01DC0614, "SV_HullPointContents", (size_t)&SV_HullPointContents }, - { 0x01DB9EB0, "SV_LinkContents", (size_t)&SV_LinkContents }, - { 0x01DBA0A0, "SV_PointContents", (size_t)&SV_PointContents }, - { 0x01DBA0F0, "SV_TestEntityPosition", (size_t)&SV_TestEntityPosition }, - { 0x01DBA160, "SV_RecursiveHullCheck", (size_t)&SV_RecursiveHullCheck }, - { 0x01DBA550, "SV_SingleClipMoveToEntity", (size_t)&SV_SingleClipMoveToEntity }, - { 0x01DBA950, "SV_ClipMoveToEntity", (size_t)&SV_ClipMoveToEntity }, - { 0x01DBA990, "SV_ClipToLinks", (size_t)&SV_ClipToLinks }, - { 0x01DBAC60, "SV_ClipToWorldbrush", (size_t)&SV_ClipToWorldbrush }, - { 0x01DBAE00, "SV_MoveBounds", (size_t)&SV_MoveBounds }, - { 0x01DBAE80, "SV_MoveNoEnts", (size_t)&SV_MoveNoEnts }, - { 0x01DBAFC0, "SV_Move", (size_t)&SV_Move }, - -#endif // World_region - -#ifndef Sv_Phys_region - - //{ 0x01D94A90, "SV_CheckAllEnts", (size_t)&SV_CheckAllEnts }, //NOXREF - { 0x01D94B00, "SV_CheckVelocity", (size_t)&SV_CheckVelocity }, - { 0x01D94C00, "SV_RunThink", (size_t)&SV_RunThink }, - { 0x01D94CB0, "SV_Impact", (size_t)&SV_Impact }, - { 0x01D94D50, "ClipVelocity", (size_t)&ClipVelocity }, - { 0x01D94E10, "SV_FlyMove", (size_t)&SV_FlyMove }, - { 0x01D952F0, "SV_AddGravity", (size_t)&SV_AddGravity }, - //{ 0x01D95370, "SV_AddCorrectGravity", (size_t)&SV_AddCorrectGravity }, //NOXREF - //{ 0x01D953F0, "SV_FixupGravityVelocity", (size_t)&SV_FixupGravityVelocity }, //NOXREF - { 0x01D95450, "SV_PushEntity", (size_t)&SV_PushEntity }, - { 0x01D95550, "SV_PushMove", (size_t)&SV_PushMove }, - { 0x01D958F0, "SV_PushRotate", (size_t)&SV_PushRotate }, - { 0x01D95F00, "SV_Physics_Pusher", (size_t)&SV_Physics_Pusher }, - { 0x01D960F0, "SV_CheckWater", (size_t)&SV_CheckWater }, - - { 0x01D96290, "SV_RecursiveWaterLevel", (size_t)&SV_RecursiveWaterLevel }, - { 0x01D96310, "SV_Submerged", (size_t)&SV_Submerged }, - { 0x01D96410, "SV_Physics_None", (size_t)&SV_Physics_None }, - { 0x01D96430, "SV_Physics_Follow", (size_t)&SV_Physics_Follow }, - { 0x01D964F0, "SV_Physics_Noclip", (size_t)&SV_Physics_Noclip }, - - { 0x01D96560, "SV_CheckWaterTransition", (size_t)&SV_CheckWaterTransition }, - { 0x01D96740, "SV_Physics_Toss", (size_t)&SV_Physics_Toss }, - { 0x01D96B20, "PF_WaterMove", (size_t)&PF_WaterMove }, - - { 0x01D96E70, "SV_Physics_Step", (size_t)&SV_Physics_Step }, - { 0x01D97240, "SV_Physics", (size_t)&SV_Physics }, - { 0x01D97480, "SV_Trace_Toss", (size_t)&SV_Trace_Toss }, - -#endif // Sv_Phys_region - -#ifndef Sv_Move_region - - { 0x01D93A40, "SV_CheckBottom", (size_t)&SV_CheckBottom }, - { 0x01D93CB0, "SV_movetest", (size_t)&SV_movetest }, - { 0x01D93ED0, "SV_movestep", (size_t)&SV_movestep }, - { 0x01D94250, "SV_StepDirection", (size_t)&SV_StepDirection }, - { 0x01D942D0, "SV_FlyDirection", (size_t)&SV_FlyDirection }, - { 0x01D94310, "SV_FixCheckBottom", (size_t)&SV_FixCheckBottom }, - //{ 0x01D94330, "SV_NewChaseDir", (size_t)&SV_NewChaseDir }, //NOXREF - //{ 0x01D94620, "SV_CloseEnough", (size_t)&SV_CloseEnough }, //NOXREF - //{ 0x01D94680, "SV_ReachedGoal", (size_t)&SV_ReachedGoal }, //NOXREF - { 0x01D946D0, "SV_NewChaseDir2", (size_t)&SV_NewChaseDir2 }, - { 0x01D949C0, "SV_MoveToOrigin_I", (size_t)&SV_MoveToOrigin_I }, - -#endif // Sv_Move_region - -#ifndef Sv_pmove_region - - { 0x01D975F0, "PM_SV_PlaybackEventFull", (size_t)&PM_SV_PlaybackEventFull }, - { 0x01D97630, "PM_SV_PlaySound", (size_t)&PM_SV_PlaySound }, - { 0x01D97670, "PM_SV_TraceTexture", (size_t)&PM_SV_TraceTexture }, - -#endif // Sv_pmove_region - -#ifndef R_Studio_region - - { 0x01D6F260, "SV_InitStudioHull", (size_t)&SV_InitStudioHull }, - { 0x01D6F2F0, "R_CheckStudioCache", (size_t)&R_CheckStudioCache }, - //{ 0x01D6F3C0, "R_AddToStudioCache", (size_t)&R_AddToStudioCache }, // NOXREF - { 0x01D6F500, "AngleQuaternion", (size_t)&AngleQuaternion }, - { 0x01D6F600, "QuaternionSlerp", (size_t)&QuaternionSlerp }, - { 0x01D6F810, "QuaternionMatrix", (size_t)&QuaternionMatrix }, - { 0x01D6F900, "R_StudioCalcBoneAdj", (size_t)&R_StudioCalcBoneAdj }, - { 0x01D6FB60, "R_StudioCalcBoneQuaterion", (size_t)&R_StudioCalcBoneQuaterion }, - { 0x01D6FD20, "R_StudioCalcBonePosition", (size_t)&R_StudioCalcBonePosition }, - { 0x01D6FE70, "R_StudioSlerpBones", (size_t)&R_StudioSlerpBones }, - { 0x01D6FF80, "R_GetAnim", (size_t)&R_GetAnim }, - { 0x01D70020, "SV_StudioSetupBones", (size_t)&SV_StudioSetupBones }, - { 0x01D70390, "SV_SetStudioHullPlane", (size_t)&SV_SetStudioHullPlane }, - { 0x01D70400, "R_StudioHull", (size_t)&R_StudioHull }, - { 0x01D70A40, "SV_HitgroupForStudioHull", (size_t)&SV_HitgroupForStudioHull }, - //{ 0x01D70A50, "R_InitStudioCache", (size_t)&R_InitStudioCache }, // NOXREF - //{ 0x01D70A90, "R_FlushStudioCache", (size_t)&R_FlushStudioCache }, // NOXREF - { 0x01D70AA0, "R_StudioBodyVariations", (size_t)&R_StudioBodyVariations }, - { 0x01D70AF0, "R_StudioPlayerBlend", (size_t)&R_StudioPlayerBlend }, - { 0x01D70BD0, "SV_HullForStudioModel", (size_t)&SV_HullForStudioModel }, - { 0x01D70E10, "DoesSphereIntersect", (size_t)&DoesSphereIntersect }, - { 0x01D70ED0, "SV_CheckSphereIntersection", (size_t)&SV_CheckSphereIntersection }, - { 0x01D70FF0, "AnimationAutomove", (size_t)&AnimationAutomove }, - { 0x01D71000, "GetBonePosition", (size_t)&GetBonePosition }, - { 0x01D710A0, "GetAttachment", (size_t)&GetAttachment }, - { 0x01D71170, "ModelFrameCount", (size_t)&ModelFrameCount }, - { 0x01D76260, "R_StudioBoundVertex", (size_t)&R_StudioBoundVertex }, - { 0x01D762F0, "R_StudioBoundBone", (size_t)&R_StudioBoundBone }, - { 0x01D76380, "R_StudioAccumulateBoneVerts", (size_t)&R_StudioAccumulateBoneVerts }, - { 0x01D76420, "R_StudioComputeBounds", (size_t)&R_StudioComputeBounds }, - { 0x01D76600, "R_GetStudioBounds", (size_t)&R_GetStudioBounds }, - { 0x01D76C40, "R_ResetSvBlending", (size_t)&R_ResetSvBlending }, - -#endif // R_Studio_region - -#ifndef Net_ws_region - - { 0x01D57050, "NET_ThreadLock", (size_t)&NET_ThreadLock }, - { 0x01D57070, "NET_ThreadUnlock", (size_t)&NET_ThreadUnlock }, - { 0x01D57090, "Q_ntohs", (size_t)&Q_ntohs }, - { 0x01D570A0, "NetadrToSockadr", (size_t)&NetadrToSockadr }, - { 0x01D57160, "SockadrToNetadr", (size_t)&SockadrToNetadr }, - { 0x01D571D0, "NET_HostToNetShort", (size_t)&NET_HostToNetShort }, // NOXREF - { 0x01D571E0, "NET_CompareAdr", (size_t)&NET_CompareAdr }, - { 0x01D57270, "NET_CompareClassBAdr", (size_t)&NET_CompareClassBAdr }, - { 0x01D572C0, "NET_IsReservedAdr", (size_t)&NET_IsReservedAdr }, - { 0x01D57310, "NET_CompareBaseAdr", (size_t)&NET_CompareBaseAdr }, - { 0x01D57380, "NET_AdrToString", (size_t)&NET_AdrToString }, - { 0x01D574A0, "NET_BaseAdrToString", (size_t)&NET_BaseAdrToString }, - { 0x01D575A0, "NET_StringToSockaddr", (size_t)&NET_StringToSockaddr }, - { 0x01D57820, "NET_StringToAdr", (size_t)&NET_StringToAdr }, - { 0x01D57890, "NET_IsLocalAddress", (size_t)&NET_IsLocalAddress }, - { 0x01D578A0, "NET_ErrorString", (size_t)&NET_ErrorString }, - { 0x01D57B20, "NET_TransferRawData", (size_t)&NET_TransferRawData }, - { 0x01D57B50, "NET_GetLoopPacket", (size_t)&NET_GetLoopPacket }, - { 0x01D57C00, "NET_SendLoopPacket", (size_t)&NET_SendLoopPacket }, - { 0x01D57C80, "NET_RemoveFromPacketList", (size_t)&NET_RemoveFromPacketList }, - { 0x01D57CA0, "NET_CountLaggedList", (size_t)&NET_CountLaggedList }, - { 0x01D57CC0, "NET_ClearLaggedList", (size_t)&NET_ClearLaggedList }, - { 0x01D57D10, "NET_AddToLagged", (size_t)&NET_AddToLagged }, - { 0x01D57D80, "NET_AdjustLag", (size_t)&NET_AdjustLag }, - { 0x01D57EC0, "NET_LagPacket", (size_t)&NET_LagPacket }, - { 0x01D58090, "NET_FlushSocket", (size_t)&NET_FlushSocket }, - { 0x01D580E0, "NET_GetLong", (size_t)&NET_GetLong }, - { 0x01D582F0, "NET_QueuePacket", (size_t)&NET_QueuePacket }, -#ifdef __linux__ - { 0x0, "NET_Sleep_Timeout", (size_t)&NET_Sleep_Timeout }, -#endif // __linux__ - { 0x01D584A0, "NET_Sleep", (size_t)&NET_Sleep }, - { 0x01D58630, "NET_StartThread", (size_t)&NET_StartThread }, - { 0x01D586B0, "NET_StopThread", (size_t)&NET_StopThread }, - { 0x01D586F0, "net_malloc", (size_t)&net_malloc }, - { 0x01D58710, "NET_AllocMsg", (size_t)&NET_AllocMsg }, - { 0x01D58760, "NET_FreeMsg", (size_t)&NET_FreeMsg }, - { 0x01D587A0, "NET_GetPacket", (size_t)&NET_GetPacket }, - { 0x01D588B0, "NET_AllocateQueues", (size_t)&NET_AllocateQueues }, - { 0x01D588F0, "NET_FlushQueues", (size_t)&NET_FlushQueues }, - { 0x01D58960, "NET_SendLong", (size_t)&NET_SendLong }, - { 0x01D58AE0, "NET_SendPacket", (size_t)&NET_SendPacket }, - { 0x01D58C80, "NET_IPSocket", (size_t)&NET_IPSocket }, - { 0x01D58E80, "NET_OpenIP", (size_t)&NET_OpenIP }, -#ifdef _WIN32 - { 0x01D59000, "NET_IPXSocket", (size_t)&NET_IPXSocket }, - { 0x01D59170, "NET_OpenIPX", (size_t)&NET_OpenIPX }, -#endif //_WIN32 - { 0x01D59240, "NET_GetLocalAddress", (size_t)&NET_GetLocalAddress }, - { 0x01D59410, "NET_IsConfigured", (size_t)&NET_IsConfigured }, - { 0x01D59420, "NET_Config", (size_t)&NET_Config }, - { 0x01D596F0, "MaxPlayers_f", (size_t)&MaxPlayers_f }, - { 0x01D594D0, "NET_Init", (size_t)&NET_Init }, - { 0x01D59790, "NET_ClearLagData", (size_t)&NET_ClearLagData }, - { 0x01D597E0, "NET_Shutdown", (size_t)&NET_Shutdown }, - { 0x01D59810, "NET_JoinGroup", (size_t)&NET_JoinGroup }, - { 0x01D59870, "NET_LeaveGroup", (size_t)&NET_LeaveGroup }, - -#endif // Net_ws_region - -#ifndef Net_chan_region - - { 0x01D54DB0, "Netchan_UnlinkFragment", (size_t)&Netchan_UnlinkFragment }, - { 0x01D54E20, "Netchan_OutOfBand", (size_t)&Netchan_OutOfBand }, - { 0x01D54EA0, "Netchan_OutOfBandPrint", (size_t)&Netchan_OutOfBandPrint }, - { 0x01D54F00, "Netchan_ClearFragbufs", (size_t)&Netchan_ClearFragbufs }, - { 0x01D54F30, "Netchan_ClearFragments", (size_t)&Netchan_ClearFragments }, - { 0x01D54FA0, "Netchan_Clear", (size_t)&Netchan_Clear }, - { 0x01D55040, "Netchan_Setup", (size_t)&Netchan_Setup }, - { 0x01D550D0, "Netchan_CanPacket", (size_t)&Netchan_CanPacket }, - { 0x01D55130, "Netchan_UpdateFlow", (size_t)&Netchan_UpdateFlow }, - { 0x01D55240, "Netchan_Transmit", (size_t)&Netchan_Transmit }, - { 0x01D558E0, "Netchan_FindBufferById", (size_t)&Netchan_FindBufferById }, - { 0x01D55950, "Netchan_CheckForCompletion", (size_t)&Netchan_CheckForCompletion }, - { 0x01D55A00, "Netchan_Validate", (size_t)&Netchan_Validate }, - { 0x01D55A90, "Netchan_Process", (size_t)&Netchan_Process }, - { 0x01D55F40, "Netchan_FragSend", (size_t)&Netchan_FragSend }, - { 0x01D55F90, "Netchan_AddBufferToList", (size_t)&Netchan_AddBufferToList }, - { 0x01D55FE0, "Netchan_AllocFragbuf", (size_t)&Netchan_AllocFragbuf }, - { 0x01D56010, "Netchan_AddFragbufToTail", (size_t)&Netchan_AddFragbufToTail }, - { 0x01D56050, "Netchan_CreateFragments_", (size_t)&Netchan_CreateFragments_ }, - { 0x01D56210, "Netchan_CreateFragments", (size_t)&Netchan_CreateFragments }, - { 0x01D56250, "Netchan_CreateFileFragmentsFromBuffer", (size_t)&Netchan_CreateFileFragmentsFromBuffer }, - { 0x01D56450, "Netchan_CreateFileFragments", (size_t)&Netchan_CreateFileFragments }, - { 0x01D56850, "Netchan_FlushIncoming", (size_t)&Netchan_FlushIncoming }, - { 0x01D568C0, "Netchan_CopyNormalFragments", (size_t)&Netchan_CopyNormalFragments }, - { 0x01D569D0, "Netchan_CopyFileFragments", (size_t)&Netchan_CopyFileFragments }, - //{ 0x01D56DB0, "Netchan_IsSending", (size_t)&Netchan_IsSending }, - //{ 0x01D56DE0, "Netchan_IsReceiving", (size_t)&Netchan_IsReceiving }, - { 0x01D56E10, "Netchan_IncomingReady", (size_t)&Netchan_IncomingReady }, - //{ 0x01D56E40, "Netchan_UpdateProgress", (size_t)&Netchan_UpdateProgress }, - { 0x01D56FE0, "Netchan_Init", (size_t)&Netchan_Init }, - //{ 0x01D57030, "Netchan_CompressPacket", (size_t)&Netchan_CompressPacket }, //NOXREF - //{ 0x01D57040, "Netchan_DecompressPacket", (size_t)&Netchan_DecompressPacket }, //NOXREF - -#endif // Net_chan_region - -#ifndef Hashpak_region - - { 0x01D3E970, "HPAK_GetDataPointer", (size_t)&HPAK_GetDataPointer }, - { 0x01D3EC40, "HPAK_FindResource", (size_t)&HPAK_FindResource }, - { 0x01D3ECB0, "HPAK_AddToQueue", (size_t)&HPAK_AddToQueue }, - { 0x01D3EDC0, "HPAK_FlushHostQueue", (size_t)&HPAK_FlushHostQueue }, - { 0x01D3EE20, "HPAK_AddLump", (size_t)&HPAK_AddLump }, - { 0x01D3F3D0, "HPAK_RemoveLump", (size_t)&HPAK_RemoveLump }, - { 0x01D3F850, "HPAK_ResourceForIndex", (size_t)&HPAK_ResourceForIndex }, - { 0x01D3F9E0, "HPAK_ResourceForHash", (size_t)&HPAK_ResourceForHash }, - { 0x01D3FBA0, "HPAK_List_f", (size_t)&HPAK_List_f }, - { 0x01D3FE30, "HPAK_CreatePak", (size_t)&HPAK_CreatePak }, - { 0x01D40140, "HPAK_Remove_f", (size_t)&HPAK_Remove_f }, - { 0x01D401F0, "HPAK_Validate_f", (size_t)&HPAK_Validate_f }, - { 0x01D405B0, "HPAK_Extract_f", (size_t)&HPAK_Extract_f }, - { 0x01D409A0, "HPAK_Init", (size_t)&HPAK_Init }, - { 0x01D409F1, "HPAK_GetItem", (size_t)&HPAK_GetItem }, // NOXREF - { 0x01D40B90, "HPAK_CheckSize", (size_t)&HPAK_CheckSize }, - { 0x01D40CE0, "HPAK_ValidatePak", (size_t)&HPAK_ValidatePak }, - { 0x01D40F80, "HPAK_CheckIntegrity", (size_t)&HPAK_CheckIntegrity }, - -#endif // Hashpak_region - -#ifndef Wad_region - - { 0x01DB8D30, "W_CleanupName", (size_t)&W_CleanupName }, - { 0x01DB8D90, "W_LoadWadFile", (size_t)&W_LoadWadFile }, - { 0x01DB8EF0, "W_GetLumpinfo", (size_t)&W_GetLumpinfo }, - { 0x01DB8F70, "W_GetLumpName", (size_t)&W_GetLumpName }, - //{ 0x, "W_GetLumpNum", (size_t)&W_GetLumpNum }, // NOXREF - { 0x01DB8FF0, "W_Shutdown", (size_t)&W_Shutdown }, - { 0x01DB9020, "SwapPic", (size_t)&SwapPic }, - -#endif // Wad_region - -#ifndef Textures_region - - { 0x01DA7200, "SafeRead", (size_t)&SafeRead }, - { 0x01DA7230, "CleanupName", (size_t)&CleanupName }, - { 0x01DA7290, "lump_sorter", (size_t)&lump_sorter }, - { 0x01DA72E0, "ForwardSlashes", (size_t)&ForwardSlashes }, - { 0x01DA7300, "TEX_InitFromWad", (size_t)&TEX_InitFromWad }, - { 0x01DA75D0, "TEX_CleanupWadInfo", (size_t)&TEX_CleanupWadInfo }, - { 0x01DA7630, "TEX_LoadLump", (size_t)&TEX_LoadLump }, - { 0x01DA76D4, "FindMiptex", (size_t)&FindMiptex }, - { 0x01DA7740, "TEX_AddAnimatingTextures", (size_t)&TEX_AddAnimatingTextures }, - -#endif // Textures_region - -#ifndef Sv_user_region - - { 0x01D9B3B0, "SV_ParseConsistencyResponse", (size_t)&SV_ParseConsistencyResponse }, - { 0x01D9B790, "SV_FileInConsistencyList", (size_t)&SV_FileInConsistencyList }, - { 0x01D9B7F0, "SV_TransferConsistencyInfo", (size_t)&SV_TransferConsistencyInfo }, - { 0x01D9B960, "SV_SendConsistencyList", (size_t)&SV_SendConsistencyList }, - { 0x01D9BA50, "SV_PreRunCmd", (size_t)&SV_PreRunCmd }, - { 0x01D9BA60, "SV_CopyEdictToPhysent", (size_t)&SV_CopyEdictToPhysent }, - { 0x01D9BD70, "SV_AddLinksToPM_", (size_t)&SV_AddLinksToPM_ }, - { 0x01D9C070, "SV_AddLinksToPM", (size_t)&SV_AddLinksToPM }, - { 0x01D9C1A0, "SV_PlayerRunPreThink", (size_t)&SV_PlayerRunPreThink }, - { 0x01D9C1C0, "SV_PlayerRunThink", (size_t)&SV_PlayerRunThink }, - { 0x01D9C260, "SV_CheckMovingGround", (size_t)&SV_CheckMovingGround }, - { 0x01D9C340, "SV_ConvertPMTrace", (size_t)&SV_ConvertPMTrace }, - { 0x01D9C3A0, "SV_ForceFullClientsUpdate", (size_t)&SV_ForceFullClientsUpdate }, - { 0x01D9C470, "SV_RunCmd", (size_t)&SV_RunCmd }, - { 0x01D9D69F, "SV_ValidateClientCommand", (size_t)&SV_ValidateClientCommand }, - { 0x01D9D6EF, "SV_CalcClientTime", (size_t)&SV_CalcClientTime }, - { 0x01D9D86F, "SV_ComputeLatency", (size_t)&SV_ComputeLatency }, - { 0x01D9D88F, "SV_UnlagCheckTeleport", (size_t)&SV_UnlagCheckTeleport }, - { 0x01D9D8DF, "SV_GetTrueOrigin", (size_t)&SV_GetTrueOrigin }, - { 0x01D9D96F, "SV_GetTrueMinMax", (size_t)&SV_GetTrueMinMax }, - { 0x01D9D9EF, "SV_FindEntInPack", (size_t)&SV_FindEntInPack }, - { 0x01D9DA2F, "SV_SetupMove", (size_t)&SV_SetupMove }, - { 0x01D9E01F, "SV_RestoreMove", (size_t)&SV_RestoreMove }, - { 0x01D9E17F, "SV_ParseStringCommand", (size_t)&SV_ParseStringCommand }, - { 0x01D9E1DF, "SV_ParseDelta", (size_t)&SV_ParseDelta }, - { 0x01D9E1FF, "SV_EstablishTimeBase", (size_t)&SV_EstablishTimeBase }, - { 0x01D9E2EF, "SV_ParseMove", (size_t)&SV_ParseMove }, - { 0x01D9E76F, "SV_ParseVoiceData", (size_t)&SV_ParseVoiceData }, - { 0x01D9E8DF, "SV_IgnoreHLTV", (size_t)&SV_IgnoreHLTV }, - { 0x01D9E8EF, "SV_ParseCvarValue", (size_t)&SV_ParseCvarValue }, - { 0x01D9E92F, "SV_ParseCvarValue2", (size_t)&SV_ParseCvarValue2 }, - { 0x01D9E9AF, "SV_ExecuteClientMessage", (size_t)&SV_ExecuteClientMessage }, - { 0x01D9EACF, "SV_SetPlayer", (size_t)&SV_SetPlayer }, - { 0x01D9EB2F, "SV_ShowServerinfo_f", (size_t)&SV_ShowServerinfo_f }, - { 0x01D9EB4F, "SV_SendEnts_f", (size_t)&SV_SendEnts_f }, - { 0x01D9EB7F, "SV_FullUpdate_f", (size_t)&SV_FullUpdate_f }, - -#endif // Sv_user_region - -#ifndef Tmessage_region - - { 0x01DA7B00, "memfgets", (size_t)&memfgets }, - { 0x01DA7B90, "IsComment", (size_t)&IsComment }, - { 0x01DA7BD0, "IsStartOfText", (size_t)&IsStartOfText }, - { 0x01DA7BF0, "IsEndOfText", (size_t)&IsEndOfText }, - { 0x01DA7C10, "IsWhiteSpace", (size_t)&IsWhiteSpace }, - //{ 0x01DA7C40, "SkipSpace", (size_t)&SkipSpace }, // NOXREF - //{ 0x01DA7C80, "SkipText", (size_t)&SkipText }, // NOXREF - //{ 0x01DA7CC0, "ParseFloats", (size_t)&ParseFloats }, // NOXREF - { 0x01DA7D10, "TrimSpace", (size_t)&TrimSpace }, - //{ 0x01DA7D90, "IsToken", (size_t)&IsToken }, // NOXREF - //{ 0x01DA7DD0, "ParseDirective", (size_t)&ParseDirective }, // NOXREF - //{ 0x01DA80A0, "TextMessageParse", (size_t)&TextMessageParse }, // NOXREF - //{ 0x01DA8030, "TextMessageShutdown", (size_t)&TextMessageShutdown }, // NOXREF - //{ 0x01DA8050, "TextMessageInit", (size_t)&TextMessageInit }, // NOXREF - //{ 0x01DA8410, "TextMessageGet", (size_t)&TextMessageGet }, // NOXREF - -#endif // Tmessage_region - -#ifndef TraceInit_Region - - { 0x01DA8CA0, "_ZN12CInitTracker4InitEPKcS1_i", mfunc_ptr_cast(&CInitTracker::Init) }, - { 0x01DA8D80, "_ZN12CInitTracker8ShutdownEPKci", mfunc_ptr_cast(&CInitTracker::Shutdown) }, - //{ 0x01DA8B60, "_ZN12CInitTrackerC2Ev", mfunc_ptr_cast(&CInitTracker::CInitTracker) }, - //{ 0x01DA8BD0, "_ZN12CInitTrackerD2Ev", mfunc_ptr_cast(&CInitTracker::~CInitTracker) }, - { 0x01DA8E60, "_Z9TraceInitPKcS0_i", (size_t)&TraceInit }, - { 0x01DA8E80, "_Z13TraceShutdownPKci", (size_t)&TraceShutdown }, - -#endif // TraceInit_Region - -#ifndef Vid_null_region - - //{ 0x, "VID_SetPalette", (size_t)&VID_SetPalette }, - //{ 0x, "VID_ShiftPalette", (size_t)&VID_ShiftPalette }, - //{ 0x, "VID_WriteBuffer", (size_t)&VID_WriteBuffer }, - //{ 0x01DB4BD0, "VID_Init", (size_t)&VID_Init }, - //{ 0x, "D_FlushCaches", (size_t)&D_FlushCaches }, - //{ 0x, "R_SetStackBase", (size_t)&R_SetStackBase }, - //{ 0x01D7E3D0, "SCR_UpdateScreen", (size_t)&SCR_UpdateScreen }, - //{ 0x, "V_Init", (size_t)&V_Init }, - //{ 0x, "Draw_Init", (size_t)&Draw_Init }, - //{ 0x, "SCR_Init", (size_t)&SCR_Init }, - //{ 0x01D65630, "R_Init", (size_t)&R_Init }, - //{ 0x01D67B20, "R_ForceCVars", (size_t)&R_ForceCVars }, - //{ 0x01D7E320, "SCR_BeginLoadingPlaque", (size_t)&SCR_BeginLoadingPlaque }, - //{ 0x01D7E3A0, "SCR_EndLoadingPlaque", (size_t)&SCR_EndLoadingPlaque }, - //{ 0x, "R_InitSky", (size_t)&R_InitSky }, - //{ 0x01D65F70, "R_MarkLeaves", (size_t)&R_MarkLeaves }, - { 0x01D65570, "R_InitTextures", (size_t)&R_InitTextures }, - //{ 0x, "StartLoadingProgressBar", (size_t)&StartLoadingProgressBar }, - //{ 0x01D07670, "ContinueLoadingProgressBar", (size_t)&ContinueLoadingProgressBar }, - //{ 0x01D07700, "SetLoadingProgressBarStatusText", (size_t)&SetLoadingProgressBarStatusText }, - -#endif // Vid_null_region - -#ifndef L_studio_region - - { 0x01D4F0E0, "Mod_LoadStudioModel", (size_t)&Mod_LoadStudioModel }, - -#endif // L_studio_region - -#ifndef Crc_region - - { 0x01D2C610, "CRC32_Init", (size_t)&CRC32_Init }, - { 0x01D2C620, "CRC32_Final", (size_t)&CRC32_Final }, - { 0x01D2C630, "CRC32_ProcessByte", (size_t)&CRC32_ProcessByte }, - { 0x01D2C660, "CRC32_ProcessBuffer", (size_t)&CRC32_ProcessBuffer }, - { 0x01D2C8D0, "COM_BlockSequenceCRCByte", (size_t)&COM_BlockSequenceCRCByte }, - { 0x01D2C970, "CRC_File", (size_t)&CRC_File }, // NOXREF - { 0x01D2CA40, "CRC_MapFile", (size_t)&CRC_MapFile }, - { 0x01D2CBB0, "MD5Init", (size_t)&MD5Init }, - { 0x01D2CBE0, "MD5Update", (size_t)&MD5Update }, - { 0x01D2CCB0, "MD5Final", (size_t)&MD5Final }, - { 0x01D2CD40, "MD5Transform", (size_t)&MD5Transform }, - { 0x01D2D5B0, "MD5_Hash_File", (size_t)&MD5_Hash_File }, - { 0x01D2D6F0, "MD5_Print", (size_t)&MD5_Print }, - -#endif // Crc_region - -#ifndef Sv_RemoteAccess_region - - { 0x01D984E0, "_ZN19CServerRemoteAccess20SendMessageToAdminUIEPKc", mfunc_ptr_cast(&CServerRemoteAccess::SendMessageToAdminUI) }, - { 0x01D985E0, "NotifyDedicatedServerUI", (size_t)&NotifyDedicatedServerUI }, - { 0x01D98090, "_ZN19CServerRemoteAccess17LookupStringValueEPKc", mfunc_ptr_cast(&CServerRemoteAccess::LookupStringValue) }, - { 0x01D97D40, "_ZN19CServerRemoteAccess11LookupValueEPKcR10CUtlBuffer", mfunc_ptr_cast(&CServerRemoteAccess::LookupValue) }, - - { 0x01D98190, "_ZN19CServerRemoteAccess14GetUserBanListER10CUtlBuffer", mfunc_ptr_cast(&CServerRemoteAccess::GetUserBanList) }, - { 0x01D98280, "_ZN19CServerRemoteAccess13GetPlayerListER10CUtlBuffer", mfunc_ptr_cast(&CServerRemoteAccess::GetPlayerList) }, - { 0x01D983B0, "_ZN19CServerRemoteAccess10GetMapListER10CUtlBuffer", mfunc_ptr_cast(&CServerRemoteAccess::GetMapList) }, - - { 0x01D97AD0, "_ZN19CServerRemoteAccess12RequestValueEiPKc", mfunc_ptr_cast(&CServerRemoteAccess::RequestValue) }, - { 0x01D97C20, "_ZN19CServerRemoteAccess8SetValueEPKcS1_", mfunc_ptr_cast(&CServerRemoteAccess::SetValue) }, - { 0x01D97D10, "_ZN19CServerRemoteAccess11ExecCommandEPKc", mfunc_ptr_cast(&CServerRemoteAccess::ExecCommand) }, - - { 0x01D97850, "_ZN19CServerRemoteAccess16WriteDataRequestEPKvi", mfunc_ptr_cast(&CServerRemoteAccess::WriteDataRequest_noVirt) }, - { 0x01D979A0, "_ZN19CServerRemoteAccess16ReadDataResponseEPvi", mfunc_ptr_cast(&CServerRemoteAccess::ReadDataResponse_noVirt) }, - -#endif // Sv_RemoteAccess_region - -#ifndef IpratelimitWrapper_region - - //{ 0x01D4D990, "CheckIP", (size_t)&CheckIP }, - -#endif // IpratelimitWrapper_region - -#ifndef Com_custom - - { 0x01D28610, "COM_ClearCustomizationList", (size_t)&COM_ClearCustomizationList }, - { 0x01D28740, "COM_CreateCustomization", (size_t)&COM_CreateCustomization }, - { 0x01D28980, "COM_SizeofResourceList", (size_t)&COM_SizeofResourceList }, - -#endif // Com_custom - -#ifndef Sv_upld - - { 0x01D9A980, "SV_CheckFile", (size_t)&SV_CheckFile }, - { 0x01D9AA50, "SV_ClearResourceLists", (size_t)&SV_ClearResourceLists }, - { 0x01D9AA90, "SV_CreateCustomizationList", (size_t)&SV_CreateCustomizationList }, - { 0x01D9ABB0, "SV_Customization", (size_t)&SV_Customization }, - { 0x01D9AD20, "SV_RegisterResources", (size_t)&SV_RegisterResources }, - { 0x01D9AD70, "SV_MoveToOnHandList", (size_t)&SV_MoveToOnHandList }, - { 0x01D9ADB0, "SV_AddToResourceList", (size_t)&SV_AddToResourceList }, - { 0x01D9AE00, "SV_ClearResourceList", (size_t)&SV_ClearResourceList }, - { 0x01D9AE50, "SV_RemoveFromResourceList", (size_t)&SV_RemoveFromResourceList }, - { 0x01D9AE80, "SV_EstimateNeededResources", (size_t)&SV_EstimateNeededResources }, - { 0x01D9AEF0, "SV_RequestMissingResourcesFromClients", (size_t)&SV_RequestMissingResourcesFromClients }, - { 0x01D9AF40, "SV_UploadComplete", (size_t)&SV_UploadComplete }, - { 0x01D9AFA0, "SV_BatchUploadRequest", (size_t)&SV_BatchUploadRequest }, - { 0x01D9B040, "SV_RequestMissingResources", (size_t)&SV_RequestMissingResources }, - { 0x01D9B070, "SV_ParseResourceList", (size_t)&SV_ParseResourceList }, - -#endif // Sv_upld - -#ifndef Decals - - { 0x01D33EF0, "Draw_Shutdown", (size_t)&Draw_Shutdown }, - { 0x01D33F30, "Draw_DecalShutdown", (size_t)&Draw_DecalShutdown }, - { 0x01D33F60, "Draw_AllocateCacheSpace", (size_t)&Draw_AllocateCacheSpace }, - { 0x01D33F90, "Draw_CacheWadInitFromFile", (size_t)&Draw_CacheWadInitFromFile }, - { 0x01D34070, "Draw_CacheWadInit", (size_t)&Draw_CacheWadInit }, - { 0x01D340C0, "Draw_CustomCacheWadInit", (size_t)&Draw_CustomCacheWadInit }, - { 0x01D3A830, "Draw_MiptexTexture", (size_t)&Draw_MiptexTexture }, - { 0x01D34290, "Draw_CacheWadHandler", (size_t)&Draw_CacheWadHandler }, - { 0x01D342B0, "Draw_FreeWad", (size_t)&Draw_FreeWad }, - { 0x01D34380, "Draw_DecalSetName", (size_t)&Draw_DecalSetName }, // NOXREF - { 0x01D343C0, "Draw_DecalIndex", (size_t)&Draw_DecalIndex }, // NOXREF - { 0x01D34450, "Draw_DecalCount", (size_t)&Draw_DecalCount }, - { 0x01D34460, "Draw_DecalSize", (size_t)&Draw_DecalSize }, - { 0x01D34490, "Draw_DecalName", (size_t)&Draw_DecalName }, - { 0x01D344C0, "Draw_DecalTexture", (size_t)&Draw_DecalTexture }, // NOXREF - { 0x01D34560, "Draw_CacheByIndex", (size_t)&Draw_CacheByIndex }, - { 0x01D34600, "Draw_DecalIndexFromName", (size_t)&Draw_DecalIndexFromName }, // NOXREF - { 0x01D34670, "Decal_ReplaceOrAppendLump", (size_t)&Decal_ReplaceOrAppendLump }, - { 0x01D34710, "Decal_CountLumps", (size_t)&Decal_CountLumps }, - { 0x01D34730, "Decal_SizeLumps", (size_t)&Decal_SizeLumps }, - { 0x01D34750, "Decal_MergeInDecals", (size_t)&Decal_MergeInDecals }, - { 0x01D349A0, "Decal_Init", (size_t)&Decal_Init }, - { 0x01D34B00, "CustomDecal_Validate", (size_t)&CustomDecal_Validate }, - { 0x01D34B60, "CustomDecal_Init", (size_t)&CustomDecal_Init }, - { 0x01D34BD0, "Draw_CacheGet", (size_t)&Draw_CacheGet }, // NOXREF - { 0x01D34CC0, "Draw_CustomCacheGet", (size_t)&Draw_CustomCacheGet }, - { 0x01D34D60, "Draw_CacheReload", (size_t)&Draw_CacheReload }, // NOXREF - { 0x01D34E40, "Draw_ValidateCustomLogo", (size_t)&Draw_ValidateCustomLogo }, - { 0x01D35000, "Draw_CacheLoadFromCustom", (size_t)&Draw_CacheLoadFromCustom }, - { 0x01D35110, "Draw_CacheIndex", (size_t)&Draw_CacheIndex }, // NOXREF - { 0x01D351A9, "Draw_CacheFindIndex", (size_t)&Draw_CacheFindIndex }, // NOXREF - -#endif // Decals - -#ifndef Sys_engine - - //{ 0x, "CEngine::CEngine", (size_t)&CEngine::CEngine }, - //{ 0x, "CEngine::~CEngine", (size_t)&CEngine::~CEngine }, - { 0x01DA1C80, "_ZN7CEngine6UnloadEv", mfunc_ptr_cast(&CEngine::Unload_noVirt) }, - { 0x01DA1CA0, "_ZN7CEngine4LoadEbPcS0_", mfunc_ptr_cast(&CEngine::Load_noVirt) }, - { 0x01DA1CF0, "_ZN7CEngine5FrameEv", mfunc_ptr_cast(&CEngine::Frame_noVirt) }, - { 0x01DA1DD0, "_ZN7CEngine11SetSubStateEi", mfunc_ptr_cast(&CEngine::SetSubState_noVirt) }, - { 0x01DA1DF0, "_ZN7CEngine8SetStateEi", mfunc_ptr_cast(&CEngine::SetState_noVirt) }, - { 0x01DA1E10, "_ZN7CEngine8GetStateEv", mfunc_ptr_cast(&CEngine::GetState_noVirt) }, - { 0x01DA1E20, "_ZN7CEngine11GetSubStateEv", mfunc_ptr_cast(&CEngine::GetSubState_noVirt) }, - { 0x01DA1E30, "_ZN7CEngine12GetFrameTimeEv", mfunc_ptr_cast(&CEngine::GetFrameTime_noVirt) }, - { 0x01DA1E40, "_ZN7CEngine10GetCurTimeEv", mfunc_ptr_cast(&CEngine::GetCurTime_noVirt) }, - { 0x01DA1E50, "_ZN7CEngine13TrapKey_EventEib", mfunc_ptr_cast(&CEngine::TrapKey_Event_noVirt) }, - { 0x01DA1E90, "_ZN7CEngine15TrapMouse_EventEib", mfunc_ptr_cast(&CEngine::TrapMouse_Event_noVirt) }, - { 0x01DA1ED0, "_ZN7CEngine13StartTrapModeEv", mfunc_ptr_cast(&CEngine::StartTrapMode_noVirt) }, - { 0x01DA1EE0, "_ZN7CEngine10IsTrappingEv", mfunc_ptr_cast(&CEngine::IsTrapping_noVirt) }, - { 0x01DA1EF0, "_ZN7CEngine17CheckDoneTrappingERiS0_", mfunc_ptr_cast(&CEngine::CheckDoneTrapping_noVirt) }, - { 0x01DA1F30, "_ZN7CEngine11SetQuittingEi", mfunc_ptr_cast(&CEngine::SetQuitting_noVirt) }, - { 0x01DA1F40, "_ZN7CEngine11GetQuittingEv", mfunc_ptr_cast(&CEngine::GetQuitting_noVirt) }, - -#endif // Sys_engine - -#ifndef Sys_linuxwind - // Disable/enable all at once! - - { 0x01DA5A10, "_ZN5CGame4InitEPv", mfunc_ptr_cast(&CGame::Init_noVirt) }, - { 0x01DA5A20, "_ZN5CGame8ShutdownEv", mfunc_ptr_cast(&CGame::Shutdown_noVirt) }, - { 0x01DA5760, "_ZN5CGame16CreateGameWindowEv", mfunc_ptr_cast(&CGame::CreateGameWindow_noVirt) }, - { 0x01DA4B20, "_ZN5CGame15SleepUntilInputEi", mfunc_ptr_cast(&CGame::SleepUntilInput_noVirt) }, - { 0x01DA5A40, "_ZN5CGame13GetMainWindowEv", mfunc_ptr_cast(&CGame::GetMainWindow_noVirt) }, - { 0x01DA5A50, "_ZN5CGame20GetMainWindowAddressEv", mfunc_ptr_cast(&CGame::GetMainWindowAddress_noVirt) }, - { 0x01DA5A60, "_ZN5CGame11SetWindowXYEii", mfunc_ptr_cast(&CGame::SetWindowXY_noVirt) }, - { 0x01DA5A80, "_ZN5CGame13SetWindowSizeEii", mfunc_ptr_cast(&CGame::SetWindowSize_noVirt) }, - { 0x01DA5B00, "_ZN5CGame13GetWindowRectEPiS0_S0_S0_", mfunc_ptr_cast(&CGame::GetWindowRect_noVirt) }, - { 0x01DA5B40, "_ZN5CGame11IsActiveAppEv", mfunc_ptr_cast(&CGame::IsActiveApp_noVirt) }, - { 0x01DA5B60, "_ZN5CGame13IsMultiplayerEv", mfunc_ptr_cast(&CGame::IsMultiplayer_noVirt) }, - { 0x01DA5BB0, "_ZN5CGame17PlayStartupVideosEv", mfunc_ptr_cast(&CGame::PlayStartupVideos_noVirt) }, - { 0x01DA5BC0, "_ZN5CGame14PlayAVIAndWaitEPKc", mfunc_ptr_cast(&CGame::PlayAVIAndWait_noVirt) }, - { 0x01DA5B70, "_ZN5CGame16SetCursorVisibleEb", mfunc_ptr_cast(&CGame::SetCursorVisible_noVirt) }, - -#endif //Sys_linuxwind - - { NULL, NULL, NULL }, -}; - - -AddressRef g_FunctionRefs[] = -{ -#ifndef Function_References_region - - { 0x01D4D990, "CheckIP", (size_t)&pCheckIP }, - - // Find C STD functions - { 0x01E000AE, "time", 0 }, - { 0x01E0008C, "rand", 0 }, - { 0x01E0007F, "srand", 0 }, - { 0x01E00AF1, "localtime", 0 }, - -#endif // Function_References_region - - { NULL, NULL, NULL }, -}; - -AddressRef g_DataRefs[] = -{ -#ifndef Data_References_region - - { 0x0229AE80, "pr_strings", (size_t)&ppr_strings }, - { 0x01E45C04, "gNullString", (size_t)&pgNullString }, - - { 0x01E46480, "SV_UPDATE_BACKUP", (size_t)&pSV_UPDATE_BACKUP }, - { 0x01E46484, "SV_UPDATE_MASK", (size_t)&pSV_UPDATE_MASK }, - - - { 0x021D3E80, "gGlobalVariables", (size_t)&pgGlobalVariables }, - { 0x021D3DE0, "svs", (size_t)&psvs }, - { 0x021D4960, "sv", (size_t)&psv }, - { 0x0208F788, "gPacketSuppressed", (size_t)&pgPacketSuppressed }, - { 0x01E45C08, "giNextUserMsg", (size_t)&pgiNextUserMsg }, - { 0x0208F7A4, "hashstrings_collisions", (size_t)&phashstrings_collisions }, - - { 0x0208F76C, "g_pplayerdelta", (size_t)&pg_pplayerdelta }, - { 0x0208F770, "g_pentitydelta", (size_t)&pg_pentitydelta }, - { 0x0208F774, "g_pcustomentitydelta", (size_t)&pg_pcustomentitydelta }, - { 0x0208F778, "g_pclientdelta", (size_t)&pg_pclientdelta }, - { 0x0208F77C, "g_pweapondelta", (size_t)&pg_pweapondelta }, - - { 0x021C2B60, "localinfo", (size_t)&plocalinfo }, - { 0x021D3F40, "localmodels", (size_t)&plocalmodels }, - - { 0x0221AD80, "ipfilters", (size_t)&pipfilters }, - { 0x021D4940, "numipfilters", (size_t)&pnumipfilters }, - { 0x0229B6C0, "userfilters", (size_t)&puserfilters }, - { 0x0208F798, "numuserfilters", (size_t)&pnumuserfilters }, - - { 0x01E45F84, "sv_lan", (size_t)&psv_lan }, - { 0x01E45FAC, "sv_lan_rate", (size_t)&psv_lan_rate }, - { 0x01E45E8C, "sv_aim", (size_t)&psv_aim }, - - { 0x021D1BC0, "sv_decalnames", (size_t)&psv_decalnames }, - { 0x0208F78C, "sv_decalnamecount", (size_t)&psv_decalnamecount }, - - { 0x01E46274, "sv_skycolor_r", (size_t)&psv_skycolor_r }, - { 0x01E46298, "sv_skycolor_g", (size_t)&psv_skycolor_g }, - { 0x01E462BC, "sv_skycolor_b", (size_t)&psv_skycolor_b }, - { 0x01E462E0, "sv_skyvec_x", (size_t)&psv_skyvec_x }, - { 0x01E46304, "sv_skyvec_y", (size_t)&psv_skyvec_y }, - { 0x01E46328, "sv_skyvec_z", (size_t)&psv_skyvec_z }, - - { 0x01E48F64, "sv_spectatormaxspeed", (size_t)&psv_spectatormaxspeed }, - { 0x01E48F90, "sv_airaccelerate", (size_t)&psv_airaccelerate }, - { 0x01E48FBC, "sv_wateraccelerate", (size_t)&psv_wateraccelerate }, - { 0x01E48FE4, "sv_waterfriction", (size_t)&psv_waterfriction }, - { 0x01E49008, "sv_zmax", (size_t)&psv_zmax }, - { 0x01E4902C, "sv_wateramp", (size_t)&psv_wateramp }, - { 0x01E49054, "sv_skyname", (size_t)&psv_skyname }, - { 0x01E46034, "mapcyclefile", (size_t)&pmapcyclefile }, - { 0x01E46060, "motdfile", (size_t)&pmotdfile }, - { 0x01E46090, "servercfgfile", (size_t)&pservercfgfile }, - { 0x01E460F0, "lservercfgfile", (size_t)&plservercfgfile }, - { 0x01E46114, "logsdir", (size_t)&plogsdir }, - { 0x01E46144, "bannedcfgfile", (size_t)&pbannedcfgfile }, - - - { 0x0208F790, "sv_gpNewUserMsgs", (size_t)&psv_gpNewUserMsgs }, - { 0x0208F794, "sv_gpUserMsgs", (size_t)&psv_gpUserMsgs }, - - { 0x0239BCE0, "g_svmove", (size_t)&pg_svmove }, - - { 0x0208F760, "sv_lastnum", (size_t)&psv_lastnum }, - { 0x02089220, "g_sv_instance_baselines", (size_t)&pg_sv_instance_baselines }, - { 0x0208F764, "g_bOutOfDateRestart", (size_t)&pg_bOutOfDateRestart }, - { 0x01E45C00, "g_userid", (size_t)&pg_userid }, - - { 0x0208F768, "g_sv_delta", (size_t)&pg_sv_delta }, - { 0x0208F780, "g_peventdelta", (size_t)&pg_peventdelta }, - - { 0x01E45C1C, "rcon_password", (size_t)&prcon_password }, - { 0x01E45C48, "sv_enableoldqueries", (size_t)&psv_enableoldqueries }, - - { 0x01E45C74, "sv_instancedbaseline", (size_t)&psv_instancedbaseline }, - { 0x01E45C94, "sv_contact", (size_t)&psv_contact }, - { 0x01E45CC4, "sv_maxupdaterate", (size_t)&psv_maxupdaterate }, - { 0x01E45CF4, "sv_minupdaterate", (size_t)&psv_minupdaterate }, - { 0x01E45D18, "sv_filterban", (size_t)&psv_filterban }, - { 0x01E45D3C, "sv_minrate", (size_t)&psv_minrate }, - { 0x01E45D60, "sv_maxrate", (size_t)&psv_maxrate }, - { 0x01E45D84, "sv_logrelay", (size_t)&psv_logrelay }, - - { 0x01E45DD0, "violence_hblood", (size_t)&pviolence_hblood }, - { 0x01E45DF8, "violence_ablood", (size_t)&pviolence_ablood }, - { 0x01E45E20, "violence_hgibs", (size_t)&pviolence_hgibs }, - { 0x01E45E48, "violence_agibs", (size_t)&pviolence_agibs }, - { 0x01E45E6C, "sv_newunit", (size_t)&psv_newunit }, - - { 0x01E45ED8, "sv_clienttrace", (size_t)&psv_clienttrace }, - { 0x01E45EFC, "sv_timeout", (size_t)&psv_timeout }, - { 0x01E45F24, "sv_failuretime", (size_t)&psv_failuretime }, - - { 0x01E45F44, "sv_cheats", (size_t)&psv_cheats }, - { 0x01E45F64, "sv_password", (size_t)&psv_password }, - { 0x01E45FD0, "sv_proxies", (size_t)&psv_proxies }, - { 0x01E46000, "sv_outofdatetime", (size_t)&psv_outofdatetime }, - - { 0x01E460B8, "mapchangecfgfile", (size_t)&pmapchangecfgfile }, - - { 0x021D1BA0, "allow_cheats", (size_t)&pallow_cheats }, - - { 0x01E455A8, "mp_logecho", (size_t)&pmp_logecho }, - { 0x01E45584, "mp_logfile", (size_t)&pmp_logfile }, - - { 0x01E4616C, "sv_allow_download", (size_t)&psv_allow_download }, - { 0x01E46190, "sv_send_logos", (size_t)&psv_send_logos }, - { 0x01E461B8, "sv_send_resources", (size_t)&psv_send_resources }, - - { 0x01E455FC, "sv_log_singleplayer", (size_t)&psv_log_singleplayer }, - { 0x01E45620, "sv_logsecret", (size_t)&psv_logsecret }, - { 0x01E455D0, "sv_log_onefile", (size_t)&psv_log_onefile }, - { 0x01E461DC, "sv_logbans", (size_t)&psv_logbans }, - { 0x01E46204, "sv_allow_upload", (size_t)&psv_allow_upload }, - { 0x01E4622C, "sv_max_upload", (size_t)&psv_max_upload }, - { 0x01E46250, "hpk_maxsize", (size_t)&phpk_maxsize }, - { 0x01E46358, "sv_visiblemaxplayers", (size_t)&psv_visiblemaxplayers }, - - { 0x01E46380, "max_queries_sec", (size_t)&pmax_queries_sec }, - { 0x01E463B0, "max_queries_sec_global", (size_t)&pmax_queries_sec_global }, - { 0x01E463DC, "max_queries_window", (size_t)&pmax_queries_window }, - - { 0x01E46400, "sv_logblocks", (size_t)&psv_logblocks }, - { 0x01E46424, "sv_downloadurl", (size_t)&psv_downloadurl }, - { 0x01E4644C, "sv_allow_dlfile", (size_t)&psv_allow_dlfile }, - { 0x01E4646C, "sv_version", (size_t)&psv_version }, - - { 0x0229B2A0, "sv_playermodel", (size_t)&psv_playermodel }, - - { 0x026EB5E0, "cls", (size_t)&pcls }, - { 0x026F1DE0, "cl", (size_t)&pcl }, - { 0x01FED50C, "key_dest", (size_t)&pkey_dest }, - - { 0x0269BB00, "g_clmove", (size_t)&pg_clmove }, - { 0x028A1454, "cl_inmovie", (size_t)&pcl_inmovie }, - - { 0x01E2F0F8, "cl_name", (size_t)&pcl_name }, - { 0x01E2F1B4, "rate", (size_t)&prate }, - { 0x01E33D6C, "console", (size_t)&pconsole }, - - { 0x01E39FF4, "host_name", (size_t)&phost_name }, - { 0x01E3A040, "host_speeds", (size_t)&phost_speeds }, - { 0x01E3A064, "host_profile", (size_t)&phost_profile }, - { 0x01E3A084, "developer", (size_t)&pdeveloper }, - { 0x01E3A0AC, "host_limitlocal", (size_t)&phost_limitlocal }, - { 0x01E3A0C8, "skill", (size_t)&pskill }, - { 0x01E3A0EC, "deathmatch", (size_t)&pdeathmatch }, - { 0x01E3A108, "coop", (size_t)&pcoop }, - { 0x0266AFA0, "realtime", (size_t)&prealtime }, - { 0x01FED0C0, "rolling_fps", (size_t)&prolling_fps }, - - { 0x0266AF20, "host_parms", (size_t)&phost_parms }, - { 0x01FED0B4, "host_initialized", (size_t)&phost_initialized }, - { 0x0266AEC8, "host_frametime", (size_t)&phost_frametime }, - - { 0x0266AED0, "host_framecount", (size_t)&phost_framecount }, - - { 0x0266AEDC, "host_client", (size_t)&phost_client }, - { 0x01FED0B8, "gfNoMasterServer", (size_t)&pgfNoMasterServer }, - - { 0x0266AF38, "oldrealtime", (size_t)&poldrealtime }, - { 0x0266AEC4, "host_hunklevel", (size_t)&phost_hunklevel }, - { 0x0266AF60, "host_abortserver", (size_t)&phost_abortserver }, - { 0x0266AEE0, "host_enddemo", (size_t)&phost_enddemo }, - - { 0x0266AED4, "host_basepal", (size_t)&phost_basepal }, - - { 0x01FD9778, "bfread", (size_t)&pbfread }, - { 0x01FD9790, "bfwrite", (size_t)&pbfwrite }, - { 0x02699D48, "msg_readcount", (size_t)&pmsg_readcount }, - { 0x02699D4C, "msg_badread", (size_t)&pmsg_badread }, - - { 0x01FEB260, "decal_wad", (size_t)&pdecal_wad }, - { 0x01FEB264, "menu_wad", (size_t)&pmenu_wad }, - { 0x0266D440, "szCustName", (size_t)&pszCustName }, - { 0x0266B440, "decal_names", (size_t)&pdecal_names }, - { 0x01FEB268, "m_bDrawInitialized", (size_t)&pm_bDrawInitialized }, - { 0x01FEB25C, "gfCustomBuild", (size_t)&pgfCustomBuild }, - - { 0x01FEB26C, "g_defs", (size_t)&pg_defs }, - { 0x01FEB270, "g_encoders", (size_t)&pg_encoders }, - { 0x01FEB274, "g_deltaregistry", (size_t)&pg_deltaregistry }, - - { 0x021B97E0, "gNetworkTextMessageBuffer", (size_t)&pgNetworkTextMessageBuffer }, - { 0x021B9FE0, "gMessageParms", (size_t)&pgMessageParms }, - { 0x02095C8C, "gMessageTable", (size_t)&pgMessageTable }, - { 0x02095C90, "gMessageTableCount", (size_t)&pgMessageTableCount }, - - { 0x01E4CE10, "gNetworkMessageNames", (size_t)&pgNetworkMessageNames }, - { 0x01E4CE30, "gNetworkTextMessage", (size_t)&pgNetworkTextMessage }, - - { 0x021B61C4, "hunk_base", (size_t)&phunk_base }, - { 0x021B61C8, "hunk_tempactive", (size_t)&phunk_tempactive }, - { 0x021B61D0, "hunk_low_used", (size_t)&phunk_low_used }, - { 0x021B61D4, "hunk_size", (size_t)&phunk_size }, - { 0x021B61D8, "hunk_high_used", (size_t)&phunk_high_used }, - { 0x021B61E0, "cache_head", (size_t)&pcache_head }, - { 0x021B6238, "hunk_tempmark", (size_t)&phunk_tempmark }, - { 0x01E4DEC0, "mem_dbgfile", (size_t)&pmem_dbgfile }, - { 0x021B61CC, "mainzone", (size_t)&pmainzone }, - { 0x0266AEC0, "current_skill", (size_t)&pcurrent_skill }, - { 0x01FED1E0, "g_careerState", (size_t)&pg_careerState }, - { 0x01FED1D8, "gHostSpawnCount", (size_t)&pgHostSpawnCount }, - { 0x01E3A960, "g_pSaveGameCommentFunc", (size_t)&pg_pSaveGameCommentFunc }, - { 0x01E5C834, "g_LastScreenUpdateTime", (size_t)&pg_LastScreenUpdateTime }, - { 0x023FECB4, "scr_skipupdate", (size_t)&pscr_skipupdate }, - { 0x023FF0C0, "scr_centertime_off", (size_t)&pscr_centertime_off }, - - { 0x02699460, "serverinfo", (size_t)&pserverinfo }, - { 0x026995EC, "com_argc", (size_t)&pcom_argc }, - { 0x02699708, "com_argv", (size_t)&pcom_argv }, - { 0x02699840, "com_token", (size_t)&pcom_token }, - { 0x01FE1FA0, "com_ignorecolons", (size_t)&pcom_ignorecolons }, - { 0x01FE1FA4, "s_com_token_unget", (size_t)&ps_com_token_unget }, - { 0x02699600, "com_clientfallback", (size_t)&pcom_clientfallback }, - { 0x02699720, "com_gamedir", (size_t)&pcom_gamedir }, - { 0x02699C40, "com_cmdline", (size_t)&pcom_cmdline }, - - { 0x02699580, "gpszVersionString", (size_t)&pgpszVersionString }, - { 0x026995C0, "gpszProductString", (size_t)&pgpszProductString }, - - { 0x02699D44, "bigendien", (size_t)&pbigendien }, - { 0x026995E8, "BigShort", (size_t)&pBigShort }, - { 0x026995E0, "LittleShort", (size_t)&pLittleShort }, - { 0x0269970C, "BigLong", (size_t)&pBigLong }, - { 0x02699710, "LittleLong", (size_t)&pLittleLong }, - { 0x026995A0, "BigFloat", (size_t)&pBigFloat }, - { 0x02699560, "LittleFloat", (size_t)&pLittleFloat }, - - { 0x01FD3420, "cmd_argc", (size_t)&pcmd_argc }, - { 0x01FD3428, "cmd_argv", (size_t)&pcmd_argv }, - { 0x01FD366C, "cmd_args", (size_t)&pcmd_args }, - { 0x02699D7C, "cmd_source", (size_t)&pcmd_source }, - { 0x02699D74, "cmd_wait", (size_t)&pcmd_wait }, - { 0x01FD3670, "cmd_functions", (size_t)&pcmd_functions }, - { 0x02699D60, "cmd_text", (size_t)&pcmd_text }, - { 0x02699D84, "cmd_alias", (size_t)&pcmd_alias }, - - { 0x01FE501C, "cvar_vars", (size_t)&pcvar_vars }, - - { 0x026995E4, "loadcache", (size_t)&ploadcache }, - { 0x02699704, "loadbuf", (size_t)&ploadbuf }, - { 0x02699D40, "loadsize", (size_t)&ploadsize }, - - { 0x01FEC4C8, "g_fallbackLocalizationFiles", (size_t)&pg_fallbackLocalizationFiles }, - { 0x01FEC4E0, "s_pBaseDir", (size_t)&ps_pBaseDir }, - - { 0x01FEC6E8, "bLowViolenceBuild", (size_t)&pbLowViolenceBuild }, - - { 0x01FEC6EC, "g_pFileSystem", (size_t)&pg_pFileSystem }, - { 0x01FEC6E0, "g_pFileSystemModule", (size_t)&pg_pFileSystemModule }, - { 0x01FEC6E4, "g_FileSystemFactory", (size_t)&pg_FileSystemFactory }, - - { 0x01E4AAC0, "g_hfind", (size_t)&pg_hfind }, - { 0x01E4AAC8, "g_engfuncsExportedToDlls", (size_t)&pg_engfuncsExportedToDlls }, - - { 0x021C2260, "gszDisconnectReason", (size_t)&pgszDisconnectReason }, - { 0x021C27C0, "gszExtendedDisconnectReason", (size_t)&pgszExtendedDisconnectReason }, - { 0x02090C64, "gfExtendedError", (size_t)&pgfExtendedError }, - { 0x021C28F8, "g_bIsDedicatedServer", (size_t)&pg_bIsDedicatedServer }, - - { 0x021C2248, "giSubState", (size_t)&pgiSubState }, - { 0x021C2448, "giActive", (size_t)&pgiActive }, - { 0x02090C60, "giStateInfo", (size_t)&pgiStateInfo }, - - { 0x021C2380, "gEntityInterface", (size_t)&pgEntityInterface }, - { 0x021C28E0, "gNewDLLFunctions", (size_t)&pgNewDLLFunctions }, - { 0x01FF0638, "g_modfuncs", (size_t)&pg_modfuncs }, - - { 0x021C2480, "g_rgextdll", (size_t)&pg_rgextdll }, - { 0x02090C94, "g_iextdllMac", (size_t)&pg_iextdllMac }, - { 0x021C2900, "gmodinfo", (size_t)&pgmodinfo }, - { 0x02090C90, "gfBackground", (size_t)&pgfBackground }, - - - { 0x02699454, "con_debuglog", (size_t)&pcon_debuglog }, - { 0x02090C78, "g_bPrintingKeepAliveDots", (size_t)&pg_bPrintingKeepAliveDots }, - { 0x02090C80, "Launcher_ConsolePrintf", (size_t)&pLauncher_ConsolePrintf }, - - { 0x01E42EC4, "registry", (size_t)&pregistry }, - - { 0x0239B740, "outputbuf", (size_t)&poutputbuf }, - { 0x021CAB94, "sv_redirected", (size_t)&psv_redirected }, - { 0x021CAB80, "sv_redirectto", (size_t)&psv_redirectto }, - - { 0x01E464A0, "sv_rcon_minfailures", (size_t)&psv_rcon_minfailures }, - { 0x01E464CC, "sv_rcon_maxfailures", (size_t)&psv_rcon_maxfailures }, - { 0x01E464FC, "sv_rcon_minfailuretime", (size_t)&psv_rcon_minfailuretime }, - { 0x01E46528, "sv_rcon_banpenalty", (size_t)&psv_rcon_banpenalty }, - { 0x0208E828, "g_rgRconFailures", (size_t)&pg_rgRconFailures }, - - { 0x01E42FF8, "scr_downloading", (size_t)&pscr_downloading }, -#ifndef REHLDS_FIXES - { 0x0208F7B8, "g_bCS_CZ_Flags_Initialized", (size_t)&pg_bCS_CZ_Flags_Initialized }, - { 0x0208F7AC, "g_bIsCZero", (size_t)&pg_bIsCZero }, - { 0x0208F7B4, "g_bIsCZeroRitual", (size_t)&pg_bIsCZeroRitual }, - { 0x0208F7B0, "g_bIsTerrorStrike", (size_t)&pg_bIsTerrorStrike }, - { 0x0208F7BC, "g_bIsTFC", (size_t)&pg_bIsTFC }, - { 0x0208F7C0, "g_bIsHL1", (size_t)&pg_bIsHL1 }, - { 0x0208F7A8, "g_bIsCStrike", (size_t)&pg_bIsCStrike }, -#endif - { 0x01FD3E80, "gPAS", (size_t)&pgPAS }, - { 0x01FD3E84, "gPVS", (size_t)&pgPVS }, - { 0x01FD3A78, "gPVSRowBytes", (size_t)&pgPVSRowBytes }, - { 0x01FD3A80, "mod_novis", (size_t)&pmod_novis }, - - { 0x0229AE84, "fatbytes", (size_t)&pfatbytes }, - { 0x0229B2C0, "fatpvs", (size_t)&pfatpvs }, - { 0x0229B2A4, "fatpasbytes", (size_t)&pfatpasbytes }, - { 0x0229AEA0, "fatpas", (size_t)&pfatpas }, - - { 0x0208FAB8, "s_Steam3Server", (size_t)&ps_Steam3Server }, - { 0x0208FA58, "s_Steam3Client", (size_t)&ps_Steam3Client }, - - { 0x01E39F14, "sys_ticrate", (size_t)&psys_ticrate }, - { 0x01E39F3C, "sys_timescale", (size_t)&psys_timescale }, - { 0x01E39F60, "fps_max", (size_t)&pfps_max }, - { 0x01E39F84, "host_killtime", (size_t)&phost_killtime }, - { 0x01E39FA4, "sv_stats", (size_t)&psv_stats }, - { 0x01E39FC8, "fps_override", (size_t)&pfps_override }, - { 0x01E3A01C, "host_framerate", (size_t)&phost_framerate }, - { 0x01E3A128, "pausable", (size_t)&ppausable }, - - { 0x01E43F6C, "suitvolume", (size_t)&psuitvolume }, - - { 0x0208FAC0, "truepositions", (size_t)&ptruepositions }, - { 0x021C2B44, "sv_player", (size_t)&psv_player }, - { 0x01E4A328, "clcommands", (size_t)&pclcommands }, - { 0x0209064C, "g_balreadymoved", (size_t)&pg_balreadymoved }, - { 0x01E4A658, "sv_clcfuncs", (size_t)&psv_clcfuncs }, - { 0x020905C0, "s_LastFullUpdate", (size_t)&ps_LastFullUpdate }, - - { 0x01E4A3E0, "sv_edgefriction", (size_t)&psv_edgefriction }, - { 0x01E4A404, "sv_maxspeed", (size_t)&psv_maxspeed }, - { 0x01E4A42C, "sv_accelerate", (size_t)&psv_accelerate }, - { 0x01E4A3BC, "sv_footsteps", (size_t)&psv_footsteps }, - { 0x01E4A454, "sv_rollspeed", (size_t)&psv_rollspeed }, - { 0x01E4A47C, "sv_rollangle", (size_t)&psv_rollangle }, - - { 0x01E4A49C, "sv_unlag", (size_t)&psv_unlag }, - { 0x01E4A4C0, "sv_maxunlag", (size_t)&psv_maxunlag }, - { 0x01E4A4E8, "sv_unlagpush", (size_t)&psv_unlagpush }, - { 0x01E4A510, "sv_unlagsamples", (size_t)&psv_unlagsamples }, - { 0x01E4A398, "mp_consistency", (size_t)&pmp_consistency }, - { 0x01E4A568, "sv_voiceenable", (size_t)&psv_voiceenable }, - - { 0x02090648, "nofind", (size_t)&pnofind }, - - { 0x01E3F7F4, "pm_showclip", (size_t)&ppm_showclip }, - { 0x01E3F808, "player_mins", (size_t)&pplayer_mins }, - { 0x01E3F838, "player_maxs", (size_t)&pplayer_maxs }, - { 0x02004308, "pmove", (size_t)&ppmove }, - { 0x025E3F00, "movevars", (size_t)&pmovevars }, - - { 0x01FED51C, "vec3_origin", (size_t)&pvec3_origin }, - - { 0x02004980, "gMsgData", (size_t)&pgMsgData }, - { 0x01E3F9AC, "gMsgBuffer", (size_t)&pgMsgBuffer }, - { 0x02004B80, "gMsgEntity", (size_t)&pgMsgEntity }, - { 0x02004B84, "gMsgDest", (size_t)&pgMsgDest }, - { 0x02004B88, "gMsgType", (size_t)&pgMsgType }, - { 0x02004B8C, "gMsgStarted", (size_t)&pgMsgStarted }, - { 0x020043A8, "gMsgOrigin", (size_t)&pgMsgOrigin }, - { 0x02004B90, "idum", (size_t)&pidum }, - { 0x02004B9C, "g_groupop", (size_t)&pg_groupop }, - { 0x02004B98, "g_groupmask", (size_t)&pg_groupmask }, - { 0x025E39E0, "checkpvs", (size_t)&pcheckpvs }, - { 0x025E3DE0, "c_invis", (size_t)&pc_invis }, - { 0x025E39CC, "c_notvis", (size_t)&pc_notvis }, - - { 0x0208F7E0, "vec_origin", (size_t)&pvec_origin }, - - { 0x025DFD94, "r_visframecount", (size_t)&pr_visframecount }, - - { 0x02052A48, "cache_hull_hitgroup", (size_t)&pcache_hull_hitgroup }, - { 0x0206FB60, "cache_hull", (size_t)&pcache_hull }, - { 0x0201CDC8, "cache_planes", (size_t)&pcache_planes }, - - { 0x0206FB50, "pstudiohdr", (size_t)&ppstudiohdr }, - { 0x0200A398, "studio_hull", (size_t)&pstudio_hull }, - { 0x02052C48, "studio_hull_hitgroup", (size_t)&pstudio_hull_hitgroup }, - { 0x0200C998, "studio_planes", (size_t)&pstudio_planes }, - { 0x02052E48, "studio_clipnodes", (size_t)&pstudio_clipnodes }, - { 0x0206E908, "rgStudioCache", (size_t)&prgStudioCache }, - { 0x0206FB54, "r_cachecurrent", (size_t)&pr_cachecurrent }, - { 0x02016DC4, "nCurrentHull", (size_t)&pnCurrentHull }, - { 0x0200A384, "nCurrentPlane", (size_t)&pnCurrentPlane }, - { 0x025DD0E0, "bonetransform", (size_t)&pbonetransform }, - { 0x01E42284, "r_cachestudio", (size_t)&pr_cachestudio }, - { 0x01E424E8, "g_pSvBlendingAPI", (size_t)&pg_pSvBlendingAPI }, - { 0x01E424E0, "svBlending", (size_t)&psvBlending }, - { 0x01E424D0, "server_studio_api", (size_t)&pserver_studio_api }, - { 0x025DEEE0, "rotationmatrix", (size_t)&protationmatrix }, - - { 0x021B1568, "box_hull", (size_t)&pbox_hull, 1 }, - { 0x021B1540, "beam_hull", (size_t)&pbeam_hull }, - { 0x021B1590, "box_clipnodes", (size_t)&pbox_clipnodes, 1 }, - { 0x021B15C0, "box_planes", (size_t)&pbox_planes, 1 }, - { 0x021B14C8, "beam_planes", (size_t)&pbeam_planes }, - { 0x021B6240, "sv_areanodes", (size_t)&psv_areanodes }, - { 0x021B6640, "sv_numareanodes", (size_t)&psv_numareanodes }, - - - { 0x02004310, "g_contentsresult", (size_t)&pg_contentsresult }, - { 0x025E3E00, "box_hull", (size_t)&pbox_hull_0, 2 }, - { 0x025E3E40, "box_clipnodes", (size_t)&pbox_clipnodes_0, 2 }, - { 0x025E3E80, "box_planes", (size_t)&pbox_planes_0, 2 }, - - { 0x01E48EF0, "sv_maxvelocity", (size_t)&psv_maxvelocity }, - { 0x01E48EC4, "sv_gravity", (size_t)&psv_gravity }, - { 0x01E48F34, "sv_bounce", (size_t)&psv_bounce }, - { 0x01E48F14, "sv_stepsize", (size_t)&psv_stepsize }, - { 0x01E48E78, "sv_friction", (size_t)&psv_friction }, - { 0x01E48EA0, "sv_stopspeed", (size_t)&psv_stopspeed }, - - { 0x021C2B48, "g_moved_from", (size_t)&pg_moved_from }, - { 0x021C2B4C, "sv_numareanodes", (size_t)&pg_moved_edict }, - - { 0x021C2B50, "c_yes", (size_t)&pc_yes }, - { 0x021C2B54, "c_no", (size_t)&pc_no }, - - { 0x020042AC, "net_thread_initialized", (size_t)&pnet_thread_initialized }, - { 0x01E3E8DC, "net_address", (size_t)&pnet_address }, - { 0x01E3E900, "ipname", (size_t)&pipname }, - { 0x01E3E968, "defport", (size_t)&pdefport }, - { 0x01E3E98C, "ip_clientport", (size_t)&pip_clientport }, - { 0x01E3E9B4, "clientport", (size_t)&pclientport }, - { 0x01E3EB34, "net_sleepforever", (size_t)&pnet_sleepforever }, - { 0x01FF2B60, "loopbacks", (size_t)&ploopbacks }, - { 0x01FF2AE8, "g_pLagData", (size_t)&pg_pLagData }, - { 0x020042D8, "gFakeLag", (size_t)&pgFakeLag }, - { 0x020042FC, "net_configured", (size_t)&pnet_configured }, - { 0x025F4020, "net_message", (size_t)&pnet_message }, - { 0x025F4040, "net_local_adr", (size_t)&pnet_local_adr }, - { 0x02604060, "net_from", (size_t)&pnet_from }, - { 0x020042BC, "noip", (size_t)&pnoip }, - { 0x01E3E9D8, "clockwindow", (size_t)&pclockwindow }, - - { 0x020042B0, "use_thread", (size_t)&puse_thread }, - - { 0x025F4000, "in_message", (size_t)&pin_message }, - { 0x025F3FC0, "in_from", (size_t)&pin_from }, - - { 0x020042C0, "ip_sockets", (size_t)&pip_sockets }, - { 0x01E3E924, "iphostport", (size_t)&piphostport }, - { 0x01E3E944, "hostport", (size_t)&phostport }, - { 0x01E3EA04, "multicastport", (size_t)&pmulticastport }, - { 0x01E3EA70, "fakelag", (size_t)&pfakelag }, - { 0x01E3EA94, "fakeloss", (size_t)&pfakeloss }, - - { 0x01E3EAB4, "net_graph", (size_t)&pnet_graph }, - { 0x01E3EADC, "net_graphwidth", (size_t)&pnet_graphwidth }, - { 0x01E3EAFC, "net_scale", (size_t)&pnet_scale }, - { 0x01E3EB20, "net_graphpos", (size_t)&pnet_graphpos }, - { 0x025F4060, "net_message_buffer", (size_t)&pnet_message_buffer }, - { 0x025E3FC0, "in_message_buf", (size_t)&pin_message_buf }, - -#ifdef _WIN32 - { 0x025F3FE0, "net_local_ipx_adr", (size_t)&pnet_local_ipx_adr }, - { 0x020042B8, "noipx", (size_t)&pnoipx }, - { 0x01E3EA28, "ipx_hostport", (size_t)&pipx_hostport }, - { 0x01E3EA50, "ipx_clientport", (size_t)&pipx_clientport }, - { 0x020042CC, "ipx_sockets", (size_t)&pipx_sockets }, -#endif // _WIN32 - { 0x02604080, "gNetSplit", (size_t)&pgNetSplit }, - { 0x020042E8, "messages", (size_t)&pmessages }, - { 0x020042F4, "normalqueue", (size_t)&pnormalqueue }, - - { 0x02605040, "gDownloadFile", (size_t)&pgDownloadFile }, - - { 0x02605140, "net_drop", (size_t)&pnet_drop }, - { 0x01E3E00C, "net_log", (size_t)&pnet_log }, - { 0x01E3E034, "net_showpackets", (size_t)&pnet_showpackets }, - { 0x01E3E058, "net_showdrop", (size_t)&pnet_showdrop }, - { 0x01E3E080, "net_drawslider", (size_t)&pnet_drawslider }, - { 0x01E3E0A4, "net_chokeloopback", (size_t)&pnet_chokeloopback }, - { 0x01E3E0D8, "sv_filetransfercompression", (size_t)&psv_filetransfercompression }, - { 0x01E3E110, "sv_filetransfermaxsize", (size_t)&psv_filetransfermaxsize }, - -#ifdef _WIN32 - { 0x02090C88, "g_PerfCounterInitialized", (size_t)&pg_PerfCounterInitialized }, - { 0x021C2460, "g_PerfCounterMutex", (size_t)&pg_PerfCounterMutex }, - - { 0x021C2454, "g_PerfCounterShiftRightAmount", (size_t)&pg_PerfCounterShiftRightAmount }, - { 0x021C28C0, "g_PerfCounterSlice", (size_t)&pg_PerfCounterSlice }, - { 0x02090C68, "g_CurrentTime", (size_t)&pg_CurrentTime }, - { 0x02090C70, "g_StartTime", (size_t)&pg_StartTime }, - - { 0x01E4E98C, "g_FPUCW_Mask_Prec_64Bit", (size_t)&pg_FPUCW_Mask_Prec_64Bit }, - { 0x01E4E990, "g_FPUCW_Mask_Prec_64Bit_2", (size_t)&pg_FPUCW_Mask_Prec_64Bit_2 }, - { 0x01E4E988, "g_FPUCW_Mask_ZeroDiv_OFlow", (size_t)&pg_FPUCW_Mask_Round_Trunc }, - { 0x01E4E984, "g_FPUCW_Mask_OFlow", (size_t)&pg_FPUCW_Mask_Round_Up }, - - { 0x021C2244, "g_WinNTOrHigher", (size_t)&pg_WinNTOrHigher }, - { 0x020914E4, "g_bIsWin95", (size_t)&pg_bIsWin95 }, - { 0x020914E8, "g_bIsWin98", (size_t)&pg_bIsWin98 }, -#endif // _WIN32 - - { 0x02605180, "loadmodel", (size_t)&ploadmodel }, - { 0x02605160, "loadname", (size_t)&ploadname }, - { 0x026051A0, "mod_known", (size_t)&pmod_known }, - { 0x02605144, "mod_numknown", (size_t)&pmod_numknown }, - { 0x026671A0, "mod_base", (size_t)&pmod_base }, - { 0x01FF062C, "wadpath", (size_t)&pwadpath }, - { 0x01FF0630, "tested", (size_t)&ptested }, - { 0x01FF0634, "ad_enabled", (size_t)&pad_enabled }, - { 0x026671C0, "ad_wad", (size_t)&pad_wad }, - { 0x01FED528, "mod_known_info", (size_t)&pmod_known_info }, - - { 0x02095B48, "lumpinfo", (size_t)&plumpinfo }, - { 0x02095B4C, "nTexLumps", (size_t)&pnTexLumps }, - { 0x021C2040, "texfiles", (size_t)&ptexfiles }, - { 0x02095B44, "nTexFiles", (size_t)&pnTexFiles }, - { 0x021B7660, "texgammatable", (size_t)&ptexgammatable }, - { 0x025DFCE4, "r_notexture_mip", (size_t)&pr_notexture_mip }, - { 0x021C2020, "nummiptex", (size_t)&pnummiptex }, - { 0x021BA020, "miptex", (size_t)&pmiptex }, - - { 0x01E41A30, "r_wadtextures", (size_t)&pr_wadtextures }, - - { 0x01E42270, "r_dointerp", (size_t)&pr_dointerp }, - { 0x025DFE40, "r_origin", (size_t)&pr_origin }, - - { 0x01E415BC, "r_pixbytes", (size_t)&pr_pixbytes }, - { 0x01E43090, "gl_vsync", (size_t)&pgl_vsync }, - { 0x023FF0D0, "scr_con_current", (size_t)&pscr_con_current }, - - - { 0x0208F7EC, "g_ServerRemoteAccess", (size_t)&pg_ServerRemoteAccess }, - - { 0x01FED1E8, "cpuPercent", (size_t)&pcpuPercent }, - { 0x01FED1D4, "startTime", (size_t)&pstartTime }, - { 0x01FED1E4, "g_bMajorMapChange", (size_t)&pg_bMajorMapChange }, - { 0x01E3A97C, "voice_recordtofile", (size_t)&pvoice_recordtofile }, - { 0x01E3A9A8, "voice_inputfromfile", (size_t)&pvoice_inputfromfile }, - { 0x01E3B250, "gTitleComments", (size_t)&pgTitleComments }, - { 0x01E3A9D8, "gGameHeaderDescription", (size_t)&pgGameHeaderDescription }, - { 0x01E3AAA0, "gSaveHeaderDescription", (size_t)&pgSaveHeaderDescription }, - { 0x01E3ABB0, "gAdjacencyDescription", (size_t)&pgAdjacencyDescription }, - { 0x01E3AC20, "gEntityTableDescription", (size_t)&pgEntityTableDescription }, - { 0x01E3AC80, "gLightstyleDescription", (size_t)&pgLightstyleDescription }, - { 0x01E3ACB0, "gHostMap", (size_t)&pgHostMap }, - { 0x01FED208, "g_iQuitCommandIssued", (size_t)&pg_iQuitCommandIssued }, - { 0x01FED20C, "g_pPostRestartCmdLineArgs", (size_t)&pg_pPostRestartCmdLineArgs }, - - { 0x021CABA0, "g_rg_sv_challenges", (size_t)&pg_rg_sv_challenges }, - - { 0x0239BCC0, "g_svdeltacallback", (size_t)&pg_svdeltacallback }, - - { 0x01FED4D0, "_ZL11rateChecker", (size_t)&prateChecker }, - - { 0x01FEC7F4, "gp_hpak_queue", (size_t)&pgp_hpak_queue }, - { 0x01FEC7F8, "hash_pack_dir", (size_t)&phash_pack_dir }, - { 0x0266AFB0, "hash_pack_header", (size_t)&phash_pack_header }, - - { 0x020891D8, "firstLog", (size_t)&pfirstLog }, - - { 0x01E4C6C4, "game", (size_t)&pgame }, - { 0x01E4BB44, "eng", (size_t)&peng }, - { 0x021B1468, "wads", (size_t)&pwads }, - { 0x01FF06B0, "g_module", (size_t)&pg_module }, - - { 0x020914E0, "dedicated", (size_t)&pdedicated }, - { 0x020914E4, "g_bIsWin95", (size_t)&pg_bIsWin95 }, - { 0x020914E8, "g_bIsWin98", (size_t)&pg_bIsWin98 }, - { 0x020914F8, "g_flLastSteamProgressUpdateTime", (size_t)&pg_flLastSteamProgressUpdateTime }, - { 0x01E4B3E0, "szCommonPreloads", (size_t)&pszCommonPreloads }, - { 0x01E4B3F0, "szReslistsBaseDir", (size_t)&pszReslistsBaseDir }, - { 0x01E4B3FC, "szReslistsExt", (size_t)&pszReslistsExt }, - - { 0x02095C98, "g_InitTracker", (size_t)&pg_InitTracker }, - -#ifndef _WIN32 - { 0x0, "gHasMMXTechnology", (size_t)&pgHasMMXTechnology }, -#endif - -#endif // Data_References_region - - { NULL, NULL, NULL }, -}; diff --git a/rehlds/hookers/engine/hooklist.cpp b/rehlds/hookers/engine/hooklist.cpp new file mode 100644 index 0000000..426d204 --- /dev/null +++ b/rehlds/hookers/engine/hooklist.cpp @@ -0,0 +1,2431 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +// Hooks stuff +#include "hookers/hooker.cpp" + +/* + Requred hooks for runing hooker with rehlds API enabled: + Whole regions: + Common_MSG_region + Common_SZ_region + Sv_Steam3_region + + SysDll_region: + Sys_FloatTime, Sys_InitHardwareTimer + + Pr_Cmds_region: + SeedRandomNumberGenerator, ran1, fran1, RandomFloat, RandomLong, PF_GetPlayerAuthId + + Sv_Main_region: + SV_RejectConnection, SV_FilterUser, SV_CheckChallenge, SV_CheckIPRestrictions, SV_CheckIPConnectionReuse, SV_FinishCertificateCheck, SV_CheckKeyInfo + SV_CheckForDuplicateSteamID, SV_CheckForDuplicateNames, SV_CheckUserInfo, SV_ConnectClient, SVC_GetChallenge, SVC_ServiceChallenge, + SV_SetMaxclients, SV_CompareUserID, SV_GetIDString, SV_GetClientIDString +*/ + +//#define Common_MSG_region +//#define Common_SZ_region +#define Common_COM_region +#define Delta_region +#define Main_region +#define Zone_region +#define FileSystem_Internal_region +#define FileSystem_region +#define Unicode_StrTools_region +#define Cmd_region +#define Cvar_region +#define Info_region +//#define SysDll_region +#define Sys_Dll2_region +#define CModel_region +#define Model_region +#define Sv_Log_region +#define Cl_Null_region +#define Snd_Null_region +//#define Sv_Steam3_region +#define Host_region +#define Host_Cmd_region +#define Pmove_region +#define Pmovetst_region +#define Pr_Edict_region +//#define Pr_Cmds_region +#define Mathlib_region +#define World_region +#define Sv_Phys_region +#define Sv_Move_region +#define Sv_pmove_region +//#define Sv_Main_region +#define R_Studio_region +#define TraceInit_Region +#define Net_ws_region +#define Net_chan_region +#define Hashpak_region +#define Sv_user_region +#define Wad_region +#define Textures_region +#define Tmessage_region +#define Vid_null_region +#define L_studio_region +#define Crc_region +#define Sv_RemoteAccess_region +#define Com_custom +#define Sv_upld +#define Decals +#define IpratelimitWrapper_region +#define Sys_engine +#define Sys_linuxwind + +//#define Function_References_region +//#define Data_References_region + +FunctionHook g_FunctionHooks[] = +{ + // DO NOT DISABLE, other functions depends on memory allocation routines +#ifndef Mem_region + + HOOK_DEF(0x01D50AB0, Mem_Malloc), + HOOK_DEF(0x01D50AD0, Mem_ZeroMalloc), + HOOK_DEF(0x01D50B00, Mem_Realloc), + HOOK_DEF(0x01D50B20, Mem_Calloc), + HOOK_DEF(0x01D50B40, Mem_Strdup), + HOOK_DEF(0x01D50B60, Mem_Free), + +#ifdef _WIN32 + HOOK_SYMBOLDEF(0x01DFE945, "_malloca", malloc_wrapper), + HOOK_SYMBOLDEF(0x01DFEA7F, "realloc", realloc_wrapper), + HOOK_SYMBOLDEF(0x01DFE35D, "_frea", free_wrapper), + HOOK_SYMBOLDEF(0x01DFF016, "calloc", calloc_wrapper), + HOOK_SYMBOLDEF(0x01DFE957, "__nh_malloc", __nh_malloc_wrapper), +#endif //_WIN32 + +#endif // Mem_region + +#ifndef Common_MSG_region + +#ifdef Q_functions + + //HOOK_DEF(0x, Q_memset), + //HOOK_DEF(0x, Q_memcpy), + //HOOK_DEF(0x, Q_memcmp), + HOOK_DEF(0x01D28AF0, Q_strcpy), + //HOOK_DEF(0x, Q_strncpy), + HOOK_DEF(0x01D28B50, Q_strlen), + //HOOK_DEF(0x, Q_strrchr), + //HOOK_DEF(0x, Q_strcat), + //HOOK_DEF(0x, Q_strcmp), + //HOOK_DEF(0x, Q_strncmp), + //HOOK_DEF(0x, Q_strncasecmp), + //HOOK_DEF(0x, Q_strcasecmp), + //HOOK_DEF(0x, Q_stricmp), + //HOOK_DEF(0x, Q_strnicmp), + //HOOK_DEF(0x, Q_atoi), + //HOOK_DEF(0x, Q_atof), + //HOOK_DEF(0x, Q_strlwr), + //HOOK_DEF(0x, Q_FileNameCmp), + //HOOK_DEF(0x, Q_strstr), + //HOOK_DEF(0x, Q_strtoull), + +#endif // Q_functions + + HOOK_DEF(0x01D29290, MSG_WriteChar), + HOOK_DEF(0x01D292B0, MSG_WriteByte), + HOOK_DEF(0x01D292D0, MSG_WriteShort), + HOOK_DEF(0x01D292F0, MSG_WriteWord), + HOOK_DEF(0x01D29310, MSG_WriteLong), + HOOK_DEF(0x01D29340, MSG_WriteFloat), + HOOK_DEF(0x01D29370, MSG_WriteString), + HOOK_DEF(0x01D293B0, MSG_WriteBuf), + HOOK_DEF(0x01D293D0, MSG_WriteAngle), + HOOK_DEF(0x01D29420, MSG_WriteHiresAngle), + HOOK_DEF(0x01D29470, MSG_WriteUsercmd), + HOOK_DEF(0x01D294D0, MSG_WriteOneBit), + HOOK_DEF(0x01D29550, MSG_StartBitWriting), + HOOK_DEF(0x01D29590, MSG_EndBitWriting), + HOOK_DEF(0x01D295E0, MSG_WriteBits), + HOOK_DEF(0x01D29700, MSG_WriteSBits), + HOOK_DEF(0x01D29750, MSG_WriteBitString), + HOOK_DEF(0x01D29790, MSG_WriteBitData), + HOOK_DEF(0x01D297C0, MSG_WriteBitAngle), + HOOK_DEF(0x01D29850, MSG_ReadBitAngle), + HOOK_DEF(0x01D298A0, MSG_CurrentBit), + HOOK_DEF(0x01D298E0, MSG_StartBitReading), + HOOK_DEF(0x01D29930, MSG_EndBitReading), + HOOK_DEF(0x01D29970, MSG_ReadOneBit), + HOOK_DEF(0x01D29A00, MSG_ReadBits), + HOOK_DEF(0x01D29B40, MSG_ReadSBits), + HOOK_DEF(0x01D29BB0, MSG_ReadBitData), + HOOK_DEF(0x01D29C70, MSG_WriteBitCoord), + HOOK_DEF(0x01D29D50, MSG_WriteBitVec3Coord), + HOOK_DEF(0x01D29E60, MSG_WriteCoord), + HOOK_DEF(0x01D29F00, MSG_BeginReading), + HOOK_DEF(0x01D29F10, MSG_ReadChar), + HOOK_DEF(0x01D29F50, MSG_ReadByte), + HOOK_DEF(0x01D29F90, MSG_ReadShort), + HOOK_DEF(0x01D2A030, MSG_ReadLong), + HOOK_DEF(0x01D2A090, MSG_ReadFloat), + HOOK_DEF(0x01D2A0E0, MSG_ReadBuf), + HOOK_DEF(0x01D2A130, MSG_ReadString), + HOOK_DEF(0x01D2A170, MSG_ReadStringLine), + HOOK_DEF(0x01D2A210, MSG_ReadUsercmd), + HOOK_DEF(0x01D29B70, MSG_ReadBitString), // NOXREF + HOOK_DEF(0x01D29BE0, MSG_ReadBitCoord), // NOXREF + HOOK_DEF(0x01D29D00, MSG_ReadBitVec3Coord), // NOXREF + HOOK_DEF(0x01D29E30, MSG_ReadCoord), // NOXREF + HOOK_DEF(0x01D29E80, MSG_ReadVec3Coord), // NOXREF + HOOK_DEF(0x01D29EC0, MSG_WriteVec3Coord), // NOXREF + HOOK_DEF(0x01D29FE0, MSG_ReadWord), // NOXREF + HOOK_DEF(0x01D29580, MSG_IsBitWriting), // NOXREF + HOOK_DEF(0x01D298D0, MSG_IsBitReading), // NOXREF + HOOK_DEF(0x01D29B00, MSG_PeekBits), // NOXREF + HOOK_DEF(0x01D2A1B0, MSG_ReadAngle), // NOXREF + HOOK_DEF(0x01D2A1E0, MSG_ReadHiresAngle), // NOXREF + +#endif // Common_MSG_region + +#ifndef Common_SZ_region + + HOOK_DEF(0x01D2A260, SZ_Alloc), + HOOK_DEF(0x01D2A2A0, SZ_Clear), + HOOK_DEF(0x01D2A2C0, SZ_GetSpace), + HOOK_DEF(0x01D2A380, SZ_Write), + HOOK_DEF(0x01D2A3B0, SZ_Print), + +#endif // Common_SZ_region + +#ifndef Common_COM_region + + HOOK_DEF(0x01D08E50, build_number), + HOOK_DEF(0x01D289E0, Info_Serverinfo), + HOOK_DEF(0x01D28FF0, COM_Nibble), + HOOK_DEF(0x01D29030, COM_HexConvert), + HOOK_DEF(0x01D29100, COM_ExplainDisconnection), + HOOK_DEF(0x01D2A440, COM_StripExtension), + HOOK_DEF(0x01D2A4A0, COM_FileExtension), + HOOK_DEF(0x01D2A4F0, COM_FileBase), + HOOK_DEF(0x01D2A580, COM_DefaultExtension), + HOOK_DEF(0x01D2A5D0, COM_UngetToken), + HOOK_DEF(0x01D2A5E0, COM_Parse), + HOOK_DEF(0x01D2A730, COM_ParseLine), + HOOK_DEF(0x01D2A830, COM_CheckParm), + HOOK_DEF(0x01D2A880, COM_InitArgv), + HOOK_DEF(0x01D2A960, COM_Init), + HOOK_DEF(0x01D2AA00, va), + HOOK_DEF(0x01D2AB70, COM_FixSlashes), + HOOK_DEF(0x01D2AB90, COM_CreatePath), + HOOK_DEF(0x01D2ACD0, COM_FileSize), + HOOK_DEF(0x01D2AD10, COM_LoadFile), + HOOK_DEF(0x01D2AE70, COM_FreeFile), + HOOK_DEF(0x01D2AEA0, COM_CopyFileChunk), + HOOK_DEF(0x01D2B020, COM_LoadHunkFile), + HOOK_DEF(0x01D2B040, COM_LoadTempFile), + HOOK_DEF(0x01D2B060, COM_LoadCacheFile), + HOOK_DEF(0x01D2B0B0, COM_Shutdown), + HOOK_DEF(0x01D2B0E0, COM_AddDefaultDir), + HOOK_DEF(0x01D2B100, COM_StripTrailingSlash), + HOOK_DEF(0x01D2B130, COM_ParseDirectoryFromCmd), + HOOK_DEF(0x01D2B1C0, COM_SetupDirectories), + //HOOK_DEF(0x01D2B3D0, COM_CheckPrintMap), // Totally not exists on Linux (it is inlined), but present and used on Windows, anyway just commented it out + HOOK_DEF(0x01D2B250, COM_ListMaps), + HOOK_DEF(0x01D2B410, COM_Log), + HOOK_DEF(0x01D2B480, COM_LoadFileForMe), + HOOK_DEF(0x01D2B4A0, COM_CompareFileTime), + HOOK_DEF(0x01D2B500, COM_GetGameDir), + HOOK_DEF(0x01D2B530, COM_EntsForPlayerSlots), + HOOK_DEF(0x01D2B590, COM_NormalizeAngles), + HOOK_DEF(0x01D2B610, COM_Munge), + HOOK_DEF(0x01D2B6A0, COM_UnMunge), + HOOK_DEF(0x01D2B730, COM_Munge2), + HOOK_DEF(0x01D2B7C0, COM_UnMunge2), + HOOK_DEF(0x01D2B850, COM_Munge3), + HOOK_DEF(0x01D2B970, COM_GetApproxWavePlayLength), + HOOK_DEF(0x01D2B8E0, COM_UnMunge3), // NOXREF + HOOK_DEF(0x01D2B080, COM_LoadStackFile), // NOXREF + HOOK_DEF(0x01D2B0C0, COM_AddAppDirectory), // NOXREF + HOOK_DEF(0x01D2ABD0, COM_CopyFile), // NOXREF + HOOK_DEF(0x01D2AC70, COM_ExpandFilename), // NOXREF + HOOK_DEF(0x01D2AAD0, COM_WriteFile), // NOXREF + HOOK_DEF(0x01D2A7A0, COM_TokenWaiting), // NOXREF + HOOK_DEF(0x01D29170, COM_ExtendedExplainDisconnection), // NOXREF + HOOK_DEF(0x01D2A410, COM_SkipPath), // NOXREF + HOOK_DEF(0x01D2AA40, vstr), // NOXREF + HOOK_DEF(0x01D2AAA0, memsearch), // NOXREF + //HOOK_DEF(0x01D29080, COM_BinPrintf), // NOXREF + //HOOK_DEF(0x01D2AF40, COM_LoadFileLimit), // NOXREF + +#endif // Common_COM_region + +#ifndef Delta_region + + HOOK_DEF(0x01D351D0, DELTA_FindField), + HOOK_DEF(0x01D35240, DELTA_FindFieldIndex), + HOOK_DEF(0x01D352A0, DELTA_SetField), + HOOK_DEF(0x01D352C0, DELTA_UnsetField), + HOOK_DEF(0x01D352E0, DELTA_SetFieldByIndex), + HOOK_DEF(0x01D35300, DELTA_UnsetFieldByIndex), + HOOK_DEF(0x01D35320, DELTA_ClearFlags), + HOOK_DEF(0x01D35340, DELTA_TestDelta), + HOOK_DEF(0x01D355B0, DELTA_CountSendFields), + HOOK_DEF(0x01D355E0, DELTA_MarkSendFields), + HOOK_DEF(0x01D35830, DELTA_SetSendFlagBits), + HOOK_DEF(0x01D358B0, DELTA_WriteMarkedFields), + HOOK_DEF(0x01D35C10, DELTA_CheckDelta), + HOOK_DEF(0x01D35C40, DELTA_WriteDelta), + HOOK_DEF(0x01D35C80, _DELTA_WriteDelta), + HOOK_DEF(0x01D35D00, DELTA_ParseDelta), + + HOOK_DEF(0x01D36420, DELTA_AddEncoder), + HOOK_DEF(0x01D36460, DELTA_ClearEncoders), + HOOK_DEF(0x01D364A0, DELTA_LookupEncoder), + HOOK_DEF(0x01D364E0, DELTA_CountLinks), + HOOK_DEF(0x01D36500, DELTA_ReverseLinks), + HOOK_DEF(0x01D36520, DELTA_ClearLinks), + HOOK_DEF(0x01D36550, DELTA_BuildFromLinks), + HOOK_DEF(0x01D365F0, DELTA_FindOffset), + HOOK_DEF(0x01D36640, DELTA_ParseType), + HOOK_DEF(0x01D36800, DELTA_ParseField), + HOOK_DEF(0x01D36A10, DELTA_FreeDescription), + HOOK_DEF(0x01D36A50, DELTA_AddDefinition), + HOOK_DEF(0x01D36AB0, DELTA_ClearDefinitions), + HOOK_DEF(0x01D36AF0, DELTA_FindDefinition), + HOOK_DEF(0x01D36B40, DELTA_SkipDescription), + HOOK_DEF(0x01D36BA0, DELTA_ParseOneField), + HOOK_DEF(0x01D36C50, DELTA_ParseDescription), + HOOK_DEF(0x01D36EA0, DELTA_Load), + HOOK_DEF(0x01D36EF0, DELTA_RegisterDescription), + HOOK_DEF(0x01D36F30, DELTA_ClearRegistrations), + HOOK_DEF(0x01D36FC0, DELTA_ClearStats), + HOOK_DEF(0x01D36FF0, DELTA_ClearStats_f), + HOOK_DEF(0x01D36F80, DELTA_LookupRegistration), + HOOK_DEF(0x01D37020, DELTA_PrintStats), + HOOK_DEF(0x01D37090, DELTA_DumpStats_f), + HOOK_DEF(0x01D370C0, DELTA_Init), + HOOK_DEF(0x01D37160, DELTA_Shutdown), + +#endif // Delta_region + +#ifndef Sv_Main_region + + //HOOK_DEF(0x01D87E40, SV_LookupDelta), + //HOOK_DEF(0x01D87F70, SV_GatherStatistics), + //HOOK_DEF(0x01D88190, SV_DeallocateDynamicData), + //HOOK_DEF(0x01D881D0, SV_ReallocateDynamicData), + //HOOK_DEF(0x01D88250, SV_AllocClientFrames), + //HOOK_DEF(0x01D882B0, SV_IsPlayerIndex_wrapped), + //HOOK_DEF(0x01D882D0, SV_ClearPacketEntities), + //HOOK_DEF(0x01D88310, SV_AllocPacketEntities), + //HOOK_DEF(0x01D88370, SV_ClearFrames), + //HOOK_DEF(0x01D883E0, SV_Serverinfo_f), + //HOOK_DEF(0x01D884C0, SV_Localinfo_f), + //HOOK_DEF(0x01D88550, SV_User_f), + //HOOK_DEF(0x01D88640, SV_Users_f), + //HOOK_DEF(0x01D88700, SV_CountPlayers), + //HOOK_DEF(0x01D88740, SV_CountProxies), + //HOOK_DEF(0x01D88790, SV_FindModelNumbers), + //HOOK_DEF(0x01D887D0, SV_StartParticle), + //HOOK_DEF(0x01D88880, SV_StartSound), + //HOOK_DEF(0x01D88960, SV_BuildSoundMsg), + //HOOK_DEF(0x01D88BD0, SV_HashString), + //HOOK_DEF(0x01D88C10, SV_LookupSoundIndex), + //HOOK_DEF(0x01D88CD0, SV_BuildHashedSoundLookupTable), + //HOOK_DEF(0x01D88D20, SV_AddSampleToHashedLookupTable), + //HOOK_DEF(0x01D88DA0, SV_ValidClientMulticast), + //HOOK_DEF(0x01D88E40, SV_Multicast), + //HOOK_DEF(0x01D88FA0, SV_WriteMovevarsToClient), + //HOOK_DEF(0x01D89110, SV_WriteDeltaDescriptionsToClient), + //HOOK_DEF(0x01D891B0, SV_SetMoveVars), + //HOOK_DEF(0x01D892F0, SV_QueryMovevarsChanged), + //HOOK_DEF(0x01D89590, SV_SendServerinfo), + //HOOK_DEF(0x01D897C0, SV_SendResources), + //HOOK_DEF(0x01D89920, SV_WriteClientdataToMessage), + //HOOK_DEF(0x01D89BF0, SV_WriteSpawn), + //HOOK_DEF(0x01D89F10, SV_SendUserReg), + //HOOK_DEF(0x01D89F80, SV_New_f), + //HOOK_DEF(0x01D8A210, SV_SendRes_f), + //HOOK_DEF(0x01D8A2C0, SV_Spawn_f), + //HOOK_DEF(0x01D8A3F0, SV_CheckUpdateRate), + HOOK_DEF(0x01D8A510, SV_RejectConnection), + //HOOK_DEF(0x01D8A5A0, SV_RejectConnectionForPassword), + //HOOK_DEF(0x01D8A610, SV_GetFragmentSize), + HOOK_DEF(0x01D8A680, SV_FilterUser), + //HOOK_DEF(0x01D8A760, SV_CheckProtocol), + HOOK_DEF(0x01D8A7E0, SV_CheckChallenge), + HOOK_DEF(0x01D8A8D0, SV_CheckIPRestrictions), + HOOK_DEF(0x01D8A980, SV_CheckIPConnectionReuse), + HOOK_DEF(0x01D8AA40, SV_FinishCertificateCheck), + HOOK_DEF(0x01D8AB10, SV_CheckKeyInfo), + HOOK_DEF(0x01D8AC30, SV_CheckForDuplicateSteamID), + HOOK_DEF(0x01D8ACE0, SV_CheckForDuplicateNames), + HOOK_DEF(0x01D8AE10, SV_CheckUserInfo), + //HOOK_DEF(0x01D8B080, SV_FindEmptySlot), + HOOK_DEF(0x01D8B100, SV_ConnectClient), + //HOOK_DEF(0x01D8B8E0, SVC_Ping), + HOOK_DEF(0x01D8B930, SVC_GetChallenge), + HOOK_DEF(0x01D8BB20, SVC_ServiceChallenge), + //HOOK_DEF(0x01D8C260, SVC_InfoString), // NOXREF + //HOOK_DEF(0x01D8C720, SVC_Info), // NOXREF + //HOOK_DEF(0x01D8CA40, SVC_PlayerInfo), // NOXREF + //HOOK_DEF(0x01D8CBA0, SVC_RuleInfo), // NOXREF + //HOOK_DEF(0x01D8CCC0, SVC_GameDllQuery), + //HOOK_DEF(0x01D8BCB0, SV_ResetModInfo), + //HOOK_DEF(0x01D8CD70, SV_FlushRedirect), + //HOOK_DEF(0x01D8CE70, SV_BeginRedirect), + //HOOK_DEF(0x01D8CEA0, SV_EndRedirect), + //HOOK_DEF(0x01D8CEB0, SV_ResetRcon_f), + //HOOK_DEF(0x01D8CED0, SV_AddFailedRcon), + //HOOK_DEF(0x01D8D1F0, SV_CheckRconFailure), + //HOOK_DEF(0x01D8D250, SV_Rcon_Validate), + //HOOK_DEF(0x01D8D370, SV_Rcon), + //HOOK_DEF(0x01D8D560, SV_ConnectionlessPacket), + //HOOK_DEF(0x01D8D750, SV_CheckRate), + //HOOK_DEF(0x01D8D810, SV_ProcessFile), + //HOOK_DEF(0x01D8D960, SV_FilterPacket), + //HOOK_DEF(0x01D8DA30, SV_SendBan), + //HOOK_DEF(0x01D8DAB0, SV_ReadPackets), + //HOOK_DEF(0x, ntohl), + //HOOK_DEF(0x, htons), + //HOOK_DEF(0x01D8DCC0, SV_CheckTimeouts), + //HOOK_DEF(0x01D8DD50, SV_CalcPing), + //HOOK_DEF(0x01D8DE20, SV_FullClientUpdate), + //HOOK_DEF(0x01D8DEF0, SV_EmitEvents), + //HOOK_DEF(0x01D8E0F0, SV_AddToFatPVS), + //HOOK_DEF(0x01D8E1B0, SV_FatPVS), + //HOOK_DEF(0x01D8E200, SV_AddToFatPAS), + //HOOK_DEF(0x01D8E2D0, SV_FatPAS), + //HOOK_DEF(0x01D8E320, SV_PointLeafnum), + //HOOK_DEF(0x01D8E370, SV_SetCallback), + //HOOK_DEF(0x01D8E3C0, SV_SetNewInfo), + //HOOK_DEF(0x01D8E3E0, SV_WriteDeltaHeader), + //HOOK_DEF(0x01D8E4E0, SV_InvokeCallback), + //HOOK_DEF(0x01D8E520, SV_FindBestBaseline), + //HOOK_DEF(0x01D8E650, SV_CreatePacketEntities), + //HOOK_DEF(0x01D8E9A0, SV_EmitPacketEntities), + //HOOK_DEF(0x01D8E9E0, SV_ShouldUpdatePing), + //HOOK_DEF(0x01D8EA70, SV_GetNetInfo), + //HOOK_DEF(0x01D8EB00, SV_CheckVisibility), + //HOOK_DEF(0x01D8EBF0, SV_EmitPings), + //HOOK_DEF(0x01D8EC90, SV_WriteEntitiesToClient), + //HOOK_DEF(0x01D8EE90, SV_CleanupEnts), + //HOOK_DEF(0x01D8EEC0, SV_SendClientDatagram), + //HOOK_DEF(0x01D8EFC0, SV_UpdateToReliableMessages), + //HOOK_DEF(0x01D8F230, SV_SkipUpdates), + //HOOK_DEF(0x01D8F280, SV_SendClientMessages), + //HOOK_DEF(0x01D8F470, SV_ExtractFromUserinfo), + //HOOK_DEF(0x01D8F870, SV_ModelIndex), + //HOOK_DEF(0x01D8F8E0, SV_AddResource), + //HOOK_DEF(0x01D8F950, SV_CreateGenericResources), + //HOOK_DEF(0x01D8FC30, SV_CreateResourceList), + //HOOK_DEF(0x01D8FDC0, SV_ClearCaches), + //HOOK_DEF(0x01D8FE00, SV_PropagateCustomizations), + //HOOK_DEF(0x01D8FF00, SV_WriteVoiceCodec), + //HOOK_DEF(0x01D8FF30, SV_CreateBaseline), + //HOOK_DEF(0x01D90170, SV_BroadcastCommand), + //HOOK_DEF(0x01D90260, SV_BuildReconnect), + //HOOK_DEF(0x01D903D0, SetCStrikeFlags), + //HOOK_DEF(0x01D904E0, SV_ActivateServer), + //HOOK_DEF(0x01D90790, SV_ServerShutdown), + //HOOK_DEF(0x01D907C0, SV_SpawnServer), + //HOOK_DEF(0x01D90E70, SV_LoadEntities), + //HOOK_DEF(0x01D90E90, SV_ClearEntities), + //HOOK_DEF(0x01D90ED0, RegUserMsg), + //HOOK_DEF(0x01D90F80, StringToFilter), + //HOOK_DEF(0x01D91020, SV_StringToUserID), + //HOOK_DEF(0x01D910C0, SV_BanId_f), + //HOOK_DEF(0x01D915C0, Host_Kick_f), + //HOOK_DEF(0x01D91990, SV_RemoveId_f), + //HOOK_DEF(0x01D91B90, SV_WriteId_f), + //HOOK_DEF(0x01D91C60, SV_ListId_f), + //HOOK_DEF(0x01D91D00, SV_AddIP_f), + //HOOK_DEF(0x01D91F00, SV_RemoveIP_f), + //HOOK_DEF(0x01D91FD0, SV_ListIP_f), + //HOOK_DEF(0x01D920B0, SV_WriteIP_f), + //HOOK_DEF(0x01D92190, SV_KickPlayer), + //HOOK_DEF(0x01D92300, SV_InactivateClients), + //HOOK_DEF(0x01D923A0, SV_FailDownload), + //HOOK_DEF(0x01D8EA40, SV_HasEventsInQueue), // NOXREF + //HOOK_DEF(0x01D90280, SV_ReconnectAllClients), // NOXREF + //HOOK_DEF(0x01D8BE40, SV_GetFakeClientCount), // NOXREF + //HOOK_DEF(0x01D8BE70, SV_GetModInfo), // NOXREF + //HOOK_DEF(0x01D87E90, SV_DownloadingModules), // NOXREF + //HOOK_DEF(0x01D923E0, Q_stristr), + //HOOK_DEF(0x01D92480, IsSafeFileToDownload), + //HOOK_DEF(0x01D92710, SV_BeginFileDownload_f), + HOOK_DEF(0x01D92940, SV_SetMaxclients), + //HOOK_DEF(0x01D92B00, SV_HandleRconPacket), + //HOOK_DEF(0x01D92B70, SV_CheckCmdTimes), + //HOOK_DEF(0x01D92C60, SV_CheckForRcon), + //HOOK_DEF(0x01D92CC0, SV_IsSimulating), + //HOOK_DEF(0x01D92D00, SV_CheckMapDifferences), + //HOOK_DEF(0x01D92D80, SV_Frame), + //HOOK_DEF(0x01D92E00, SV_Drop_f), + //HOOK_DEF(0x01D92E40, SV_RegisterDelta), + //HOOK_DEF(0x01D92EC0, SV_InitDeltas), + //HOOK_DEF(0x01D93010, SV_InitEncoders), + //HOOK_DEF(0x01D93050, SV_Init), + //HOOK_DEF(0x01D93600, SV_Shutdown), + HOOK_DEF(0x01D93650, SV_CompareUserID), + HOOK_DEF(0x01D936D0, SV_GetIDString), + HOOK_DEF(0x01D938E0, SV_GetClientIDString), + //HOOK_DEF(0x01D93950, GetGameAppID), + //HOOK_DEF(0x01D939C0, IsGameSubscribed), + //HOOK_DEF(0x, TRACE_DELTA), // NOXREF + + //HOOK_DEF(0x01D93A10, BIsValveGame), // NOXREF + //HOOK_DEF(0x01D8BF40, RequireValidChallenge), // NOXREF + //HOOK_DEF(0x01D8BF60, ValidInfoChallenge), // NOXREF + //HOOK_DEF(0x01D8BFB0, GetChallengeNr), // NOXREF + //HOOK_DEF(0x01D8C0C0, CheckChallengeNr), // NOXREF + //HOOK_DEF(0x01D8C180, ReplyServerChallenge), // NOXREF + //HOOK_DEF(0x01D8C200, ValidChallenge), // NOXREF + +#endif // Sv_Main_region + +#ifndef Zone_region + + HOOK_DEF(0x01DBB120, Z_ClearZone), + HOOK_DEF(0x01DBB170, Z_Free), + HOOK_DEF(0x01DBB220, Z_Malloc), + HOOK_DEF(0x01DBB260, Z_TagMalloc), + HOOK_DEF(0x01DBB310, Z_Print), // NOXREF + HOOK_DEF(0x01DBB3C0, Z_CheckHeap), + + HOOK_DEF(0x01DBB440, Hunk_Check), + HOOK_DEF(0x01DBB4B0, Hunk_Print), // NOXREF + HOOK_DEF(0x01DBB6B0, Hunk_AllocName), + HOOK_DEF(0x01DBB750, Hunk_Alloc), + HOOK_DEF(0x01DBB770, Hunk_LowMark), + HOOK_DEF(0x01DBB780, Hunk_FreeToLowMark), + HOOK_DEF(0x01DBB7B0, Hunk_HighMark), + HOOK_DEF(0x01DBB7E0, Hunk_FreeToHighMark), + HOOK_DEF(0x01DBB830, Hunk_HighAllocName), + HOOK_DEF(0x01DBB900, Hunk_TempAlloc), + + HOOK_DEF(0x01DBB960, Cache_Move), + HOOK_DEF(0x01DBB9D0, Cache_FreeLow), + HOOK_DEF(0x01DBBA00, Cache_FreeHigh), + HOOK_DEF(0x01DBBA60, Cache_UnlinkLRU), + HOOK_DEF(0x01DBBAA0, Cache_MakeLRU), + HOOK_DEF(0x01DBBAF0, Cache_TryAlloc), + HOOK_DEF(0x01DBBC30, Cache_Force_Flush), + HOOK_DEF(0x01DBBC60, Cache_Flush), + HOOK_DEF(0x01DBBC90, Cache_Print), // NOXREF + //HOOK_DEF(0x, ComparePath1), // NOXREF // not yet located on windows + //HOOK_DEF(0x, CommatizeNumber), // NOXREF // not yet located on windows + //HOOK_DEF(0x, Cache_Report), // NOXREF // not yet located on windows + //HOOK_DEF(0x, Cache_Compact), // NOXREF // not yet located on windows + HOOK_DEF(0x01DBBED0, Cache_Init), + HOOK_DEF(0x01DBBF00, Cache_Free), + HOOK_DEF(0x01DBBF70, Cache_Check), + HOOK_DEF(0x01DBBFA0, Cache_Alloc), + HOOK_DEF(0x01DBC040, Memory_Init), + HOOK_DEF(0x01DBBD60, CacheSystemCompare), + HOOK_DEF(0x01DBBF50, Cache_TotalUsed), // NOXREF // NOXREF + //HOOK_DEF(0x01DBC0E0, Cache_Print_Models_And_Totals), // NOXREF + //HOOK_DEF(0x01DBC1F0, Cache_Print_Sounds_And_Totals), // NOXREF + +#endif // Zone_region + +#ifndef FileSystem_Internal_region + + HOOK_DEF(0x01D3E2E0, FS_RemoveAllSearchPaths), // NOXREF + HOOK_DEF(0x01D3E2F0, FS_AddSearchPath), + HOOK_DEF(0x01D3E310, FS_RemoveSearchPath), // NOXREF + HOOK_DEF(0x01D3E330, FS_RemoveFile), + HOOK_DEF(0x01D3E350, FS_CreateDirHierarchy), + HOOK_DEF(0x01D3E370, FS_FileExists), + HOOK_DEF(0x01D3E390, FS_IsDirectory), // NOXREF + HOOK_DEF(0x01D3E3B0, FS_Open), + HOOK_DEF(0x01D3E3D0, FS_OpenPathID), + HOOK_DEF(0x01D3E3F0, FS_Close), + HOOK_DEF(0x01D3E410, FS_Seek), + HOOK_DEF(0x01D3E430, FS_Tell), + HOOK_DEF(0x01D3E450, FS_Size), + HOOK_DEF(0x01D3E470, FS_FileSize), + HOOK_DEF(0x01D3E490, FS_GetFileTime), + HOOK_DEF(0x01D3E4B0, FS_FileTimeToString), // NOXREF + HOOK_DEF(0x01D3E4D0, FS_IsOk), + HOOK_DEF(0x01D3E4F0, FS_Flush), + HOOK_DEF(0x01D3E510, FS_EndOfFile), + HOOK_DEF(0x01D3E530, FS_Read), + HOOK_DEF(0x01D3E550, FS_Write), + HOOK_DEF(0x01D3E570, FS_ReadLine), + HOOK_DEF(0x01D3E590, FS_FPrintf), + HOOK_DEF(0x01D3E5E0, FS_FindFirst), + HOOK_DEF(0x01D3E600, FS_FindNext), + HOOK_DEF(0x01D3E620, FS_FindIsDirectory), // NOXREF + HOOK_DEF(0x01D3E640, FS_FindClose), + HOOK_DEF(0x01D3E660, FS_GetLocalCopy), + HOOK_DEF(0x01D3E680, FS_GetLocalPath), + HOOK_DEF(0x01D3E6A0, FS_ParseFile), // NOXREF + HOOK_DEF(0x01D3E6E0, FS_FullPathToRelativePath), // NOXREF + HOOK_DEF(0x01D3E700, FS_GetCurrentDirectory), // NOXREF + HOOK_DEF(0x01D3E720, FS_PrintOpenedFiles), // NOXREF + HOOK_DEF(0x01D3E730, FS_SetWarningFunc), // NOXREF + HOOK_DEF(0x01D3E750, FS_SetWarningLevel), // NOXREF + HOOK_DEF(0x01D3E770, FS_GetCharacter), // NOXREF + HOOK_DEF(0x01D3E790, FS_LogLevelLoadStarted), + HOOK_DEF(0x01D3E7B0, FS_LogLevelLoadFinished), + HOOK_DEF(0x01D3E7D0, FS_SetVBuf), + HOOK_DEF(0x01D3E800, FS_GetInterfaceVersion), + HOOK_DEF(0x01D3E820, FS_GetReadBuffer), + HOOK_DEF(0x01D3E840, FS_ReleaseReadBuffer), + HOOK_DEF(0x01D3E860, FS_Unlink), + HOOK_DEF(0x01D3E8A0, FS_Rename), + HOOK_DEF(0x01D3E940, FS_LoadLibrary), + +#endif // FileSystem_Internal_region + +#ifndef FileSystem_region + + HOOK_DEF(0x01D3D340, GetBaseDirectory), + //HOOK_DEF(0x01D3E250, FileSystem_LoadDLL), // Totally not exists on Linux (it is inlined), but present and used on Windows, anyway just commented it out + //HOOK_DEF(0x01D3E2C0, FileSystem_UnloadDLL), // Totally not exists on Linux (it is inlined), but present and used on Windows, anyway just commented it out + HOOK_DEF(0x01D3D360, BEnabledHDAddon), + HOOK_DEF(0x01D3D390, BEnableAddonsFolder), + + HOOK_DEF(0x01D3D3C0, Host_SetHDModels_f), + HOOK_DEF(0x01D3D440, Host_SetAddonsFolder_f), + HOOK_DEF(0x01D3D4C0, Host_SetVideoLevel_f), + HOOK_DEF(0x01D3D510, Host_GetVideoLevel), + + HOOK_DEF(0x01D3DA60, FileSystem_SetGameDirectory), + HOOK_DEF(0x01D3E130, FileSystem_AddFallbackGameDir), + + HOOK_SYMBOLDEF(0x01D3D355, "_Z20GetFileSystemFactoryv", GetFileSystemFactory), // NOXREF + HOOK_SYMBOLDEF(0x01D3D530, "_Z26CheckLiblistForFallbackDirPKcbS0_b", CheckLiblistForFallbackDir), + HOOK_SYMBOLDEF(0x01D3E200, "_Z15FileSystem_InitPcPv", FileSystem_Init), + HOOK_SYMBOLDEF(0x01D3E2B0, "_Z19FileSystem_Shutdownv", FileSystem_Shutdown), + +#endif // FileSystem_region + +#ifndef Unicode_StrTools_region + + HOOK_SYMBOLDEF(0x01DA8F00, "_Z16Q_IsValidUChar32w", Q_IsValidUChar32), + HOOK_SYMBOLDEF(0x01DA97D0, "_Z15Q_UTF8ToUChar32PKcRwRb", Q_UTF8ToUChar32), + + HOOK_DEF(0x01DA9910, Q_UnicodeValidate), + HOOK_DEF(0x01DA99A0, Q_UnicodeAdvance), + HOOK_DEF(0x01DA9EA0, Q_UnicodeRepair), + HOOK_DEF(0x01DA9E70, V_UTF8ToUChar32), + +#endif // Unicode_StrTools_region + +#ifndef Cmd_region + + HOOK_DEF(0x01D26CD0, Cmd_Wait_f), + HOOK_DEF(0x01D26CE0, Cbuf_Init), + HOOK_DEF(0x01D26D00, Cbuf_AddText), + HOOK_DEF(0x01D26D50, Cbuf_InsertText), + HOOK_DEF(0x01D26DE0, Cbuf_InsertTextLines), + HOOK_DEF(0x01D26E80, Cbuf_Execute), + HOOK_DEF(0x01D26F60, Cmd_StuffCmds_f), + HOOK_DEF(0x01D270F0, Cmd_Exec_f), + HOOK_DEF(0x01D273A0, Cmd_Echo_f), + HOOK_DEF(0x01D273E0, CopyString), + HOOK_DEF(0x01D27410, Cmd_Alias_f), + HOOK_DEF(0x01D276A0, Cmd_GetFirstCmd), + HOOK_DEF(0x01D276B0, Cmd_Init), + HOOK_DEF(0x01D27720, Cmd_Shutdown), + HOOK_DEF(0x01D27750, Cmd_Argc), + HOOK_DEF(0x01D27760, Cmd_Argv), + HOOK_DEF(0x01D27790, Cmd_Args), + HOOK_DEF(0x01D277A0, Cmd_TokenizeString), + + HOOK_DEF(0x01D27900, Cmd_AddCommand), + HOOK_DEF(0x01D27A10, Cmd_AddMallocCommand), + HOOK_DEF(0x01D27AF0, Cmd_AddGameCommand), + HOOK_DEF(0x01D27B10, Cmd_RemoveMallocedCmds), + HOOK_DEF(0x01D27B60, Cmd_RemoveGameCmds), + HOOK_DEF(0x01D27B70, Cmd_RemoveWrapperCmds), + HOOK_DEF(0x01D27B80, Cmd_Exists), + HOOK_DEF(0x01D27D10, Cmd_ExecuteString), + HOOK_DEF(0x01D27DF0, Cmd_ForwardToServerInternal), + HOOK_DEF(0x01D27F40, Cmd_ForwardToServer), + HOOK_DEF(0x01D27F90, Cmd_ForwardToServerUnreliable), + HOOK_DEF(0x01D28000, Cmd_CmdList_f), + HOOK_DEF(0x01D27AB0, Cmd_AddHUDCommand), // NOXREF + HOOK_DEF(0x01D27AD0, Cmd_AddWrapperCommand), // NOXREF + HOOK_DEF(0x01D27B50, Cmd_RemoveHudCmds), // NOXREF + HOOK_DEF(0x01D27BC0, Cmd_CompleteCommand), // NOXREF + HOOK_DEF(0x01D27FA0, Cmd_CheckParm), // NOXREF + HOOK_DEF(0x01D27880, Cmd_FindCmd), // NOXREF + HOOK_DEF(0x01D278C0, Cmd_FindCmdPrev), // NOXREF +#endif // Cmd_region + +#ifndef Cvar_region + + HOOK_DEF(0x01D2D760, Cvar_Init), + HOOK_DEF(0x01D2D770, Cvar_Shutdown), + HOOK_DEF(0x01D2D780, Cvar_FindVar), + HOOK_DEF(0x01D2D800, Cvar_VariableValue), + HOOK_DEF(0x01D2D860, Cvar_VariableString), + HOOK_DEF(0x01D2D9C0, Cvar_DirectSet), + HOOK_DEF(0x01D2DC30, Cvar_Set), + HOOK_DEF(0x01D2DC70, Cvar_SetValue), + HOOK_DEF(0x01D2DD20, Cvar_RegisterVariable), + HOOK_DEF(0x01D2DE70, Cvar_IsMultipleTokens), + HOOK_DEF(0x01D2DED0, Cvar_Command), + HOOK_DEF(0x01D2E350, Cvar_UnlinkExternals), + HOOK_DEF(0x01D2E380, Cvar_CmdInit), + HOOK_DEF(0x01D2D7C0, Cvar_FindPrevVar), // NOXREF + HOOK_DEF(0x01D2D830, Cvar_VariableInt), // NOXREF + HOOK_DEF(0x01D2D880, Cvar_CompleteVariable), // NOXREF + HOOK_DEF(0x01D2DE10, Cvar_RemoveHudCvars), // NOXREF + HOOK_DEF(0x01D2DFA0, Cvar_WriteVariables), // NOXREF + HOOK_DEF(0x01D2E330, Cvar_CountServerVariables), // NOXREF + HOOK_DEF(0x01D2DFE0, Cmd_CvarListPrintCvar), + HOOK_DEF(0x01D2E0F0, Cmd_CvarList_f), + +#endif // Cvar_region + +#ifndef Info_region + + HOOK_DEF(0x01D4B610, Info_ValueForKey), + HOOK_DEF(0x01D4B6E0, Info_RemoveKey), + HOOK_DEF(0x01D4B7D0, Info_RemovePrefixedKeys), + HOOK_DEF(0x01D4B860, Info_IsKeyImportant), + HOOK_DEF(0x01D4B980, Info_FindLargestKey), + HOOK_DEF(0x01D4BA80, Info_SetValueForStarKey), + HOOK_DEF(0x01D4BCF0, Info_SetValueForKey), + HOOK_DEF(0x01D4BD30, Info_Print), + HOOK_DEF(0x01D4BE10, Info_IsValid), + +#endif // Info_region + +#ifndef SysDll_region + + //HOOK_DEF(0x, Sys_PageIn), + //HOOK_DEF(0x01D9ECF0, Sys_FindFirst), + //HOOK_DEF(0x01D9ED50, Sys_FindFirstPathID), + //HOOK_DEF(0x01D9ED90, Sys_FindNext), + //HOOK_DEF(0x01D9EDC0, Sys_FindClose), + //HOOK_DEF(0x01D9EDE0, glob_match_after_star), + //HOOK_DEF(0x01D9EF50, glob_match), + //HOOK_DEF(0x01D9EFD0, Sys_MakeCodeWriteable), + //HOOK_DEF(0x, Sys_SetFPCW), + //HOOK_DEF(0x, Sys_PushFPCW_SetHigh), + //HOOK_DEF(0x, Sys_PopFPCW), + //HOOK_DEF(0x, MaskExceptions), + //HOOK_DEF(0x, Sys_Init), // NOXREF + //HOOK_DEF(0x, Sys_Sleep), + //HOOK_DEF(0x, Sys_DebugOutStraight), + //HOOK_DEF(0x01D9F0E0, Sys_Error), + //HOOK_DEF(0x01D9F1F0, Sys_Warning), + //HOOK_DEF(0x01D9F230, Sys_Printf), + //HOOK_DEF(0x01D9F4A0, Sys_Quit), + HOOK_DEF(0x01D9F2A0, Sys_FloatTime), + //HOOK_DEF(0x01D9F460, Dispatch_Substate), + //HOOK_DEF(0x01D9F470, GameSetSubState), + //HOOK_DEF(0x01D9F4A0, GameSetState), + //HOOK_DEF(0x, GameSetBackground), + //HOOK_DEF(0x01D9F7B0, Voice_GetClientListening), + //HOOK_DEF(0x01D9F810, Voice_SetClientListening), + //HOOK_DEF(0x01D9F890, GetDispatch), + //HOOK_DEF(0x01D9F8D0, FindAddressInTable), + //HOOK_DEF(0x01D9F910, FindNameInTable), + //HOOK_DEF(0x, ConvertNameToLocalPlatform), + //HOOK_DEF(0x01D9FAA0, FunctionFromName), + //HOOK_DEF(0x01D9FB00, NameForFunction), + //HOOK_DEF(0x01D9FB50, GetEntityInit), + //HOOK_DEF(0x01D9FB70, GetIOFunction), + //HOOK_DEF(0x01D9FB90, DLL_SetModKey), + //HOOK_DEF(0x01D9FE50, LoadEntityDLLs), + //HOOK_DEF(0x01DA02D0, LoadThisDll), + //HOOK_DEF(0x01DA0390, ReleaseEntityDlls), + //HOOK_DEF(0x01DA0410, EngineFprintf), + //HOOK_DEF(0x01DA0420, AlertMessage), + //HOOK_DEF(0x01DA0640, Sys_SplitPath), + //HOOK_DEF(0x01D2BD90, Con_Debug_f), + //HOOK_DEF(0x01D2BDD0, Con_Init), + //HOOK_DEF(0x01D2BFC0, Con_DebugLog), + //HOOK_DEF(0x01D2C020, Con_Printf), + //HOOK_DEF(0x01D2C1E0, Con_SafePrintf), + //HOOK_DEF(0x01D2C140, Con_DPrintf), + +#ifdef _WIN32 + HOOK_DEF(0x01DA0A70, Sys_InitHardwareTimer), +#endif //_WIN32 + +#endif // SysDll_region + +#ifndef Sys_Dll2_region + + // virtual functions + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA16B0, "_ZN19CDedicatedServerAPI4InitEPcS0_PFP14IBaseInterfacePKcPiES7_", CDedicatedServerAPI::Init), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1800, "_ZN19CDedicatedServerAPI8ShutdownEv", CDedicatedServerAPI::Shutdown), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1860, "_ZN19CDedicatedServerAPI8RunFrameEv", CDedicatedServerAPI::RunFrame), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1880, "_ZN19CDedicatedServerAPI14AddConsoleTextEPc", CDedicatedServerAPI::AddConsoleText), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA18A0, "_ZN19CDedicatedServerAPI12UpdateStatusEPfPiS1_Pc", CDedicatedServerAPI::UpdateStatus), + + HOOK_DEF(0x01DA0670, GetCurrentSteamAppName), + HOOK_DEF(0x01DA07A0, F), + HOOK_DEF(0x01DA0820, Sys_GetCDKey), + HOOK_DEF(0x01DA0D50, Sys_ShutdownMemory), + +#ifdef _WIN32 + HOOK_SYMBOLDEF(0x01DA09E0, "_Z18Sys_CheckOSVersionv", Sys_CheckOSVersion), +#else + //HOOK_SYMBOLDEF(0x0, "_Z19Sys_SetupLegacyAPIsv", Sys_SetupLegacyAPIs), +#endif + + HOOK_SYMBOLDEF(0x01DA0940, "_Z17Legacy_Sys_PrintfPcz", Legacy_Sys_Printf), + HOOK_SYMBOLDEF(0x01DA0B70, "_Z12Sys_InitArgvPc", Sys_InitArgv), + HOOK_SYMBOLDEF(0x01DA0C20, "_Z14Sys_InitMemoryv", Sys_InitMemory), + HOOK_SYMBOLDEF(0x01DA0D70, "_Z25Sys_InitLauncherInterfacev", Sys_InitLauncherInterface), + HOOK_SYMBOLDEF(0x01DA0DA0, "_Z22Sys_InitAuthenticationv", Sys_InitAuthentication), + HOOK_SYMBOLDEF(0x01DA0DC0, "_Z21Sys_ShowProgressTicksPc", Sys_ShowProgressTicks), + HOOK_SYMBOLDEF(0x01DA0ED0, "_Z12Sys_InitGamePcS_Pvi", Sys_InitGame), + HOOK_SYMBOLDEF(0x01DA0FE0, "_Z16Sys_ShutdownGamev", Sys_ShutdownGame), + HOOK_SYMBOLDEF(0x01DA1060, "_Z13ClearIOStatesv", ClearIOStates), + + //HOOK_DEF(0x01DA0930, "_Z19Legacy_ErrorMessageiPKc", Legacy_ErrorMessage), // NOXREF + //HOOK_DEF(0x01DA09C0, "_Z11Sys_IsWin95v", Sys_IsWin95), // NOXREF + //HOOK_DEF(0x01DA09D0, "_Z11Sys_IsWin98v", Sys_IsWin98), // NOXREF + //HOOK_DEF(0x01DA0980, "_Z30Legacy_MP3subsys_Suspend_Audiov", Legacy_MP3subsys_Suspend_Audio), // NOXREF + //HOOK_DEF(0x01DA0990, "_Z29Legacy_MP3subsys_Resume_Audiov", Legacy_MP3subsys_Resume_Audio), // NOXREF + //HOOK_DEF(0x01DA13E0, "_Z22BuildMapCycleListHintsPPc", BuildMapCycleListHints), // NOXREF + + //HOOK_DEF(0x, Sys_Init), // NOXREF + //HOOK_DEF(0x, Sys_Shutdown), // NOXREF + //HOOK_DEF(0x, Sys_ShutdownArgv), // NOXREF + //HOOK_DEF(0x, Sys_ShutdownLauncherInterface), // NOXREF + //HOOK_DEF(0x, Sys_ShutdownAuthentication), // NOXREF + //HOOK_DEF(0x01DA0760, SetRateRegistrySetting), // NOXREF + //HOOK_DEF(0x01DA0780, GetRateRegistrySetting), // NOXREF + +#endif // Sys_Dll2_region + +#ifndef CModel_region + + HOOK_DEF(0x01D281B0, Mod_Init), + HOOK_DEF(0x01D281D0, Mod_DecompressVis), + HOOK_DEF(0x01D28210, Mod_LeafPVS), + HOOK_DEF(0x01D28270, CM_DecompressPVS), + HOOK_DEF(0x01D282E0, CM_LeafPVS), + HOOK_DEF(0x01D28310, CM_LeafPAS), + HOOK_DEF(0x01D28340, CM_FreePAS), + HOOK_DEF(0x01D28380, CM_CalcPAS), + HOOK_DEF(0x01D28580, CM_HeadnodeVisible), + +#endif // CModel_region + +#ifndef Model_region + + HOOK_DEF(0x01D50B80, SW_Mod_Init), + HOOK_DEF(0x01D50B90, Mod_Extradata), + HOOK_DEF(0x01D50BF0, Mod_PointInLeaf), + HOOK_DEF(0x01D50C80, Mod_ClearAll), + HOOK_DEF(0x01D50CC0, Mod_FillInCRCInfo), + HOOK_DEF(0x01D50CE0, Mod_FindName), + HOOK_DEF(0x01D50E90, Mod_LoadModel), + HOOK_DEF(0x01D51110, Mod_ForName), + HOOK_DEF(0x01D51150, Mod_AdInit), + HOOK_DEF(0x01D511F0, Mod_AdSwap), + HOOK_DEF(0x01D51280, Mod_LoadTextures), + HOOK_DEF(0x01D517C0, Mod_LoadLighting), + HOOK_DEF(0x01D51810, Mod_LoadVisibility), + HOOK_DEF(0x01D51860, Mod_LoadEntities), + HOOK_DEF(0x01D51930, Mod_LoadVertexes), + HOOK_DEF(0x01D519E0, Mod_LoadSubmodels), + HOOK_DEF(0x01D51B10, Mod_LoadEdges), + HOOK_DEF(0x01D51BA0, Mod_LoadTexinfo), + HOOK_DEF(0x01D51D60, CalcSurfaceExtents), + HOOK_DEF(0x01D51F10, Mod_LoadFaces), + HOOK_DEF(0x01D52140, Mod_SetParent), + HOOK_DEF(0x01D52180, Mod_LoadNodes), + HOOK_DEF(0x01D52330, Mod_LoadLeafs), + HOOK_DEF(0x01D52490, Mod_LoadClipnodes), + HOOK_DEF(0x01D52630, Mod_MakeHull0), + HOOK_DEF(0x01D52720, Mod_LoadMarksurfaces), + HOOK_DEF(0x01D527E0, Mod_LoadSurfedges), + HOOK_DEF(0x01D52860, Mod_LoadPlanes), + HOOK_DEF(0x01D52970, RadiusFromBounds), + HOOK_DEF(0x01D52A00, Mod_LoadBrushModel), + HOOK_DEF(0x01D53410, Mod_LoadSpriteFrame), + HOOK_DEF(0x01D53510, Mod_LoadSpriteGroup), + HOOK_DEF(0x01D535E0, Mod_LoadSpriteModel), + HOOK_DEF(0x01D53820, Mod_Print), + //HOOK_DEF(0x01D52C30, Mod_LoadAliasFrame), + //HOOK_DEF(0x01D52CE0, Mod_LoadAliasGroup), + //HOOK_DEF(0x01D52DF0, Mod_LoadAliasSkin), + //HOOK_DEF(0x01D52E60, Mod_LoadAliasSkinGroup), + //HOOK_DEF(0x01D52F40, Mod_LoadAliasModel), + //HOOK_DEF(0x01D53800, Mod_UnloadSpriteTextures), + //HOOK_DEF(0x01D538A0, Mod_ChangeGame), + //HOOK_DEF(0x01D51100, Mod_MarkClient), // NOXREF + //HOOK_DEF(0x01D50DF0, Mod_ValidateCRC), // NOXREF + //HOOK_DEF(0x01D50E50, Mod_NeedCRC), // NOXREF + +#endif // Model_region + +#ifndef Sv_Log_region + + HOOK_DEF(0x01D873D0, Log_Printf), + HOOK_DEF(0x01D875A0, Log_PrintServerVars), + HOOK_DEF(0x01D87600, Log_Close), + HOOK_DEF(0x01D87630, Log_Open), + HOOK_DEF(0x01D87850, SV_SetLogAddress_f), + HOOK_DEF(0x01D87990, SV_AddLogAddress_f), + HOOK_DEF(0x01D87BC0, SV_DelLogAddress_f), + +#endif // Sv_Log_region + +#ifndef Cl_Null_region + + //HOOK_DEF(0x, CL_RecordHUDCommand), + //HOOK_DEF(0x, R_DecalRemoveAll), + //HOOK_DEF(0x, CL_CheckForResend), + //HOOK_DEF(0x, CL_CheckFile), + //HOOK_DEF(0x01D17350, CL_ClearClientState), + //HOOK_DEF(0x, CL_Connect_f), + //HOOK_DEF(0x, CL_DecayLights), + //HOOK_DEF(0x01D17490, CL_Disconnect), + //HOOK_DEF(0x01D17660, CL_Disconnect_f), + //HOOK_DEF(0x, CL_EmitEntities), + //HOOK_DEF(0x, CL_InitClosest), + //HOOK_DEF(0x, CL_Init), + HOOK_DEF(0x01D131E0, CL_Particle), + //HOOK_DEF(0x, CL_PredictMove), + //HOOK_DEF(0x, CL_PrintLogos), + //HOOK_DEF(0x, CL_ReadPackets), + //HOOK_DEF(0x, CL_RequestMissingResources), + //HOOK_DEF(0x, CL_Move), + //HOOK_DEF(0x, CL_SendConnectPacket), + //HOOK_DEF(0x01D0FABD, CL_StopPlayback), + //HOOK_DEF(0x, CL_UpdateSoundFade), + //HOOK_DEF(0x, CL_AdjustClock), + //HOOK_DEF(0x01D48910, CL_Save), + //HOOK_DEF(0x01D19650, CL_HudMessage), + //HOOK_DEF(0x, Key_WriteBindings), + //HOOK_DEF(0x, ClientDLL_UpdateClientData), + //HOOK_DEF(0x, ClientDLL_HudVidInit), + //HOOK_DEF(0x, Chase_Init), + //HOOK_DEF(0x, Key_Init), + //HOOK_DEF(0x, ClientDLL_Init), + //HOOK_DEF(0x, Con_Shutdown), + //HOOK_DEF(0x, DispatchDirectUserMsg), + //HOOK_DEF(0x, CL_ShutDownUsrMessages), + //HOOK_DEF(0x, CL_ShutDownClientStatic), + //HOOK_DEF(0x, ClientDLL_MoveClient), + //HOOK_DEF(0x, CL_Shutdown), + //HOOK_DEF(0x, ClientDLL_Frame), + //HOOK_DEF(0x, ClientDLL_CAM_Think), + //HOOK_DEF(0x, CL_InitEventSystem), + //HOOK_DEF(0x, CL_CheckClientState), + //HOOK_DEF(0x, CL_RedoPrediction), + //HOOK_DEF(0x, CL_SetLastUpdate), + //HOOK_DEF(0x, Con_NPrintf), + //HOOK_DEF(0x01D805A0, Sequence_OnLevelLoad), + //HOOK_DEF(0x01D1CDD0, CL_WriteMessageHistory), + //HOOK_DEF(0x, CL_MoveSpectatorCamera), + //HOOK_DEF(0x, CL_AddVoiceToDatagram), + //HOOK_DEF(0x, CL_VoiceIdle), + //HOOK_DEF(0x, PollDInputDevices), + //HOOK_DEF(0x, CL_KeepConnectionActive), + //HOOK_DEF(0x, CL_UpdateModuleC), + //HOOK_DEF(0x, VGuiWrap2_IsInCareerMatch), + //HOOK_DEF(0x, VguiWrap2_GetCareerUI), + //HOOK_DEF(0x, VGuiWrap2_GetLocalizedStringLength), + //HOOK_DEF(0x01D07630, VGuiWrap2_LoadingStarted), + //HOOK_DEF(0x, ConstructTutorMessageDecayBuffer), + //HOOK_DEF(0x, ProcessTutorMessageDecayBuffer), + //HOOK_DEF(0x, GetTimesTutorMessageShown), + //HOOK_DEF(0x, RegisterTutorMessageShown), + //HOOK_DEF(0x, ResetTutorMessageDecayData), + //HOOK_DEF(0x01D83340, SetCareerAudioState), + +#endif // Cl_Null_region + +#ifndef Snd_Null_region + + //HOOK_DEF(0x0, S_Init), + //HOOK_DEF(0x0, S_AmbientOff), + //HOOK_DEF(0x0, S_AmbientOn), + //HOOK_DEF(0x0, S_Shutdown), + //HOOK_DEF(0x0, S_TouchSound), + //HOOK_DEF(0x0, S_ClearBuffer), + //HOOK_DEF(0x0, S_StartStaticSound), + //HOOK_DEF(0x0, S_StartDynamicSound), + //HOOK_DEF(0x0, S_StopSound), + //HOOK_DEF(0x0, S_PrecacheSound), + //HOOK_DEF(0x0, S_ClearPrecache), + //HOOK_DEF(0x0, S_Update), + //HOOK_DEF(0x0, S_StopAllSounds), + //HOOK_DEF(0x0, S_BeginPrecaching), + //HOOK_DEF(0x0, S_EndPrecaching), + //HOOK_DEF(0x0, S_ExtraUpdate), + //HOOK_DEF(0x0, S_LocalSound), + //HOOK_DEF(0x0, S_BlockSound), + //HOOK_DEF(0x0, S_PrintStats), + //HOOK_DEF(0x0, Voice_RecordStart), + //HOOK_DEF(0x0, Voice_IsRecording), + //HOOK_DEF(0x0, Voice_RegisterCvars), + //HOOK_DEF(0x01DB65D0, Voice_Deinit), + //HOOK_DEF(0x0, Voice_Idle), + //HOOK_DEF(0x0, Voice_RecordStop), + +#endif // Snd_Null_region + +#ifndef Sv_Steam3_region + + HOOK_SYMBOLDEF(0x01D994C0, "_ZN13CSteam3Server19NotifyClientConnectEP8client_sPKvj", CSteam3Server::NotifyClientConnect), + HOOK_SYMBOLDEF(0x01D98B20, "_ZN13CSteam3Server14OnLogonFailureEP27SteamServerConnectFailure_t", CSteam3Server::OnLogonFailure), + HOOK_SYMBOLDEF(0x01D99A10, "_ZN13CSteam3Server24SendUpdatedServerDetailsEv", CSteam3Server::SendUpdatedServerDetails), + HOOK_SYMBOLDEF(0x01D98A70, "_ZN13CSteam3Server14OnLogonSuccessEP23SteamServersConnected_t", CSteam3Server::OnLogonSuccess), + HOOK_SYMBOLDEF(0x01D98A40, "_ZN13CSteam3Server18OnGSPolicyResponseEP18GSPolicyResponse_t", CSteam3Server::OnGSPolicyResponse), + HOOK_SYMBOLDEF(0x01D98AE0, "_ZN13CSteam3Server10GetSteamIDEv", CSteam3Server::GetSteamID), + HOOK_SYMBOLDEF(0x01D98F10, "_ZN13CSteam3Server21ClientFindFromSteamIDER8CSteamID", CSteam3Server::ClientFindFromSteamID), + HOOK_SYMBOLDEF(0x01D98DF0, "_ZN13CSteam3Server17OnGSClientApproveEP17GSClientApprove_t", CSteam3Server::OnGSClientApprove), + HOOK_SYMBOLDEF(0x01D99660, "_ZN13CSteam3Server22NotifyClientDisconnectEP8client_s", CSteam3Server::NotifyClientDisconnect), + HOOK_SYMBOLDEF(0x01D98BC0, "_ZN13CSteam3Server20OnGSClientDenyHelperEP8client_s11EDenyReasonPKc", CSteam3Server::OnGSClientDenyHelper), + HOOK_SYMBOLDEF(0x01D98B90, "_ZN13CSteam3Server14OnGSClientDenyEP14GSClientDeny_t", CSteam3Server::OnGSClientDeny), + HOOK_SYMBOLDEF(0x01D98DC0, "_ZN13CSteam3Server14OnGSClientKickEP14GSClientKick_t", CSteam3Server::OnGSClientKick), + HOOK_SYMBOLDEF(0x01D996B0, "_ZN13CSteam3Server19NotifyOfLevelChangeEb", CSteam3Server::NotifyOfLevelChange), + HOOK_SYMBOLDEF(0x01D99110, "_ZN13CSteam3Server8ActivateEv", CSteam3Server::Activate), + HOOK_SYMBOLDEF(0x01D99770, "_ZN13CSteam3Server8RunFrameEv", CSteam3Server::RunFrame), + HOOK_SYMBOLDEF(0x01D99600, "_ZN13CSteam3Server16NotifyBotConnectEP8client_s", CSteam3Server::NotifyBotConnect), + + HOOK_DEF(0x01D99550, ISteamGameServer_CreateUnauthenticatedUserConnection), + HOOK_DEF(0x01D99590, ISteamGameServer_BUpdateUserData), + HOOK_DEF(0x01D995D0, ISteamApps_BIsSubscribedApp), + HOOK_DEF(0x01D99AB0, Steam_GetCommunityName), + HOOK_DEF(0x01D99CA0, Steam_NotifyClientConnect), + HOOK_DEF(0x01D99CD0, Steam_NotifyBotConnect), + HOOK_DEF(0x01D99D00, Steam_NotifyClientDisconnect), + HOOK_DEF(0x01D99D20, Steam_NotifyOfLevelChange), + HOOK_DEF(0x01D99D40, Steam_Shutdown), + HOOK_DEF(0x01D99D70, Steam_Activate), + HOOK_DEF(0x01D99DC0, Steam_RunFrame), + HOOK_DEF(0x01D99DE0, Steam_SetCVar), + HOOK_DEF(0x01D99E10, Steam_ClientRunFrame), + HOOK_DEF(0x01D99E20, Steam_InitClient), + HOOK_DEF(0x01D99E30, Steam_GSInitiateGameConnection), + HOOK_DEF(0x01D99E70, Steam_GSTerminateGameConnection), + HOOK_DEF(0x01D99E90, Steam_ShutdownClient), + HOOK_DEF(0x01D99EA0, Steam_GSGetSteamID), + HOOK_DEF(0x01D99EB0, Steam_GSBSecure), + HOOK_DEF(0x01D99ED0, Steam_GSBLoggedOn), + HOOK_DEF(0x01D99F00, Steam_GSBSecurePreference), + HOOK_DEF(0x01D99F10, Steam_Steam3IDtoSteam2), + HOOK_DEF(0x01D99F50, Steam_StringToSteamID), + HOOK_DEF(0x01D99FD0, Steam_GetGSUniverse), + HOOK_DEF(0x01D9A020, Steam3Server), + HOOK_DEF(0x01D9A1D0, Steam3Client), + HOOK_DEF(0x01D9A1E0, Master_SetMaster_f), + HOOK_DEF(0x01D9A2D0, Steam_HandleIncomingPacket), + +#endif // Sv_Steam3_region + +#ifndef Host_region + + HOOK_DEF(0x01D43A00, Host_EndGame), + HOOK_DEF(0x01D43AC0, Host_Error), + HOOK_DEF(0x01D43BA0, Host_InitLocal), + HOOK_DEF(0x01D43C90, Info_WriteVars), // NOXREF + HOOK_DEF(0x01D43D70, Host_WriteConfiguration), // NOXREF + HOOK_DEF(0x01D43FA0, Host_WriteCustomConfig), + HOOK_DEF(0x01D44190, SV_ClientPrintf), + HOOK_DEF(0x01D441F0, SV_BroadcastPrintf), + HOOK_DEF(0x01D442A0, Host_ClientCommands), + HOOK_DEF(0x01D44310, SV_DropClient), + HOOK_DEF(0x01D44510, Host_ClearClients), + HOOK_DEF(0x01D446B0, Host_ShutdownServer), + HOOK_DEF(0x01D447F0, SV_ClearClientStates), + HOOK_DEF(0x01D44830, Host_CheckDyanmicStructures), + HOOK_DEF(0x01D44880, Host_ClearMemory), + HOOK_DEF(0x01D44900, Host_FilterTime), + HOOK_DEF(0x01D44B50, Master_IsLanGame), + HOOK_DEF(0x01D44B70, Master_Heartbeat_f), + HOOK_DEF(0x01D44B80, Host_ComputeFPS), + HOOK_DEF(0x01D44BB0, Host_GetHostInfo), + HOOK_DEF(0x01D44C80, Host_Speeds), + HOOK_DEF(0x01D44DC0, Host_UpdateScreen), + HOOK_DEF(0x01D44EB0, Host_UpdateSounds), + HOOK_DEF(0x01D44F30, Host_CheckConnectionFailure), + HOOK_DEF(0x01D44F90, _Host_Frame), + HOOK_DEF(0x01D45150, Host_Frame), + HOOK_DEF(0x01D45290, CheckGore), + HOOK_DEF(0x01D45450, Host_IsSinglePlayerGame), + HOOK_DEF(0x01D45470, Host_IsServerActive), + HOOK_DEF(0x01D45480, Host_Version), + HOOK_DEF(0x01D456A0, Host_Init), + HOOK_DEF(0x01D459A0, Host_Shutdown), + +#endif // Host_region + +#ifndef Host_Cmd_region + + HOOK_DEF(0x01D45AF0, SV_GetPlayerHulls), + HOOK_DEF(0x01D45B20, Host_InitializeGameDLL), + HOOK_DEF(0x01D45BA0, Host_Motd_f), + HOOK_DEF(0x01D45D00, Host_Motd_Write_f), + HOOK_DEF(0x01D45E70, Host_GetStartTime), + HOOK_DEF(0x01D45E80, Host_UpdateStats), // UNTESTED Linux + HOOK_DEF(0x01D45FB0, GetStatsString), + HOOK_DEF(0x01D460B0, Host_Stats_f), + HOOK_DEF(0x01D460F0, Host_Quit_f), + HOOK_DEF(0x01D46140, Host_Quit_Restart_f), + HOOK_DEF(0x01D46250, Host_Status_Printf), + HOOK_DEF(0x01D462F0, Host_Status_f), + HOOK_DEF(0x01D467B0, Host_Status_Formatted_f), + HOOK_DEF(0x01D46EC0, Host_Ping_f), + HOOK_DEF(0x01D46F30, Host_Map), + HOOK_DEF(0x01D470D0, Host_Map_f), + HOOK_DEF(0x01D473B0, Host_Career_f), + HOOK_DEF(0x01D473D0, Host_Maps_f), + HOOK_DEF(0x01D47410, Host_Changelevel_f), + HOOK_DEF(0x01D47510, Host_FindRecentSave), + HOOK_DEF(0x01D47600, Host_Restart_f), + HOOK_DEF(0x01D47690, Host_Reload_f), + HOOK_DEF(0x01D47710, Host_Reconnect_f), + HOOK_DEF(0x01D477E0, Host_SaveGameDirectory), + HOOK_DEF(0x01D47810, Host_SavegameComment), + HOOK_DEF(0x01D478B0, Host_SaveAgeList), + HOOK_DEF(0x01D479B0, Host_ValidSave), + HOOK_DEF(0x01D47A70, SaveInit), + HOOK_DEF(0x01D47B80, SaveExit), + HOOK_DEF(0x01D47BC0, SaveGameSlot), + HOOK_DEF(0x01D47E70, Host_Savegame_f), + HOOK_DEF(0x01D47F60, Host_AutoSave_f), + HOOK_DEF(0x01D47FF0, SaveGame), + HOOK_DEF(0x01D48020, SaveReadHeader), + HOOK_DEF(0x01D481A0, SaveReadComment), // NOXREF + HOOK_DEF(0x01D481D0, Host_Loadgame_f), + HOOK_DEF(0x01D48220, LoadGame), + HOOK_DEF(0x01D48250, Host_Load), + HOOK_DEF(0x01D484C0, SaveGamestate), + HOOK_DEF(0x01D48A00, EntityInit), + HOOK_DEF(0x01D48A50, LoadSaveData), + HOOK_DEF(0x01D48C70, ParseSaveTables), + HOOK_DEF(0x01D48DC0, EntityPatchWrite), + HOOK_DEF(0x01D48EB0, EntityPatchRead), + HOOK_DEF(0x01D48F60, LoadGamestate), + HOOK_DEF(0x01D491D0, EntryInTable), + HOOK_DEF(0x01D49220, LandmarkOrigin), + HOOK_DEF(0x01D49290, EntityInSolid), + HOOK_DEF(0x01D49320, CreateEntityList), + HOOK_DEF(0x01D49570, LoadAdjacentEntities), + HOOK_DEF(0x01D49730, FileSize), + HOOK_DEF(0x01D49750, FileCopy), + HOOK_DEF(0x01D497B0, DirectoryCopy), + HOOK_DEF(0x01D49880, DirectoryExtract), + HOOK_DEF(0x01D49930, DirectoryCount), + HOOK_DEF(0x01D49970, Host_ClearSaveDirectory), + HOOK_DEF(0x01D49AB0, Host_ClearGameState), + HOOK_DEF(0x01D49AD0, Host_Changelevel2_f), + HOOK_DEF(0x01D49CB0, Host_Version_f), + HOOK_DEF(0x01D49CE0, Host_FullInfo_f), + HOOK_DEF(0x01D49E00, Host_KillVoice_f), // NOXREF + HOOK_DEF(0x01D49E10, Host_SetInfo_f), + HOOK_DEF(0x01D49EB0, Host_Say), + HOOK_DEF(0x01D4A060, Host_Say_f), + HOOK_DEF(0x01D4A070, Host_Say_Team_f), + HOOK_DEF(0x01D4A080, Host_Tell_f), + HOOK_DEF(0x01D4A230, Host_Kill_f), + HOOK_DEF(0x01D4A280, Host_TogglePause_f), + HOOK_DEF(0x01D4A320, Host_Pause_f), + HOOK_DEF(0x01D4A380, Host_Unpause_f), + HOOK_DEF(0x01D4A620, Host_Interp_f), + HOOK_DEF(0x01D4A650, Host_NextDemo), + HOOK_DEF(0x01D4A700, Host_Startdemos_f), + HOOK_DEF(0x01D4A7C0, Host_Demos_f), + HOOK_DEF(0x01D4A7F0, Host_Stopdemo_f), + HOOK_DEF(0x01D4A810, Host_EndSection), // NOXREF + HOOK_DEF(0x01D4A910, Host_Soundfade_f), + HOOK_DEF(0x01D4AA10, Host_KillServer_f), + HOOK_DEF(0x01D4AA50, Host_VoiceRecordStart_f), + HOOK_DEF(0x01D4AAA0, Host_VoiceRecordStop_f), + HOOK_DEF(0x01D4AC90, Host_Crash_f), // NOXREF + HOOK_DEF(0x01D4ACA0, Host_InitCommands), + HOOK_DEF(0x01D4B060, SV_CheckBlendingInterface), + HOOK_DEF(0x01D4B0D0, SV_CheckSaveGameCommentInterface), + +#endif // Host_Cmd_region + +#ifndef Pmove_region + + HOOK_DEF(0x01D5B490, PM_AddToTouched), + HOOK_DEF(0x01D5B530, PM_StuckTouch), + HOOK_DEF(0x01D5B590, PM_Init), + +#endif // Pmove_region + +#ifndef Pmovetst_region + + HOOK_DEF(0x01D5B8F0, PM_TraceModel), + HOOK_DEF(0x01D5B990, PM_GetModelBounds), + HOOK_DEF(0x01D5B9C0, PM_GetModelType), + HOOK_DEF(0x01D5B9D0, PM_InitBoxHull), + HOOK_DEF(0x01D5BA60, PM_HullForBox), + HOOK_DEF(0x01D5BAB0, PM_HullPointContents), + HOOK_DEF(0x01D5BB50, PM_LinkContents), + HOOK_DEF(0x01D5BC10, PM_PointContents), + HOOK_DEF(0x01D5BCA0, PM_WaterEntity), + HOOK_DEF(0x01D5BD10, PM_TruePointContents), + HOOK_DEF(0x01D5BD40, PM_HullForStudioModel), + HOOK_DEF(0x01D5BDF0, PM_HullForBsp), + HOOK_DEF(0x01D5BEA0, _PM_TestPlayerPosition), + HOOK_DEF(0x01D5C190, PM_TestPlayerPosition), + HOOK_DEF(0x01D5C1B0, PM_TestPlayerPositionEx), + HOOK_DEF(0x01D5C1D0, _PM_PlayerTrace), + HOOK_DEF(0x01D5C890, PM_PlayerTrace), + HOOK_DEF(0x01D5C8F0, PM_PlayerTraceEx), + HOOK_DEF(0x01D5C9C8, PM_TraceLine), + HOOK_DEF(0x01D5CA60, PM_TraceLineEx), + HOOK_DEF(0x01D5CB20, PM_RecursiveHullCheck), + +#endif // Pmovetst_region + +#ifndef Pr_Edict_region + + HOOK_DEF(0x01D61510, ED_ClearEdict), + HOOK_DEF(0x01D61550, ED_Alloc), + HOOK_DEF(0x01D61610, ED_Free), + HOOK_DEF(0x01D616D0, ED_Count), // NOXREF + HOOK_DEF(0x01D61770, ED_NewString), + HOOK_DEF(0x01D617D0, ED_ParseEdict), + HOOK_DEF(0x01D61A70, ED_LoadFromFile), + HOOK_DEF(0x01D61B80, PR_Init), // NOXREF + HOOK_DEF(0x01D61B90, EDICT_NUM), + HOOK_DEF(0x01D61BD0, NUM_FOR_EDICT), + HOOK_DEF(0x01D61C10, SuckOutClassname), + HOOK_DEF(0x01D61CD0, ReleaseEntityDLLFields), + HOOK_DEF(0x01D61CF0, InitEntityDLLFields), + HOOK_DEF(0x01D61D00, PvAllocEntPrivateData), + HOOK_DEF(0x01D61D30, PvEntPrivateData), + HOOK_DEF(0x01D61D50, FreeEntPrivateData), + HOOK_DEF(0x01D61D90, FreeAllEntPrivateData), + HOOK_DEF(0x01D61DD0, PEntityOfEntOffset), + HOOK_DEF(0x01D61DE0, EntOffsetOfPEntity), + HOOK_DEF(0x01D61DF0, IndexOfEdict), + HOOK_DEF(0x01D61E40, PEntityOfEntIndex), + HOOK_DEF(0x01D61E80, SzFromIndex), + HOOK_DEF(0x01D61E90, GetVarsOfEnt), + HOOK_DEF(0x01D61EA0, FindEntityByVars), + HOOK_DEF(0x01D61EE0, CVarGetFloat), + HOOK_DEF(0x01D61F00, CVarGetString), + HOOK_DEF(0x01D61F20, CVarGetPointer), + HOOK_DEF(0x01D61F40, CVarSetFloat), + HOOK_DEF(0x01D61F60, CVarSetString), + HOOK_DEF(0x01D61F80, CVarRegister), + HOOK_DEF(0x01D61FA0, AllocEngineString), + HOOK_DEF(0x01D61FC0, SaveSpawnParms), + HOOK_DEF(0x01D61FF0, GetModelPtr), + +#endif // Pr_Edict_region + +#ifndef Pr_Cmds_region + + //HOOK_DEF(0x01D5CF00, PF_makevectors_I), + //HOOK_DEF(0x01D5CF20, PF_Time), + //HOOK_DEF(0x01D5CF40, PF_setorigin_I), + //HOOK_DEF(0x01D5CF80, SetMinMaxSize), + //HOOK_DEF(0x01D5D030, PF_setsize_I), + //HOOK_DEF(0x01D5D050, PF_setmodel_I), + //HOOK_DEF(0x01D5D0F0, PF_modelindex), + //HOOK_DEF(0x01D5D110, ModelFrames), + //HOOK_DEF(0x01D5D150, PF_bprint), + //HOOK_DEF(0x01D5D170, PF_sprint), + //HOOK_DEF(0x01D5D1D0, ServerPrint), + //HOOK_DEF(0x01D5D1F0, ClientPrintf), + //HOOK_DEF(0x01D5D2A0, PF_vectoyaw_I), + //HOOK_DEF(0x01D5D330, PF_vectoangles_I), + //HOOK_DEF(0x01D5D350, PF_particle_I), + //HOOK_DEF(0x01D5D380, PF_ambientsound_I), + //HOOK_DEF(0x01D5D4C0, PF_sound_I), + //HOOK_DEF(0x01D5D5A0, PF_traceline_Shared), + //HOOK_DEF(0x01D5D600, PF_traceline_DLL), + //HOOK_DEF(0x01D5D6C0, TraceHull), + //HOOK_DEF(0x01D5D770, TraceSphere), + //HOOK_DEF(0x01D5D780, TraceModel), + //HOOK_DEF(0x01D5D890, SurfaceAtPoint), + //HOOK_DEF(0x01D5DA90, TraceTexture), + //HOOK_DEF(0x01D5DCA0, PF_TraceToss_Shared), + //HOOK_DEF(0x01D5DCE0, SV_SetGlobalTrace), + //HOOK_DEF(0x01D5DD80, PF_TraceToss_DLL), + //HOOK_DEF(0x01D5DE40, TraceMonsterHull), + //HOOK_DEF(0x01D5DF10, PF_newcheckclient), + //HOOK_DEF(0x01D5DFF0, PF_checkclient_I), + //HOOK_DEF(0x01D5E110, PVSNode), + //HOOK_DEF(0x01D5E1D0, PVSMark), + //HOOK_DEF(0x01D5E250, PVSFindEntities), + //HOOK_DEF(0x01D5E360, ValidCmd), + //HOOK_DEF(0x01D5E390, PF_stuffcmd_I), + //HOOK_DEF(0x01D5E450, PF_localcmd_I), + //HOOK_DEF(0x01D5E480, PF_localexec_I), + //HOOK_DEF(0x01D5E490, FindEntityInSphere), + //HOOK_DEF(0x01D5E5C0, PF_Spawn_I), + //HOOK_DEF(0x01D5E5D0, CreateNamedEntity), + //HOOK_DEF(0x01D5E640, PF_Remove_I), + //HOOK_DEF(0x01D5E920, PF_find_Shared), + //HOOK_DEF(0x01D5E660, iGetIndex), + //HOOK_DEF(0x01D5E8C0, FindEntityByString), + //HOOK_DEF(0x01D5E9B0, GetEntityIllum), + //HOOK_DEF(0x01D5EA50, PR_IsEmptyString), + //HOOK_DEF(0x01D5EA60, PF_precache_sound_I), + //HOOK_DEF(0x01D5EB50, EV_Precache), + //HOOK_DEF(0x01D5ECD0, EV_PlayReliableEvent), + //HOOK_DEF(0x01D5EE10, EV_Playback), + //HOOK_DEF(0x01D5F190, EV_SV_Playback), + //HOOK_DEF(0x01D5F210, PF_precache_model_I), + //HOOK_DEF(0x01D5F310, PF_precache_generic_I), + //HOOK_DEF(0x01D5F3E0, PF_IsMapValid_I), + //HOOK_DEF(0x01D5F430, PF_NumberOfEntities_I), + //HOOK_DEF(0x01D5F460, PF_GetInfoKeyBuffer_I), + //HOOK_DEF(0x01D5F4B0, PF_InfoKeyValue_I), + //HOOK_DEF(0x01D5F4D0, PF_SetKeyValue_I), + //HOOK_DEF(0x01D5F530, PF_RemoveKey_I), + //HOOK_DEF(0x01D5F550, PF_SetClientKeyValue_I), + //HOOK_DEF(0x01D5F5E0, PF_walkmove_I), + //HOOK_DEF(0x01D5F690, PF_droptofloor_I), + //HOOK_DEF(0x01D5F780, PF_DecalIndex), + //HOOK_DEF(0x01D5F7D0, PF_lightstyle_I), + //HOOK_DEF(0x01D5F860, PF_checkbottom_I), + //HOOK_DEF(0x01D5F880, PF_pointcontents_I), + //HOOK_DEF(0x01D5F8A0, PF_aim_I), + //HOOK_DEF(0x01D5FB60, PF_changeyaw_I), + //HOOK_DEF(0x01D5FC50, PF_changepitch_I), + //HOOK_DEF(0x01D5FD40, PF_setview_I), + //HOOK_DEF(0x01D5FDC0, PF_crosshairangle_I), + //HOOK_DEF(0x01D5FEC0, PF_CreateFakeClient_I), + //HOOK_DEF(0x01D60070, PF_RunPlayerMove_I), + //HOOK_DEF(0x01D60180, WriteDest_Parm), + //HOOK_DEF(0x01D60260, PF_MessageBegin_I), + //HOOK_DEF(0x01D60350, PF_MessageEnd_I), + //HOOK_DEF(0x01D605E0, PF_WriteByte_I), + //HOOK_DEF(0x01D60610, PF_WriteChar_I), + //HOOK_DEF(0x01D60640, PF_WriteShort_I), + //HOOK_DEF(0x01D60670, PF_WriteLong_I), + //HOOK_DEF(0x01D606A0, PF_WriteAngle_I), + //HOOK_DEF(0x01D606D0, PF_WriteCoord_I), + //HOOK_DEF(0x01D60710, PF_WriteString_I), + //HOOK_DEF(0x01D60740, PF_WriteEntity_I), + //HOOK_DEF(0x01D60770, PF_makestatic_I), + //HOOK_DEF(0x01D608C0, PF_StaticDecal), + //HOOK_DEF(0x01D60940, PF_setspawnparms_I), + //HOOK_DEF(0x01D60970, PF_changelevel_I), + HOOK_DEF(0x01D609D0, SeedRandomNumberGenerator), + HOOK_DEF(0x01D60A10, ran1), + HOOK_DEF(0x01D60AE0, fran1), + HOOK_DEF(0x01D60B30, RandomFloat), + HOOK_DEF(0x01D60B60, RandomLong), + //HOOK_DEF(0x01D60BC0, PF_FadeVolume), + //HOOK_DEF(0x01D60C60, PF_SetClientMaxspeed), + //HOOK_DEF(0x01D60CA0, PF_GetPlayerUserId), + //HOOK_DEF(0x01D60CF0, PF_GetPlayerWONId), + HOOK_DEF(0x01D60D00, PF_GetPlayerAuthId), + //HOOK_DEF(0x01D60E00, PF_BuildSoundMsg_I), + //HOOK_DEF(0x01D60E50, PF_IsDedicatedServer), + //HOOK_DEF(0x01D60E60, PF_GetPhysicsInfoString), + //HOOK_DEF(0x01D60EB0, PF_GetPhysicsKeyValue), + //HOOK_DEF(0x01D60F10, PF_SetPhysicsKeyValue), + //HOOK_DEF(0x01D60F70, PF_GetCurrentPlayer), + //HOOK_DEF(0x01D60FB0, PF_CanSkipPlayer), + //HOOK_DEF(0x01D61000, PF_SetGroupMask), + //HOOK_DEF(0x01D61020, PF_CreateInstancedBaseline), + //HOOK_DEF(0x01D61070, PF_Cvar_DirectSet), + //HOOK_DEF(0x01D61090, PF_ForceUnmodified), + //HOOK_DEF(0x01D611B0, PF_GetPlayerStats), + //HOOK_DEF(0x01D61230, QueryClientCvarValueCmd), // NOXREF + //HOOK_DEF(0x01D612D0, QueryClientCvarValueCmd2), // NOXREF + //HOOK_DEF(0x01D61390, QueryClientCvarValue), + //HOOK_DEF(0x01D61410, QueryClientCvarValue2), + //HOOK_DEF(0x01D614A0, hudCheckParm), + //HOOK_DEF(0x01D614F0, EngCheckParm), + +#endif // Pr_Cmds_region + +#ifndef Mathlib_region + + HOOK_DEF(0x01D4F570, anglemod), + //HOOK_DEF(0x, BOPS_Error), + HOOK_DEF(0x01DBEE44, BoxOnPlaneSide), + //HOOK_DEF(0x, InvertMatrix), + HOOK_DEF(0x01D4FD10, AngleVectors), + HOOK_DEF(0x01D4FE70, AngleVectorsTranspose), + HOOK_DEF(0x01D4FF90, AngleMatrix), + //HOOK_DEF(0x, AngleIMatrix), + //HOOK_DEF(0x, NormalizeAngles), + //HOOK_DEF(0x, InterpolateAngles), + HOOK_DEF(0x01D502C0, VectorTransform), + HOOK_DEF(0x01D50320, VectorCompare), + HOOK_DEF(0x01D50350, VectorMA), + //HOOK_DEF(0x, _DotProduct), + //HOOK_DEF(0x, _VectorSubtract), + //HOOK_DEF(0x, _VectorAdd), + //HOOK_DEF(0x, _VectorCopy), + HOOK_DEF(0x01D50420, CrossProduct), + HOOK_DEF(0x01D50460, Length), + HOOK_DEF(0x01D504A0, VectorNormalize), + //HOOK_DEF(0x, VectorInverse), + HOOK_DEF(0x01D50550, VectorScale), + //HOOK_DEF(0x, Q_log2), + //HOOK_DEF(0x, VectorMatrix), + HOOK_DEF(0x01D50640, VectorAngles), + //HOOK_DEF(0x, R_ConcatRotations), + HOOK_DEF(0x01D50850, R_ConcatTransforms), + //HOOK_DEF(0x, FloorDivMod), + //HOOK_DEF(0x, GreatestCommonDivisor), + //HOOK_DEF(0x, Invert24To16), + +#endif // Mathlib_region + +#ifndef World_region + + HOOK_DEF(0x01DB9050, ClearLink), + HOOK_DEF(0x01DB9060, RemoveLink), + HOOK_DEF(0x01DB9080, InsertLinkBefore), + //HOOK_DEF(0x01DB90A0, InsertLinkAfter), // NOXREF + HOOK_DEF(0x01DB90C0, SV_InitBoxHull), + HOOK_DEF(0x01DB9180, SV_HullForBox), + //HOOK_DEF(0x01DB91D0, SV_HullForBeam), // NOXREF + HOOK_DEF(0x01DB9640, SV_HullForBsp), + HOOK_DEF(0x01DB9780, SV_HullForEntity), + HOOK_DEF(0x01DB9850, SV_CreateAreaNode), + HOOK_DEF(0x01DB9970, SV_ClearWorld), + HOOK_DEF(0x01DB99B0, SV_UnlinkEdict), + HOOK_DEF(0x01DB99E0, SV_TouchLinks), + HOOK_DEF(0x01DB9BC0, SV_FindTouchedLeafs), + HOOK_DEF(0x01DB9CF0, SV_LinkEdict), + HOOK_DEF(0x01DC0614, SV_HullPointContents), + HOOK_DEF(0x01DB9EB0, SV_LinkContents), + HOOK_DEF(0x01DBA0A0, SV_PointContents), + HOOK_DEF(0x01DBA0F0, SV_TestEntityPosition), + HOOK_DEF(0x01DBA160, SV_RecursiveHullCheck), + HOOK_DEF(0x01DBA550, SV_SingleClipMoveToEntity), + HOOK_DEF(0x01DBA950, SV_ClipMoveToEntity), + HOOK_DEF(0x01DBA990, SV_ClipToLinks), + HOOK_DEF(0x01DBAC60, SV_ClipToWorldbrush), + HOOK_DEF(0x01DBAE00, SV_MoveBounds), + HOOK_DEF(0x01DBAE80, SV_MoveNoEnts), + HOOK_DEF(0x01DBAFC0, SV_Move), + +#endif // World_region + +#ifndef Sv_Phys_region + + //HOOK_DEF(0x01D94A90, SV_CheckAllEnts), // NOXREF + HOOK_DEF(0x01D94B00, SV_CheckVelocity), + HOOK_DEF(0x01D94C00, SV_RunThink), + HOOK_DEF(0x01D94CB0, SV_Impact), + HOOK_DEF(0x01D94D50, ClipVelocity), + HOOK_DEF(0x01D94E10, SV_FlyMove), + HOOK_DEF(0x01D952F0, SV_AddGravity), + //HOOK_DEF(0x01D95370, SV_AddCorrectGravity), // NOXREF + //HOOK_DEF(0x01D953F0, SV_FixupGravityVelocity), // NOXREF + HOOK_DEF(0x01D95450, SV_PushEntity), + HOOK_DEF(0x01D95550, SV_PushMove), + HOOK_DEF(0x01D958F0, SV_PushRotate), + HOOK_DEF(0x01D95F00, SV_Physics_Pusher), + HOOK_DEF(0x01D960F0, SV_CheckWater), + + HOOK_DEF(0x01D96290, SV_RecursiveWaterLevel), + HOOK_DEF(0x01D96310, SV_Submerged), + HOOK_DEF(0x01D96410, SV_Physics_None), + HOOK_DEF(0x01D96430, SV_Physics_Follow), + HOOK_DEF(0x01D964F0, SV_Physics_Noclip), + + HOOK_DEF(0x01D96560, SV_CheckWaterTransition), + HOOK_DEF(0x01D96740, SV_Physics_Toss), + HOOK_DEF(0x01D96B20, PF_WaterMove), + + HOOK_DEF(0x01D96E70, SV_Physics_Step), + HOOK_DEF(0x01D97240, SV_Physics), + HOOK_DEF(0x01D97480, SV_Trace_Toss), + +#endif // Sv_Phys_region + +#ifndef Sv_Move_region + + HOOK_DEF(0x01D93A40, SV_CheckBottom), + HOOK_DEF(0x01D93CB0, SV_movetest), + HOOK_DEF(0x01D93ED0, SV_movestep), + HOOK_DEF(0x01D94250, SV_StepDirection), + HOOK_DEF(0x01D942D0, SV_FlyDirection), + HOOK_DEF(0x01D94310, SV_FixCheckBottom), + //HOOK_DEF(0x01D94330, SV_NewChaseDir), // NOXREF + //HOOK_DEF(0x01D94620, SV_CloseEnough), // NOXREF + //HOOK_DEF(0x01D94680, SV_ReachedGoal), // NOXREF + HOOK_DEF(0x01D946D0, SV_NewChaseDir2), + HOOK_DEF(0x01D949C0, SV_MoveToOrigin_I), + +#endif // Sv_Move_region + +#ifndef Sv_pmove_region + + HOOK_DEF(0x01D975F0, PM_SV_PlaybackEventFull), + HOOK_DEF(0x01D97630, PM_SV_PlaySound), + HOOK_DEF(0x01D97670, PM_SV_TraceTexture), + +#endif // Sv_pmove_region + +#ifndef R_Studio_region + + HOOK_DEF(0x01D6F260, SV_InitStudioHull), + HOOK_DEF(0x01D6F2F0, R_CheckStudioCache), + //HOOK_DEF(0x01D6F3C0, R_AddToStudioCache), // NOXREF + HOOK_DEF(0x01D6F500, AngleQuaternion), + HOOK_DEF(0x01D6F600, QuaternionSlerp), + HOOK_DEF(0x01D6F810, QuaternionMatrix), + HOOK_DEF(0x01D6F900, R_StudioCalcBoneAdj), + HOOK_DEF(0x01D6FB60, R_StudioCalcBoneQuaterion), + HOOK_DEF(0x01D6FD20, R_StudioCalcBonePosition), + HOOK_DEF(0x01D6FE70, R_StudioSlerpBones), + HOOK_DEF(0x01D6FF80, R_GetAnim), + HOOK_DEF(0x01D70020, SV_StudioSetupBones), + HOOK_DEF(0x01D70390, SV_SetStudioHullPlane), + HOOK_DEF(0x01D70400, R_StudioHull), + HOOK_DEF(0x01D70A40, SV_HitgroupForStudioHull), + //HOOK_DEF(0x01D70A50, R_InitStudioCache), // NOXREF + //HOOK_DEF(0x01D70A90, R_FlushStudioCache), // NOXREF + HOOK_DEF(0x01D70AA0, R_StudioBodyVariations), + HOOK_DEF(0x01D70AF0, R_StudioPlayerBlend), + HOOK_DEF(0x01D70BD0, SV_HullForStudioModel), + HOOK_DEF(0x01D70E10, DoesSphereIntersect), + HOOK_DEF(0x01D70ED0, SV_CheckSphereIntersection), + HOOK_DEF(0x01D70FF0, AnimationAutomove), + HOOK_DEF(0x01D71000, GetBonePosition), + HOOK_DEF(0x01D710A0, GetAttachment), + HOOK_DEF(0x01D71170, ModelFrameCount), + HOOK_DEF(0x01D76260, R_StudioBoundVertex), + HOOK_DEF(0x01D762F0, R_StudioBoundBone), + HOOK_DEF(0x01D76380, R_StudioAccumulateBoneVerts), + HOOK_DEF(0x01D76420, R_StudioComputeBounds), + HOOK_DEF(0x01D76600, R_GetStudioBounds), + HOOK_DEF(0x01D76C40, R_ResetSvBlending), + +#endif // R_Studio_region + +#ifndef Net_ws_region + + HOOK_DEF(0x01D57050, NET_ThreadLock), + HOOK_DEF(0x01D57070, NET_ThreadUnlock), + HOOK_DEF(0x01D57090, Q_ntohs), + HOOK_DEF(0x01D570A0, NetadrToSockadr), + HOOK_DEF(0x01D57160, SockadrToNetadr), + HOOK_DEF(0x01D571D0, NET_HostToNetShort), // NOXREF + HOOK_DEF(0x01D571E0, NET_CompareAdr), + HOOK_DEF(0x01D57270, NET_CompareClassBAdr), + HOOK_DEF(0x01D572C0, NET_IsReservedAdr), + HOOK_DEF(0x01D57310, NET_CompareBaseAdr), + HOOK_DEF(0x01D57380, NET_AdrToString), + HOOK_DEF(0x01D574A0, NET_BaseAdrToString), + HOOK_DEF(0x01D575A0, NET_StringToSockaddr), + HOOK_DEF(0x01D57820, NET_StringToAdr), + HOOK_DEF(0x01D57890, NET_IsLocalAddress), + HOOK_DEF(0x01D578A0, NET_ErrorString), + HOOK_DEF(0x01D57B20, NET_TransferRawData), + HOOK_DEF(0x01D57B50, NET_GetLoopPacket), + HOOK_DEF(0x01D57C00, NET_SendLoopPacket), + HOOK_DEF(0x01D57C80, NET_RemoveFromPacketList), + HOOK_DEF(0x01D57CA0, NET_CountLaggedList), + HOOK_DEF(0x01D57CC0, NET_ClearLaggedList), + HOOK_DEF(0x01D57D10, NET_AddToLagged), + HOOK_DEF(0x01D57D80, NET_AdjustLag), + HOOK_DEF(0x01D57EC0, NET_LagPacket), + HOOK_DEF(0x01D58090, NET_FlushSocket), + HOOK_DEF(0x01D580E0, NET_GetLong), + HOOK_DEF(0x01D582F0, NET_QueuePacket), + +#ifdef __linux__ + //HOOK_DEF(0x0, NET_Sleep_Timeout), +#endif // __linux__ + + HOOK_DEF(0x01D584A0, NET_Sleep), + HOOK_DEF(0x01D58630, NET_StartThread), + HOOK_DEF(0x01D586B0, NET_StopThread), + HOOK_DEF(0x01D586F0, net_malloc), + HOOK_DEF(0x01D58710, NET_AllocMsg), + HOOK_DEF(0x01D58760, NET_FreeMsg), + HOOK_DEF(0x01D587A0, NET_GetPacket), + HOOK_DEF(0x01D588B0, NET_AllocateQueues), + HOOK_DEF(0x01D588F0, NET_FlushQueues), + HOOK_DEF(0x01D58960, NET_SendLong), + HOOK_DEF(0x01D58AE0, NET_SendPacket), + HOOK_DEF(0x01D58C80, NET_IPSocket), + HOOK_DEF(0x01D58E80, NET_OpenIP), +#ifdef _WIN32 + HOOK_DEF(0x01D59000, NET_IPXSocket), + HOOK_DEF(0x01D59170, NET_OpenIPX), +#endif //_WIN32 + HOOK_DEF(0x01D59240, NET_GetLocalAddress), + HOOK_DEF(0x01D59410, NET_IsConfigured), + HOOK_DEF(0x01D59420, NET_Config), + HOOK_DEF(0x01D596F0, MaxPlayers_f), + HOOK_DEF(0x01D594D0, NET_Init), + HOOK_DEF(0x01D59790, NET_ClearLagData), + HOOK_DEF(0x01D597E0, NET_Shutdown), + HOOK_DEF(0x01D59810, NET_JoinGroup), + HOOK_DEF(0x01D59870, NET_LeaveGroup), + +#endif // Net_ws_region + +#ifndef Net_chan_region + + HOOK_DEF(0x01D54DB0, Netchan_UnlinkFragment), + HOOK_DEF(0x01D54E20, Netchan_OutOfBand), + HOOK_DEF(0x01D54EA0, Netchan_OutOfBandPrint), + HOOK_DEF(0x01D54F00, Netchan_ClearFragbufs), + HOOK_DEF(0x01D54F30, Netchan_ClearFragments), + HOOK_DEF(0x01D54FA0, Netchan_Clear), + HOOK_DEF(0x01D55040, Netchan_Setup), + HOOK_DEF(0x01D550D0, Netchan_CanPacket), + HOOK_DEF(0x01D55130, Netchan_UpdateFlow), + HOOK_DEF(0x01D55240, Netchan_Transmit), + HOOK_DEF(0x01D558E0, Netchan_FindBufferById), + HOOK_DEF(0x01D55950, Netchan_CheckForCompletion), + HOOK_DEF(0x01D55A00, Netchan_Validate), + HOOK_DEF(0x01D55A90, Netchan_Process), + HOOK_DEF(0x01D55F40, Netchan_FragSend), + HOOK_DEF(0x01D55F90, Netchan_AddBufferToList), + HOOK_DEF(0x01D55FE0, Netchan_AllocFragbuf), + HOOK_DEF(0x01D56010, Netchan_AddFragbufToTail), + HOOK_DEF(0x01D56050, Netchan_CreateFragments_), + HOOK_DEF(0x01D56210, Netchan_CreateFragments), + HOOK_DEF(0x01D56250, Netchan_CreateFileFragmentsFromBuffer), + HOOK_DEF(0x01D56450, Netchan_CreateFileFragments), + HOOK_DEF(0x01D56850, Netchan_FlushIncoming), + HOOK_DEF(0x01D568C0, Netchan_CopyNormalFragments), + HOOK_DEF(0x01D569D0, Netchan_CopyFileFragments), + //HOOK_DEF(0x01D56DB0, Netchan_IsSending), + //HOOK_DEF(0x01D56DE0, Netchan_IsReceiving), + HOOK_DEF(0x01D56E10, Netchan_IncomingReady), + //HOOK_DEF(0x01D56E40, Netchan_UpdateProgress), + HOOK_DEF(0x01D56FE0, Netchan_Init), + //HOOK_DEF(0x01D57030, Netchan_CompressPacket), // NOXREF + //HOOK_DEF(0x01D57040, Netchan_DecompressPacket), // NOXREF + +#endif // Net_chan_region + +#ifndef Hashpak_region + + HOOK_DEF(0x01D3E970, HPAK_GetDataPointer), + HOOK_DEF(0x01D3EC40, HPAK_FindResource), + HOOK_DEF(0x01D3ECB0, HPAK_AddToQueue), + HOOK_DEF(0x01D3EDC0, HPAK_FlushHostQueue), + HOOK_DEF(0x01D3EE20, HPAK_AddLump), + HOOK_DEF(0x01D3F3D0, HPAK_RemoveLump), + HOOK_DEF(0x01D3F850, HPAK_ResourceForIndex), + HOOK_DEF(0x01D3F9E0, HPAK_ResourceForHash), + HOOK_DEF(0x01D3FBA0, HPAK_List_f), + HOOK_DEF(0x01D3FE30, HPAK_CreatePak), + HOOK_DEF(0x01D40140, HPAK_Remove_f), + HOOK_DEF(0x01D401F0, HPAK_Validate_f), + HOOK_DEF(0x01D405B0, HPAK_Extract_f), + HOOK_DEF(0x01D409A0, HPAK_Init), + HOOK_DEF(0x01D409F1, HPAK_GetItem), // NOXREF + HOOK_DEF(0x01D40B90, HPAK_CheckSize), + HOOK_DEF(0x01D40CE0, HPAK_ValidatePak), + HOOK_DEF(0x01D40F80, HPAK_CheckIntegrity), + +#endif // Hashpak_region + +#ifndef Wad_region + + HOOK_DEF(0x01DB8D30, W_CleanupName), + HOOK_DEF(0x01DB8D90, W_LoadWadFile), + HOOK_DEF(0x01DB8EF0, W_GetLumpinfo), + HOOK_DEF(0x01DB8F70, W_GetLumpName), + //HOOK_DEF(0x, W_GetLumpNum), // NOXREF + HOOK_DEF(0x01DB8FF0, W_Shutdown), + HOOK_DEF(0x01DB9020, SwapPic), + +#endif // Wad_region + +#ifndef Textures_region + + HOOK_DEF(0x01DA7200, SafeRead), + HOOK_DEF(0x01DA7230, CleanupName), + HOOK_DEF(0x01DA7290, lump_sorter), + HOOK_DEF(0x01DA72E0, ForwardSlashes), + HOOK_DEF(0x01DA7300, TEX_InitFromWad), + HOOK_DEF(0x01DA75D0, TEX_CleanupWadInfo), + HOOK_DEF(0x01DA7630, TEX_LoadLump), + HOOK_DEF(0x01DA76D4, FindMiptex), + HOOK_DEF(0x01DA7740, TEX_AddAnimatingTextures), + +#endif // Textures_region + +#ifndef Sv_user_region + + HOOK_DEF(0x01D9B3B0, SV_ParseConsistencyResponse), + HOOK_DEF(0x01D9B790, SV_FileInConsistencyList), + HOOK_DEF(0x01D9B7F0, SV_TransferConsistencyInfo), + HOOK_DEF(0x01D9B960, SV_SendConsistencyList), + HOOK_DEF(0x01D9BA50, SV_PreRunCmd), + HOOK_DEF(0x01D9BA60, SV_CopyEdictToPhysent), + HOOK_DEF(0x01D9BD70, SV_AddLinksToPM_), + HOOK_DEF(0x01D9C070, SV_AddLinksToPM), + HOOK_DEF(0x01D9C1A0, SV_PlayerRunPreThink), + HOOK_DEF(0x01D9C1C0, SV_PlayerRunThink), + HOOK_DEF(0x01D9C260, SV_CheckMovingGround), + HOOK_DEF(0x01D9C340, SV_ConvertPMTrace), + HOOK_DEF(0x01D9C3A0, SV_ForceFullClientsUpdate), + HOOK_DEF(0x01D9C470, SV_RunCmd), + HOOK_DEF(0x01D9D69F, SV_ValidateClientCommand), + HOOK_DEF(0x01D9D6EF, SV_CalcClientTime), + HOOK_DEF(0x01D9D86F, SV_ComputeLatency), + HOOK_DEF(0x01D9D88F, SV_UnlagCheckTeleport), + HOOK_DEF(0x01D9D8DF, SV_GetTrueOrigin), + HOOK_DEF(0x01D9D96F, SV_GetTrueMinMax), + HOOK_DEF(0x01D9D9EF, SV_FindEntInPack), + HOOK_DEF(0x01D9DA2F, SV_SetupMove), + HOOK_DEF(0x01D9E01F, SV_RestoreMove), + HOOK_DEF(0x01D9E17F, SV_ParseStringCommand), + HOOK_DEF(0x01D9E1DF, SV_ParseDelta), + HOOK_DEF(0x01D9E1FF, SV_EstablishTimeBase), + HOOK_DEF(0x01D9E2EF, SV_ParseMove), + HOOK_DEF(0x01D9E76F, SV_ParseVoiceData), + HOOK_DEF(0x01D9E8DF, SV_IgnoreHLTV), + HOOK_DEF(0x01D9E8EF, SV_ParseCvarValue), + HOOK_DEF(0x01D9E92F, SV_ParseCvarValue2), + HOOK_DEF(0x01D9E9AF, SV_ExecuteClientMessage), + HOOK_DEF(0x01D9EACF, SV_SetPlayer), + HOOK_DEF(0x01D9EB2F, SV_ShowServerinfo_f), + HOOK_DEF(0x01D9EB4F, SV_SendEnts_f), + HOOK_DEF(0x01D9EB7F, SV_FullUpdate_f), + +#endif // Sv_user_region + +#ifndef Tmessage_region + + HOOK_DEF(0x01DA7B00, memfgets), + HOOK_DEF(0x01DA7B90, IsComment), + HOOK_DEF(0x01DA7BD0, IsStartOfText), + HOOK_DEF(0x01DA7BF0, IsEndOfText), + HOOK_DEF(0x01DA7C10, IsWhiteSpace), + //HOOK_DEF(0x01DA7C40, SkipSpace), // NOXREF + //HOOK_DEF(0x01DA7C80, SkipText), // NOXREF + //HOOK_DEF(0x01DA7CC0, ParseFloats), // NOXREF + HOOK_DEF(0x01DA7D10, TrimSpace), + //HOOK_DEF(0x01DA7D90, IsToken), // NOXREF + //HOOK_DEF(0x01DA7DD0, ParseDirective), // NOXREF + //HOOK_DEF(0x01DA80A0, TextMessageParse), // NOXREF + //HOOK_DEF(0x01DA8030, TextMessageShutdown), // NOXREF + //HOOK_DEF(0x01DA8050, TextMessageInit), // NOXREF + //HOOK_DEF(0x01DA8410, TextMessageGet), // NOXREF + +#endif // Tmessage_region + +#ifndef TraceInit_Region + + //HOOK_SYMBOLDEF(0x01DA8B60, "_ZN12CInitTrackerC2Ev", MethodThunk::Constructor), + //HOOK_SYMBOLDEF(0x01DA8BD0, "_ZN12CInitTrackerD2Ev", MethodThunk::Destructor), + + HOOK_SYMBOLDEF(0x01DA8CA0, "_ZN12CInitTracker4InitEPKcS1_i", CInitTracker::Init), + HOOK_SYMBOLDEF(0x01DA8D80, "_ZN12CInitTracker8ShutdownEPKci", CInitTracker::Shutdown), + HOOK_SYMBOLDEF(0x01DA8E60, "_Z9TraceInitPKcS0_i", TraceInit), + HOOK_SYMBOLDEF(0x01DA8E80, "_Z13TraceShutdownPKci", TraceShutdown), + +#endif // TraceInit_Region + +#ifndef Vid_null_region + + //HOOK_DEF(0x, VID_SetPalette), + //HOOK_DEF(0x, VID_ShiftPalette), + //HOOK_DEF(0x, VID_WriteBuffer), + //HOOK_DEF(0x01DB4BD0, VID_Init), + //HOOK_DEF(0x, D_FlushCaches), + //HOOK_DEF(0x, R_SetStackBase), + //HOOK_DEF(0x01D7E3D0, SCR_UpdateScreen), + //HOOK_DEF(0x, V_Init), + //HOOK_DEF(0x, Draw_Init), + //HOOK_DEF(0x, SCR_Init), + //HOOK_DEF(0x01D65630, R_Init), + //HOOK_DEF(0x01D67B20, R_ForceCVars), + //HOOK_DEF(0x01D7E320, SCR_BeginLoadingPlaque), + //HOOK_DEF(0x01D7E3A0, SCR_EndLoadingPlaque), + //HOOK_DEF(0x, R_InitSky), + //HOOK_DEF(0x01D65F70, R_MarkLeaves), + HOOK_DEF(0x01D65570, R_InitTextures), + //HOOK_DEF(0x, StartLoadingProgressBar), + //HOOK_DEF(0x01D07670, ContinueLoadingProgressBar), + //HOOK_DEF(0x01D07700, SetLoadingProgressBarStatusText), + +#endif // Vid_null_region + +#ifndef L_studio_region + + HOOK_DEF(0x01D4F0E0, Mod_LoadStudioModel), + +#endif // L_studio_region + +#ifndef Crc_region + + HOOK_DEF(0x01D2C610, CRC32_Init), + HOOK_DEF(0x01D2C620, CRC32_Final), + HOOK_DEF(0x01D2C630, CRC32_ProcessByte), + HOOK_DEF(0x01D2C660, CRC32_ProcessBuffer), + HOOK_DEF(0x01D2C8D0, COM_BlockSequenceCRCByte), + HOOK_DEF(0x01D2C970, CRC_File), // NOXREF + HOOK_DEF(0x01D2CA40, CRC_MapFile), + HOOK_DEF(0x01D2CBB0, MD5Init), + HOOK_DEF(0x01D2CBE0, MD5Update), + HOOK_DEF(0x01D2CCB0, MD5Final), + HOOK_DEF(0x01D2CD40, MD5Transform), + HOOK_DEF(0x01D2D5B0, MD5_Hash_File), + HOOK_DEF(0x01D2D6F0, MD5_Print), + +#endif // Crc_region + +#ifndef Sv_RemoteAccess_region + + // virtual functions + HOOK_SYMBOL_VIRTUAL_DEF(0x01D97850, "_ZN19CServerRemoteAccess16WriteDataRequestEPKvi", CServerRemoteAccess::WriteDataRequest), + HOOK_SYMBOL_VIRTUAL_DEF(0x01D979A0, "_ZN19CServerRemoteAccess16ReadDataResponseEPvi", CServerRemoteAccess::ReadDataResponse), + + HOOK_SYMBOLDEF(0x01D984E0, "_ZN19CServerRemoteAccess20SendMessageToAdminUIEPKc", CServerRemoteAccess::SendMessageToAdminUI), + HOOK_SYMBOLDEF(0x01D98090, "_ZN19CServerRemoteAccess17LookupStringValueEPKc", CServerRemoteAccess::LookupStringValue), + HOOK_SYMBOLDEF(0x01D97D40, "_ZN19CServerRemoteAccess11LookupValueEPKcR10CUtlBuffer", CServerRemoteAccess::LookupValue), + HOOK_SYMBOLDEF(0x01D98190, "_ZN19CServerRemoteAccess14GetUserBanListER10CUtlBuffer", CServerRemoteAccess::GetUserBanList), + HOOK_SYMBOLDEF(0x01D98280, "_ZN19CServerRemoteAccess13GetPlayerListER10CUtlBuffer", CServerRemoteAccess::GetPlayerList), + HOOK_SYMBOLDEF(0x01D983B0, "_ZN19CServerRemoteAccess10GetMapListER10CUtlBuffer", CServerRemoteAccess::GetMapList), + HOOK_SYMBOLDEF(0x01D97AD0, "_ZN19CServerRemoteAccess12RequestValueEiPKc", CServerRemoteAccess::RequestValue), + HOOK_SYMBOLDEF(0x01D97C20, "_ZN19CServerRemoteAccess8SetValueEPKcS1_", CServerRemoteAccess::SetValue), + HOOK_SYMBOLDEF(0x01D97D10, "_ZN19CServerRemoteAccess11ExecCommandEPKc", CServerRemoteAccess::ExecCommand), + + HOOK_DEF(0x01D985E0, NotifyDedicatedServerUI), + +#endif // Sv_RemoteAccess_region + +#ifndef IpratelimitWrapper_region + + //HOOK_DEF(0x01D4D990, CheckIP), + +#endif // IpratelimitWrapper_region + +#ifndef Com_custom + + HOOK_DEF(0x01D28610, COM_ClearCustomizationList), + HOOK_DEF(0x01D28740, COM_CreateCustomization), + HOOK_DEF(0x01D28980, COM_SizeofResourceList), + +#endif // Com_custom + +#ifndef Sv_upld + + HOOK_DEF(0x01D9A980, SV_CheckFile), + HOOK_DEF(0x01D9AA50, SV_ClearResourceLists), + HOOK_DEF(0x01D9AA90, SV_CreateCustomizationList), + HOOK_DEF(0x01D9ABB0, SV_Customization), + HOOK_DEF(0x01D9AD20, SV_RegisterResources), + HOOK_DEF(0x01D9AD70, SV_MoveToOnHandList), + HOOK_DEF(0x01D9ADB0, SV_AddToResourceList), + HOOK_DEF(0x01D9AE00, SV_ClearResourceList), + HOOK_DEF(0x01D9AE50, SV_RemoveFromResourceList), + HOOK_DEF(0x01D9AE80, SV_EstimateNeededResources), + HOOK_DEF(0x01D9AEF0, SV_RequestMissingResourcesFromClients), + HOOK_DEF(0x01D9AF40, SV_UploadComplete), + HOOK_DEF(0x01D9AFA0, SV_BatchUploadRequest), + HOOK_DEF(0x01D9B040, SV_RequestMissingResources), + HOOK_DEF(0x01D9B070, SV_ParseResourceList), + +#endif // Sv_upld + +#ifndef Decals + + HOOK_DEF(0x01D33EF0, Draw_Shutdown), + HOOK_DEF(0x01D33F30, Draw_DecalShutdown), + HOOK_DEF(0x01D33F60, Draw_AllocateCacheSpace), + HOOK_DEF(0x01D33F90, Draw_CacheWadInitFromFile), + HOOK_DEF(0x01D34070, Draw_CacheWadInit), + HOOK_DEF(0x01D340C0, Draw_CustomCacheWadInit), + HOOK_DEF(0x01D3A830, Draw_MiptexTexture), + HOOK_DEF(0x01D34290, Draw_CacheWadHandler), + HOOK_DEF(0x01D342B0, Draw_FreeWad), + HOOK_DEF(0x01D34380, Draw_DecalSetName), // NOXREF + HOOK_DEF(0x01D343C0, Draw_DecalIndex), // NOXREF + HOOK_DEF(0x01D34450, Draw_DecalCount), + HOOK_DEF(0x01D34460, Draw_DecalSize), + HOOK_DEF(0x01D34490, Draw_DecalName), + HOOK_DEF(0x01D344C0, Draw_DecalTexture), // NOXREF + HOOK_DEF(0x01D34560, Draw_CacheByIndex), + HOOK_DEF(0x01D34600, Draw_DecalIndexFromName), // NOXREF + HOOK_DEF(0x01D34670, Decal_ReplaceOrAppendLump), + HOOK_DEF(0x01D34710, Decal_CountLumps), + HOOK_DEF(0x01D34730, Decal_SizeLumps), + HOOK_DEF(0x01D34750, Decal_MergeInDecals), + HOOK_DEF(0x01D349A0, Decal_Init), + HOOK_DEF(0x01D34B00, CustomDecal_Validate), + HOOK_DEF(0x01D34B60, CustomDecal_Init), + HOOK_DEF(0x01D34BD0, Draw_CacheGet), // NOXREF + HOOK_DEF(0x01D34CC0, Draw_CustomCacheGet), + HOOK_DEF(0x01D34D60, Draw_CacheReload), // NOXREF + HOOK_DEF(0x01D34E40, Draw_ValidateCustomLogo), + HOOK_DEF(0x01D35000, Draw_CacheLoadFromCustom), + HOOK_DEF(0x01D35110, Draw_CacheIndex), // NOXREF + HOOK_DEF(0x01D351A9, Draw_CacheFindIndex), // NOXREF + +#endif // Decals + +#ifndef Sys_engine + + //HOOK_SYMBOLDEF(0x, "_ZN7CEngineC2Ev", MethodThunk::Constructor), + //HOOK_SYMBOLDEF(0x, "_ZN7CEngineD0Ev", MethodThunk::Destructor), + + // virtual functions + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1C80, "_ZN7CEngine6UnloadEv", CEngine::Unload), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1CA0, "_ZN7CEngine4LoadEbPcS0_", CEngine::Load), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1CF0, "_ZN7CEngine5FrameEv", CEngine::Frame), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1DD0, "_ZN7CEngine11SetSubStateEi", CEngine::SetSubState), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1DF0, "_ZN7CEngine8SetStateEi", CEngine::SetState), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1E10, "_ZN7CEngine8GetStateEv", CEngine::GetState), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1E20, "_ZN7CEngine11GetSubStateEv", CEngine::GetSubState), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1E30, "_ZN7CEngine12GetFrameTimeEv", CEngine::GetFrameTime), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1E40, "_ZN7CEngine10GetCurTimeEv", CEngine::GetCurTime), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1E50, "_ZN7CEngine13TrapKey_EventEib", CEngine::TrapKey_Event), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1E90, "_ZN7CEngine15TrapMouse_EventEib", CEngine::TrapMouse_Event), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1ED0, "_ZN7CEngine13StartTrapModeEv", CEngine::StartTrapMode), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1EE0, "_ZN7CEngine10IsTrappingEv", CEngine::IsTrapping), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1EF0, "_ZN7CEngine17CheckDoneTrappingERiS0_", CEngine::CheckDoneTrapping), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1F30, "_ZN7CEngine11SetQuittingEi", CEngine::SetQuitting), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA1F40, "_ZN7CEngine11GetQuittingEv", CEngine::GetQuitting), + +#endif // Sys_engine + +#ifndef Sys_linuxwind + + // Disable/enable all at once! + // virtual functions + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5A10, "_ZN5CGame4InitEPv", CGame::Init), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5A20, "_ZN5CGame8ShutdownEv", CGame::Shutdown), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5760, "_ZN5CGame16CreateGameWindowEv", CGame::CreateGameWindow), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA4B20, "_ZN5CGame15SleepUntilInputEi", CGame::SleepUntilInput), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5A40, "_ZN5CGame13GetMainWindowEv", CGame::GetMainWindow), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5A50, "_ZN5CGame20GetMainWindowAddressEv", CGame::GetMainWindowAddress), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5A60, "_ZN5CGame11SetWindowXYEii", CGame::SetWindowXY), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5A80, "_ZN5CGame13SetWindowSizeEii", CGame::SetWindowSize), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5B00, "_ZN5CGame13GetWindowRectEPiS0_S0_S0_", CGame::GetWindowRect), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5B40, "_ZN5CGame11IsActiveAppEv", CGame::IsActiveApp), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5B60, "_ZN5CGame13IsMultiplayerEv", CGame::IsMultiplayer), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5BB0, "_ZN5CGame17PlayStartupVideosEv", CGame::PlayStartupVideos), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5BC0, "_ZN5CGame14PlayAVIAndWaitEPKc", CGame::PlayAVIAndWait), + HOOK_SYMBOL_VIRTUAL_DEF(0x01DA5B70, "_ZN5CGame16SetCursorVisibleEb", CGame::SetCursorVisible), + +#endif // Sys_linuxwind + + { NULL, NULL, NULL }, +}; + + +AddressRef g_FunctionRefs[] = +{ +#ifndef Function_References_region + + { 0x01D4D990, "CheckIP", (size_t)&pCheckIP }, + + // Find C STD functions + { 0x01E000AE, "time", 0 }, + { 0x01E0008C, "rand", 0 }, + { 0x01E0007F, "srand", 0 }, + { 0x01E00AF1, "localtime", 0 }, + +#endif // Function_References_region + + { NULL, NULL, NULL }, +}; + +AddressRef g_DataRefs[] = +{ +#ifndef Data_References_region + + + GLOBALVAR_LINK(0x0229AE80, "pr_strings", ppr_strings), + GLOBALVAR_LINK(0x01E45C04, "gNullString", pgNullString), + GLOBALVAR_LINK(0x01E46480, "SV_UPDATE_BACKUP", pSV_UPDATE_BACKUP), + GLOBALVAR_LINK(0x01E46484, "SV_UPDATE_MASK", pSV_UPDATE_MASK), + GLOBALVAR_LINK(0x021D3E80, "gGlobalVariables", pgGlobalVariables), + GLOBALVAR_LINK(0x021D3DE0, "svs", psvs), + GLOBALVAR_LINK(0x021D4960, "sv", psv), + GLOBALVAR_LINK(0x0208F788, "gPacketSuppressed", pgPacketSuppressed), + GLOBALVAR_LINK(0x01E45C08, "giNextUserMsg", pgiNextUserMsg), + GLOBALVAR_LINK(0x0208F7A4, "hashstrings_collisions", phashstrings_collisions), + GLOBALVAR_LINK(0x0208F76C, "g_pplayerdelta", pg_pplayerdelta), + GLOBALVAR_LINK(0x0208F770, "g_pentitydelta", pg_pentitydelta), + GLOBALVAR_LINK(0x0208F774, "g_pcustomentitydelta", pg_pcustomentitydelta), + GLOBALVAR_LINK(0x0208F778, "g_pclientdelta", pg_pclientdelta), + GLOBALVAR_LINK(0x0208F77C, "g_pweapondelta", pg_pweapondelta), + GLOBALVAR_LINK(0x021C2B60, "localinfo", plocalinfo), + GLOBALVAR_LINK(0x021D3F40, "localmodels", plocalmodels), + GLOBALVAR_LINK(0x0221AD80, "ipfilters", pipfilters), + GLOBALVAR_LINK(0x021D4940, "numipfilters", pnumipfilters), + GLOBALVAR_LINK(0x0229B6C0, "userfilters", puserfilters), + GLOBALVAR_LINK(0x0208F798, "numuserfilters", pnumuserfilters), + GLOBALVAR_LINK(0x01E45F84, "sv_lan", psv_lan), + GLOBALVAR_LINK(0x01E45FAC, "sv_lan_rate", psv_lan_rate), + GLOBALVAR_LINK(0x01E45E8C, "sv_aim", psv_aim), + GLOBALVAR_LINK(0x021D1BC0, "sv_decalnames", psv_decalnames), + GLOBALVAR_LINK(0x0208F78C, "sv_decalnamecount", psv_decalnamecount), + GLOBALVAR_LINK(0x01E46274, "sv_skycolor_r", psv_skycolor_r), + GLOBALVAR_LINK(0x01E46298, "sv_skycolor_g", psv_skycolor_g), + GLOBALVAR_LINK(0x01E462BC, "sv_skycolor_b", psv_skycolor_b), + GLOBALVAR_LINK(0x01E462E0, "sv_skyvec_x", psv_skyvec_x), + GLOBALVAR_LINK(0x01E46304, "sv_skyvec_y", psv_skyvec_y), + GLOBALVAR_LINK(0x01E46328, "sv_skyvec_z", psv_skyvec_z), + GLOBALVAR_LINK(0x01E48F64, "sv_spectatormaxspeed", psv_spectatormaxspeed), + GLOBALVAR_LINK(0x01E48F90, "sv_airaccelerate", psv_airaccelerate), + GLOBALVAR_LINK(0x01E48FBC, "sv_wateraccelerate", psv_wateraccelerate), + GLOBALVAR_LINK(0x01E48FE4, "sv_waterfriction", psv_waterfriction), + GLOBALVAR_LINK(0x01E49008, "sv_zmax", psv_zmax), + GLOBALVAR_LINK(0x01E4902C, "sv_wateramp", psv_wateramp), + GLOBALVAR_LINK(0x01E49054, "sv_skyname", psv_skyname), + GLOBALVAR_LINK(0x01E46034, "mapcyclefile", pmapcyclefile), + GLOBALVAR_LINK(0x01E46060, "motdfile", pmotdfile), + GLOBALVAR_LINK(0x01E46090, "servercfgfile", pservercfgfile), + GLOBALVAR_LINK(0x01E460F0, "lservercfgfile", plservercfgfile), + GLOBALVAR_LINK(0x01E46114, "logsdir", plogsdir), + GLOBALVAR_LINK(0x01E46144, "bannedcfgfile", pbannedcfgfile), + GLOBALVAR_LINK(0x0208F790, "sv_gpNewUserMsgs", psv_gpNewUserMsgs), + GLOBALVAR_LINK(0x0208F794, "sv_gpUserMsgs", psv_gpUserMsgs), + GLOBALVAR_LINK(0x0239BCE0, "g_svmove", pg_svmove), + GLOBALVAR_LINK(0x0208F760, "sv_lastnum", psv_lastnum), + GLOBALVAR_LINK(0x02089220, "g_sv_instance_baselines", pg_sv_instance_baselines), + GLOBALVAR_LINK(0x0208F764, "g_bOutOfDateRestart", pg_bOutOfDateRestart), + GLOBALVAR_LINK(0x01E45C00, "g_userid", pg_userid), + GLOBALVAR_LINK(0x0208F768, "g_sv_delta", pg_sv_delta), + GLOBALVAR_LINK(0x0208F780, "g_peventdelta", pg_peventdelta), + GLOBALVAR_LINK(0x01E45C1C, "rcon_password", prcon_password), + GLOBALVAR_LINK(0x01E45C48, "sv_enableoldqueries", psv_enableoldqueries), + GLOBALVAR_LINK(0x01E45C74, "sv_instancedbaseline", psv_instancedbaseline), + GLOBALVAR_LINK(0x01E45C94, "sv_contact", psv_contact), + GLOBALVAR_LINK(0x01E45CC4, "sv_maxupdaterate", psv_maxupdaterate), + GLOBALVAR_LINK(0x01E45CF4, "sv_minupdaterate", psv_minupdaterate), + GLOBALVAR_LINK(0x01E45D18, "sv_filterban", psv_filterban), + GLOBALVAR_LINK(0x01E45D3C, "sv_minrate", psv_minrate), + GLOBALVAR_LINK(0x01E45D60, "sv_maxrate", psv_maxrate), + GLOBALVAR_LINK(0x01E45D84, "sv_logrelay", psv_logrelay), + GLOBALVAR_LINK(0x01E45DD0, "violence_hblood", pviolence_hblood), + GLOBALVAR_LINK(0x01E45DF8, "violence_ablood", pviolence_ablood), + GLOBALVAR_LINK(0x01E45E20, "violence_hgibs", pviolence_hgibs), + GLOBALVAR_LINK(0x01E45E48, "violence_agibs", pviolence_agibs), + GLOBALVAR_LINK(0x01E45E6C, "sv_newunit", psv_newunit), + GLOBALVAR_LINK(0x01E45ED8, "sv_clienttrace", psv_clienttrace), + GLOBALVAR_LINK(0x01E45EFC, "sv_timeout", psv_timeout), + GLOBALVAR_LINK(0x01E45F24, "sv_failuretime", psv_failuretime), + GLOBALVAR_LINK(0x01E45F44, "sv_cheats", psv_cheats), + GLOBALVAR_LINK(0x01E45F64, "sv_password", psv_password), + GLOBALVAR_LINK(0x01E45FD0, "sv_proxies", psv_proxies), + GLOBALVAR_LINK(0x01E46000, "sv_outofdatetime", psv_outofdatetime), + GLOBALVAR_LINK(0x01E460B8, "mapchangecfgfile", pmapchangecfgfile), + GLOBALVAR_LINK(0x021D1BA0, "allow_cheats", pallow_cheats), + GLOBALVAR_LINK(0x01E455A8, "mp_logecho", pmp_logecho), + GLOBALVAR_LINK(0x01E45584, "mp_logfile", pmp_logfile), + GLOBALVAR_LINK(0x01E4616C, "sv_allow_download", psv_allow_download), + GLOBALVAR_LINK(0x01E46190, "sv_send_logos", psv_send_logos), + GLOBALVAR_LINK(0x01E461B8, "sv_send_resources", psv_send_resources), + GLOBALVAR_LINK(0x01E455FC, "sv_log_singleplayer", psv_log_singleplayer), + GLOBALVAR_LINK(0x01E45620, "sv_logsecret", psv_logsecret), + GLOBALVAR_LINK(0x01E455D0, "sv_log_onefile", psv_log_onefile), + GLOBALVAR_LINK(0x01E461DC, "sv_logbans", psv_logbans), + GLOBALVAR_LINK(0x01E46204, "sv_allow_upload", psv_allow_upload), + GLOBALVAR_LINK(0x01E4622C, "sv_max_upload", psv_max_upload), + GLOBALVAR_LINK(0x01E46250, "hpk_maxsize", phpk_maxsize), + GLOBALVAR_LINK(0x01E46358, "sv_visiblemaxplayers", psv_visiblemaxplayers), + GLOBALVAR_LINK(0x01E46380, "max_queries_sec", pmax_queries_sec), + GLOBALVAR_LINK(0x01E463B0, "max_queries_sec_global", pmax_queries_sec_global), + GLOBALVAR_LINK(0x01E463DC, "max_queries_window", pmax_queries_window), + GLOBALVAR_LINK(0x01E46400, "sv_logblocks", psv_logblocks), + GLOBALVAR_LINK(0x01E46424, "sv_downloadurl", psv_downloadurl), + GLOBALVAR_LINK(0x01E4644C, "sv_allow_dlfile", psv_allow_dlfile), + GLOBALVAR_LINK(0x01E4646C, "sv_version", psv_version), + GLOBALVAR_LINK(0x0229B2A0, "sv_playermodel", psv_playermodel), + GLOBALVAR_LINK(0x026EB5E0, "cls", pcls), + GLOBALVAR_LINK(0x026F1DE0, "cl", pcl), + GLOBALVAR_LINK(0x01FED50C, "key_dest", pkey_dest), + GLOBALVAR_LINK(0x0269BB00, "g_clmove", pg_clmove), + GLOBALVAR_LINK(0x028A1454, "cl_inmovie", pcl_inmovie), + GLOBALVAR_LINK(0x01E2F0F8, "cl_name", pcl_name), + GLOBALVAR_LINK(0x01E2F1B4, "rate", prate), + GLOBALVAR_LINK(0x01E33D6C, "console", pconsole), + GLOBALVAR_LINK(0x01E39FF4, "host_name", phost_name), + GLOBALVAR_LINK(0x01E3A040, "host_speeds", phost_speeds), + GLOBALVAR_LINK(0x01E3A064, "host_profile", phost_profile), + GLOBALVAR_LINK(0x01E3A084, "developer", pdeveloper), + GLOBALVAR_LINK(0x01E3A0AC, "host_limitlocal", phost_limitlocal), + GLOBALVAR_LINK(0x01E3A0C8, "skill", pskill), + GLOBALVAR_LINK(0x01E3A0EC, "deathmatch", pdeathmatch), + GLOBALVAR_LINK(0x01E3A108, "coop", pcoop), + GLOBALVAR_LINK(0x0266AFA0, "realtime", prealtime), + GLOBALVAR_LINK(0x01FED0C0, "rolling_fps", prolling_fps), + GLOBALVAR_LINK(0x0266AF20, "host_parms", phost_parms), + GLOBALVAR_LINK(0x01FED0B4, "host_initialized", phost_initialized), + GLOBALVAR_LINK(0x0266AEC8, "host_frametime", phost_frametime), + GLOBALVAR_LINK(0x0266AED0, "host_framecount", phost_framecount), + GLOBALVAR_LINK(0x0266AEDC, "host_client", phost_client), + GLOBALVAR_LINK(0x01FED0B8, "gfNoMasterServer", pgfNoMasterServer), + GLOBALVAR_LINK(0x0266AF38, "oldrealtime", poldrealtime), + GLOBALVAR_LINK(0x0266AEC4, "host_hunklevel", phost_hunklevel), + GLOBALVAR_LINK(0x0266AF60, "host_abortserver", phost_abortserver), + GLOBALVAR_LINK(0x0266AEE0, "host_enddemo", phost_enddemo), + GLOBALVAR_LINK(0x0266AED4, "host_basepal", phost_basepal), + GLOBALVAR_LINK(0x01FD9778, "bfread", pbfread), + GLOBALVAR_LINK(0x01FD9790, "bfwrite", pbfwrite), + GLOBALVAR_LINK(0x02699D48, "msg_readcount", pmsg_readcount), + GLOBALVAR_LINK(0x02699D4C, "msg_badread", pmsg_badread), + GLOBALVAR_LINK(0x01FEB260, "decal_wad", pdecal_wad), + GLOBALVAR_LINK(0x01FEB264, "menu_wad", pmenu_wad), + GLOBALVAR_LINK(0x0266D440, "szCustName", pszCustName), + GLOBALVAR_LINK(0x0266B440, "decal_names", pdecal_names), + GLOBALVAR_LINK(0x01FEB268, "m_bDrawInitialized", pm_bDrawInitialized), + GLOBALVAR_LINK(0x01FEB25C, "gfCustomBuild", pgfCustomBuild), + GLOBALVAR_LINK(0x01FEB26C, "g_defs", pg_defs), + GLOBALVAR_LINK(0x01FEB270, "g_encoders", pg_encoders), + GLOBALVAR_LINK(0x01FEB274, "g_deltaregistry", pg_deltaregistry), + GLOBALVAR_LINK(0x021B97E0, "gNetworkTextMessageBuffer", pgNetworkTextMessageBuffer), + GLOBALVAR_LINK(0x021B9FE0, "gMessageParms", pgMessageParms), + GLOBALVAR_LINK(0x02095C8C, "gMessageTable", pgMessageTable), + GLOBALVAR_LINK(0x02095C90, "gMessageTableCount", pgMessageTableCount), + GLOBALVAR_LINK(0x01E4CE10, "gNetworkMessageNames", pgNetworkMessageNames), + GLOBALVAR_LINK(0x01E4CE30, "gNetworkTextMessage", pgNetworkTextMessage), + GLOBALVAR_LINK(0x021B61C4, "hunk_base", phunk_base), + GLOBALVAR_LINK(0x021B61C8, "hunk_tempactive", phunk_tempactive), + GLOBALVAR_LINK(0x021B61D0, "hunk_low_used", phunk_low_used), + GLOBALVAR_LINK(0x021B61D4, "hunk_size", phunk_size), + GLOBALVAR_LINK(0x021B61D8, "hunk_high_used", phunk_high_used), + GLOBALVAR_LINK(0x021B61E0, "cache_head", pcache_head), + GLOBALVAR_LINK(0x021B6238, "hunk_tempmark", phunk_tempmark), + GLOBALVAR_LINK(0x01E4DEC0, "mem_dbgfile", pmem_dbgfile), + GLOBALVAR_LINK(0x021B61CC, "mainzone", pmainzone), + GLOBALVAR_LINK(0x0266AEC0, "current_skill", pcurrent_skill), + GLOBALVAR_LINK(0x01FED1E0, "g_careerState", pg_careerState), + GLOBALVAR_LINK(0x01FED1D8, "gHostSpawnCount", pgHostSpawnCount), + GLOBALVAR_LINK(0x01E3A960, "g_pSaveGameCommentFunc", pg_pSaveGameCommentFunc), + GLOBALVAR_LINK(0x01E5C834, "g_LastScreenUpdateTime", pg_LastScreenUpdateTime), + GLOBALVAR_LINK(0x023FECB4, "scr_skipupdate", pscr_skipupdate), + GLOBALVAR_LINK(0x023FF0C0, "scr_centertime_off", pscr_centertime_off), + GLOBALVAR_LINK(0x02699460, "serverinfo", pserverinfo), + GLOBALVAR_LINK(0x026995EC, "com_argc", pcom_argc), + GLOBALVAR_LINK(0x02699708, "com_argv", pcom_argv), + GLOBALVAR_LINK(0x02699840, "com_token", pcom_token), + GLOBALVAR_LINK(0x01FE1FA0, "com_ignorecolons", pcom_ignorecolons), + GLOBALVAR_LINK(0x01FE1FA4, "s_com_token_unget", ps_com_token_unget), + GLOBALVAR_LINK(0x02699600, "com_clientfallback", pcom_clientfallback), + GLOBALVAR_LINK(0x02699720, "com_gamedir", pcom_gamedir), + GLOBALVAR_LINK(0x02699C40, "com_cmdline", pcom_cmdline), + GLOBALVAR_LINK(0x02699580, "gpszVersionString", pgpszVersionString), + GLOBALVAR_LINK(0x026995C0, "gpszProductString", pgpszProductString), + GLOBALVAR_LINK(0x02699D44, "bigendien", pbigendien), + GLOBALVAR_LINK(0x026995E8, "BigShort", pBigShort), + GLOBALVAR_LINK(0x026995E0, "LittleShort", pLittleShort), + GLOBALVAR_LINK(0x0269970C, "BigLong", pBigLong), + GLOBALVAR_LINK(0x02699710, "LittleLong", pLittleLong), + GLOBALVAR_LINK(0x026995A0, "BigFloat", pBigFloat), + GLOBALVAR_LINK(0x02699560, "LittleFloat", pLittleFloat), + GLOBALVAR_LINK(0x01FD3420, "cmd_argc", pcmd_argc), + GLOBALVAR_LINK(0x01FD3428, "cmd_argv", pcmd_argv), + GLOBALVAR_LINK(0x01FD366C, "cmd_args", pcmd_args), + GLOBALVAR_LINK(0x02699D7C, "cmd_source", pcmd_source), + GLOBALVAR_LINK(0x02699D74, "cmd_wait", pcmd_wait), + GLOBALVAR_LINK(0x01FD3670, "cmd_functions", pcmd_functions), + GLOBALVAR_LINK(0x02699D60, "cmd_text", pcmd_text), + GLOBALVAR_LINK(0x02699D84, "cmd_alias", pcmd_alias), + GLOBALVAR_LINK(0x01FE501C, "cvar_vars", pcvar_vars), + GLOBALVAR_LINK(0x026995E4, "loadcache", ploadcache), + GLOBALVAR_LINK(0x02699704, "loadbuf", ploadbuf), + GLOBALVAR_LINK(0x02699D40, "loadsize", ploadsize), + GLOBALVAR_LINK(0x01FEC4C8, "g_fallbackLocalizationFiles", pg_fallbackLocalizationFiles), + GLOBALVAR_LINK(0x01FEC4E0, "s_pBaseDir", ps_pBaseDir), + GLOBALVAR_LINK(0x01FEC6E8, "bLowViolenceBuild", pbLowViolenceBuild), + GLOBALVAR_LINK(0x01FEC6EC, "g_pFileSystem", pg_pFileSystem), + GLOBALVAR_LINK(0x01FEC6E0, "g_pFileSystemModule", pg_pFileSystemModule), + GLOBALVAR_LINK(0x01FEC6E4, "g_FileSystemFactory", pg_FileSystemFactory), + GLOBALVAR_LINK(0x01E4AAC0, "g_hfind", pg_hfind), + GLOBALVAR_LINK(0x01E4AAC8, "g_engfuncsExportedToDlls", pg_engfuncsExportedToDlls), + GLOBALVAR_LINK(0x021C2260, "gszDisconnectReason", pgszDisconnectReason), + GLOBALVAR_LINK(0x021C27C0, "gszExtendedDisconnectReason", pgszExtendedDisconnectReason), + GLOBALVAR_LINK(0x02090C64, "gfExtendedError", pgfExtendedError), + GLOBALVAR_LINK(0x021C28F8, "g_bIsDedicatedServer", pg_bIsDedicatedServer), + GLOBALVAR_LINK(0x021C2248, "giSubState", pgiSubState), + GLOBALVAR_LINK(0x021C2448, "giActive", pgiActive), + GLOBALVAR_LINK(0x02090C60, "giStateInfo", pgiStateInfo), + GLOBALVAR_LINK(0x021C2380, "gEntityInterface", pgEntityInterface), + GLOBALVAR_LINK(0x021C28E0, "gNewDLLFunctions", pgNewDLLFunctions), + GLOBALVAR_LINK(0x01FF0638, "g_modfuncs", pg_modfuncs), + GLOBALVAR_LINK(0x021C2480, "g_rgextdll", pg_rgextdll), + GLOBALVAR_LINK(0x02090C94, "g_iextdllMac", pg_iextdllMac), + GLOBALVAR_LINK(0x021C2900, "gmodinfo", pgmodinfo), + GLOBALVAR_LINK(0x02090C90, "gfBackground", pgfBackground), + GLOBALVAR_LINK(0x02699454, "con_debuglog", pcon_debuglog), + GLOBALVAR_LINK(0x02090C78, "g_bPrintingKeepAliveDots", pg_bPrintingKeepAliveDots), + GLOBALVAR_LINK(0x02090C80, "Launcher_ConsolePrintf", pLauncher_ConsolePrintf), + GLOBALVAR_LINK(0x01E42EC4, "registry", pregistry), + GLOBALVAR_LINK(0x0239B740, "outputbuf", poutputbuf), + GLOBALVAR_LINK(0x021CAB94, "sv_redirected", psv_redirected), + GLOBALVAR_LINK(0x021CAB80, "sv_redirectto", psv_redirectto), + GLOBALVAR_LINK(0x01E464A0, "sv_rcon_minfailures", psv_rcon_minfailures), + GLOBALVAR_LINK(0x01E464CC, "sv_rcon_maxfailures", psv_rcon_maxfailures), + GLOBALVAR_LINK(0x01E464FC, "sv_rcon_minfailuretime", psv_rcon_minfailuretime), + GLOBALVAR_LINK(0x01E46528, "sv_rcon_banpenalty", psv_rcon_banpenalty), + GLOBALVAR_LINK(0x0208E828, "g_rgRconFailures", pg_rgRconFailures), + GLOBALVAR_LINK(0x01E42FF8, "scr_downloading", pscr_downloading), + +#ifndef REHLDS_FIXES + GLOBALVAR_LINK(0x0208F7B8, "g_bCS_CZ_Flags_Initialized", pg_bCS_CZ_Flags_Initialized), + GLOBALVAR_LINK(0x0208F7AC, "g_bIsCZero", pg_bIsCZero), + GLOBALVAR_LINK(0x0208F7B4, "g_bIsCZeroRitual", pg_bIsCZeroRitual), + GLOBALVAR_LINK(0x0208F7B0, "g_bIsTerrorStrike", pg_bIsTerrorStrike), + GLOBALVAR_LINK(0x0208F7BC, "g_bIsTFC", pg_bIsTFC), + GLOBALVAR_LINK(0x0208F7C0, "g_bIsHL1", pg_bIsHL1), + GLOBALVAR_LINK(0x0208F7A8, "g_bIsCStrike", pg_bIsCStrike), +#endif + + GLOBALVAR_LINK(0x01FD3E80, "gPAS", pgPAS), + GLOBALVAR_LINK(0x01FD3E84, "gPVS", pgPVS), + GLOBALVAR_LINK(0x01FD3A78, "gPVSRowBytes", pgPVSRowBytes), + GLOBALVAR_LINK(0x01FD3A80, "mod_novis", pmod_novis), + GLOBALVAR_LINK(0x0229AE84, "fatbytes", pfatbytes), + GLOBALVAR_LINK(0x0229B2C0, "fatpvs", pfatpvs), + GLOBALVAR_LINK(0x0229B2A4, "fatpasbytes", pfatpasbytes), + GLOBALVAR_LINK(0x0229AEA0, "fatpas", pfatpas), + GLOBALVAR_LINK(0x0208FAB8, "s_Steam3Server", ps_Steam3Server), + GLOBALVAR_LINK(0x0208FA58, "s_Steam3Client", ps_Steam3Client), + GLOBALVAR_LINK(0x01E39F14, "sys_ticrate", psys_ticrate), + GLOBALVAR_LINK(0x01E39F3C, "sys_timescale", psys_timescale), + GLOBALVAR_LINK(0x01E39F60, "fps_max", pfps_max), + GLOBALVAR_LINK(0x01E39F84, "host_killtime", phost_killtime), + GLOBALVAR_LINK(0x01E39FA4, "sv_stats", psv_stats), + GLOBALVAR_LINK(0x01E39FC8, "fps_override", pfps_override), + GLOBALVAR_LINK(0x01E3A01C, "host_framerate", phost_framerate), + GLOBALVAR_LINK(0x01E3A128, "pausable", ppausable), + GLOBALVAR_LINK(0x01E43F6C, "suitvolume", psuitvolume), + GLOBALVAR_LINK(0x0208FAC0, "truepositions", ptruepositions), + GLOBALVAR_LINK(0x021C2B44, "sv_player", psv_player), + GLOBALVAR_LINK(0x01E4A328, "clcommands", pclcommands), + GLOBALVAR_LINK(0x0209064C, "g_balreadymoved", pg_balreadymoved), + GLOBALVAR_LINK(0x01E4A658, "sv_clcfuncs", psv_clcfuncs), + GLOBALVAR_LINK(0x020905C0, "s_LastFullUpdate", ps_LastFullUpdate), + GLOBALVAR_LINK(0x01E4A3E0, "sv_edgefriction", psv_edgefriction), + GLOBALVAR_LINK(0x01E4A404, "sv_maxspeed", psv_maxspeed), + GLOBALVAR_LINK(0x01E4A42C, "sv_accelerate", psv_accelerate), + GLOBALVAR_LINK(0x01E4A3BC, "sv_footsteps", psv_footsteps), + GLOBALVAR_LINK(0x01E4A454, "sv_rollspeed", psv_rollspeed), + GLOBALVAR_LINK(0x01E4A47C, "sv_rollangle", psv_rollangle), + GLOBALVAR_LINK(0x01E4A49C, "sv_unlag", psv_unlag), + GLOBALVAR_LINK(0x01E4A4C0, "sv_maxunlag", psv_maxunlag), + GLOBALVAR_LINK(0x01E4A4E8, "sv_unlagpush", psv_unlagpush), + GLOBALVAR_LINK(0x01E4A510, "sv_unlagsamples", psv_unlagsamples), + GLOBALVAR_LINK(0x01E4A398, "mp_consistency", pmp_consistency), + GLOBALVAR_LINK(0x01E4A568, "sv_voiceenable", psv_voiceenable), + GLOBALVAR_LINK(0x02090648, "nofind", pnofind), + GLOBALVAR_LINK(0x01E3F7F4, "pm_showclip", ppm_showclip), + GLOBALVAR_LINK(0x01E3F808, "player_mins", pplayer_mins), + GLOBALVAR_LINK(0x01E3F838, "player_maxs", pplayer_maxs), + GLOBALVAR_LINK(0x02004308, "pmove", ppmove), + GLOBALVAR_LINK(0x025E3F00, "movevars", pmovevars), + GLOBALVAR_LINK(0x01FED51C, "vec3_origin", pvec3_origin), + GLOBALVAR_LINK(0x02004980, "gMsgData", pgMsgData), + GLOBALVAR_LINK(0x01E3F9AC, "gMsgBuffer", pgMsgBuffer), + GLOBALVAR_LINK(0x02004B80, "gMsgEntity", pgMsgEntity), + GLOBALVAR_LINK(0x02004B84, "gMsgDest", pgMsgDest), + GLOBALVAR_LINK(0x02004B88, "gMsgType", pgMsgType), + GLOBALVAR_LINK(0x02004B8C, "gMsgStarted", pgMsgStarted), + GLOBALVAR_LINK(0x020043A8, "gMsgOrigin", pgMsgOrigin), + GLOBALVAR_LINK(0x02004B90, "idum", pidum), + GLOBALVAR_LINK(0x02004B9C, "g_groupop", pg_groupop), + GLOBALVAR_LINK(0x02004B98, "g_groupmask", pg_groupmask), + GLOBALVAR_LINK(0x025E39E0, "checkpvs", pcheckpvs), + GLOBALVAR_LINK(0x025E3DE0, "c_invis", pc_invis), + GLOBALVAR_LINK(0x025E39CC, "c_notvis", pc_notvis), + GLOBALVAR_LINK(0x0208F7E0, "vec_origin", pvec_origin), + GLOBALVAR_LINK(0x025DFD94, "r_visframecount", pr_visframecount), + GLOBALVAR_LINK(0x02052A48, "cache_hull_hitgroup", pcache_hull_hitgroup), + GLOBALVAR_LINK(0x0206FB60, "cache_hull", pcache_hull), + GLOBALVAR_LINK(0x0201CDC8, "cache_planes", pcache_planes), + GLOBALVAR_LINK(0x0206FB50, "pstudiohdr", ppstudiohdr), + GLOBALVAR_LINK(0x0200A398, "studio_hull", pstudio_hull), + GLOBALVAR_LINK(0x02052C48, "studio_hull_hitgroup", pstudio_hull_hitgroup), + GLOBALVAR_LINK(0x0200C998, "studio_planes", pstudio_planes), + GLOBALVAR_LINK(0x02052E48, "studio_clipnodes", pstudio_clipnodes), + GLOBALVAR_LINK(0x0206E908, "rgStudioCache", prgStudioCache), + GLOBALVAR_LINK(0x0206FB54, "r_cachecurrent", pr_cachecurrent), + GLOBALVAR_LINK(0x02016DC4, "nCurrentHull", pnCurrentHull), + GLOBALVAR_LINK(0x0200A384, "nCurrentPlane", pnCurrentPlane), + GLOBALVAR_LINK(0x025DD0E0, "bonetransform", pbonetransform), + GLOBALVAR_LINK(0x01E42284, "r_cachestudio", pr_cachestudio), + GLOBALVAR_LINK(0x01E424E8, "g_pSvBlendingAPI", pg_pSvBlendingAPI), + GLOBALVAR_LINK(0x01E424E0, "svBlending", psvBlending), + GLOBALVAR_LINK(0x01E424D0, "server_studio_api", pserver_studio_api), + GLOBALVAR_LINK(0x025DEEE0, "rotationmatrix", protationmatrix), + GLOBALVAR_LINK(0x021B1568, "box_hull", pbox_hull, 1), + GLOBALVAR_LINK(0x021B1540, "beam_hull", pbeam_hull), + GLOBALVAR_LINK(0x021B1590, "box_clipnodes", pbox_clipnodes, 1), + GLOBALVAR_LINK(0x021B15C0, "box_planes", pbox_planes, 1), + GLOBALVAR_LINK(0x021B14C8, "beam_planes", pbeam_planes), + GLOBALVAR_LINK(0x021B6240, "sv_areanodes", psv_areanodes), + GLOBALVAR_LINK(0x021B6640, "sv_numareanodes", psv_numareanodes), + GLOBALVAR_LINK(0x02004310, "g_contentsresult", pg_contentsresult), + GLOBALVAR_LINK(0x025E3E00, "box_hull", pbox_hull_0, 2), + GLOBALVAR_LINK(0x025E3E40, "box_clipnodes", pbox_clipnodes_0, 2), + GLOBALVAR_LINK(0x025E3E80, "box_planes", pbox_planes_0, 2), + GLOBALVAR_LINK(0x01E48EF0, "sv_maxvelocity", psv_maxvelocity), + GLOBALVAR_LINK(0x01E48EC4, "sv_gravity", psv_gravity), + GLOBALVAR_LINK(0x01E48F34, "sv_bounce", psv_bounce), + GLOBALVAR_LINK(0x01E48F14, "sv_stepsize", psv_stepsize), + GLOBALVAR_LINK(0x01E48E78, "sv_friction", psv_friction), + GLOBALVAR_LINK(0x01E48EA0, "sv_stopspeed", psv_stopspeed), + GLOBALVAR_LINK(0x021C2B48, "g_moved_from", pg_moved_from), + GLOBALVAR_LINK(0x021C2B4C, "sv_numareanodes", pg_moved_edict), + GLOBALVAR_LINK(0x021C2B50, "c_yes", pc_yes), + GLOBALVAR_LINK(0x021C2B54, "c_no", pc_no), + GLOBALVAR_LINK(0x020042AC, "net_thread_initialized", pnet_thread_initialized), + GLOBALVAR_LINK(0x01E3E8DC, "net_address", pnet_address), + GLOBALVAR_LINK(0x01E3E900, "ipname", pipname), + GLOBALVAR_LINK(0x01E3E968, "defport", pdefport), + GLOBALVAR_LINK(0x01E3E98C, "ip_clientport", pip_clientport), + GLOBALVAR_LINK(0x01E3E9B4, "clientport", pclientport), + GLOBALVAR_LINK(0x01E3EB34, "net_sleepforever", pnet_sleepforever), + GLOBALVAR_LINK(0x01FF2B60, "loopbacks", ploopbacks), + GLOBALVAR_LINK(0x01FF2AE8, "g_pLagData", pg_pLagData), + GLOBALVAR_LINK(0x020042D8, "gFakeLag", pgFakeLag), + GLOBALVAR_LINK(0x020042FC, "net_configured", pnet_configured), + GLOBALVAR_LINK(0x025F4020, "net_message", pnet_message), + GLOBALVAR_LINK(0x025F4040, "net_local_adr", pnet_local_adr), + GLOBALVAR_LINK(0x02604060, "net_from", pnet_from), + GLOBALVAR_LINK(0x020042BC, "noip", pnoip), + GLOBALVAR_LINK(0x01E3E9D8, "clockwindow", pclockwindow), + GLOBALVAR_LINK(0x020042B0, "use_thread", puse_thread), + GLOBALVAR_LINK(0x025F4000, "in_message", pin_message), + GLOBALVAR_LINK(0x025F3FC0, "in_from", pin_from), + GLOBALVAR_LINK(0x020042C0, "ip_sockets", pip_sockets), + GLOBALVAR_LINK(0x01E3E924, "iphostport", piphostport), + GLOBALVAR_LINK(0x01E3E944, "hostport", phostport), + GLOBALVAR_LINK(0x01E3EA04, "multicastport", pmulticastport), + GLOBALVAR_LINK(0x01E3EA70, "fakelag", pfakelag), + GLOBALVAR_LINK(0x01E3EA94, "fakeloss", pfakeloss), + GLOBALVAR_LINK(0x01E3EAB4, "net_graph", pnet_graph), + GLOBALVAR_LINK(0x01E3EADC, "net_graphwidth", pnet_graphwidth), + GLOBALVAR_LINK(0x01E3EAFC, "net_scale", pnet_scale), + GLOBALVAR_LINK(0x01E3EB20, "net_graphpos", pnet_graphpos), + GLOBALVAR_LINK(0x025F4060, "net_message_buffer", pnet_message_buffer), + GLOBALVAR_LINK(0x025E3FC0, "in_message_buf", pin_message_buf), + +#ifdef _WIN32 + GLOBALVAR_LINK(0x025F3FE0, "net_local_ipx_adr", pnet_local_ipx_adr), + GLOBALVAR_LINK(0x020042B8, "noipx", pnoipx), + GLOBALVAR_LINK(0x01E3EA28, "ipx_hostport", pipx_hostport), + GLOBALVAR_LINK(0x01E3EA50, "ipx_clientport", pipx_clientport), + GLOBALVAR_LINK(0x020042CC, "ipx_sockets", pipx_sockets), +#endif // _WIN32 + + GLOBALVAR_LINK(0x02604080, "gNetSplit", pgNetSplit), + GLOBALVAR_LINK(0x020042E8, "messages", pmessages), + GLOBALVAR_LINK(0x020042F4, "normalqueue", pnormalqueue), + GLOBALVAR_LINK(0x02605040, "gDownloadFile", pgDownloadFile), + GLOBALVAR_LINK(0x02605140, "net_drop", pnet_drop), + GLOBALVAR_LINK(0x01E3E00C, "net_log", pnet_log), + GLOBALVAR_LINK(0x01E3E034, "net_showpackets", pnet_showpackets), + GLOBALVAR_LINK(0x01E3E058, "net_showdrop", pnet_showdrop), + GLOBALVAR_LINK(0x01E3E080, "net_drawslider", pnet_drawslider), + GLOBALVAR_LINK(0x01E3E0A4, "net_chokeloopback", pnet_chokeloopback), + GLOBALVAR_LINK(0x01E3E0D8, "sv_filetransfercompression", psv_filetransfercompression), + GLOBALVAR_LINK(0x01E3E110, "sv_filetransfermaxsize", psv_filetransfermaxsize), + +#ifdef _WIN32 + GLOBALVAR_LINK(0x02090C88, "g_PerfCounterInitialized", pg_PerfCounterInitialized), + GLOBALVAR_LINK(0x021C2460, "g_PerfCounterMutex", pg_PerfCounterMutex), + GLOBALVAR_LINK(0x021C2454, "g_PerfCounterShiftRightAmount", pg_PerfCounterShiftRightAmount), + GLOBALVAR_LINK(0x021C28C0, "g_PerfCounterSlice", pg_PerfCounterSlice), + GLOBALVAR_LINK(0x02090C68, "g_CurrentTime", pg_CurrentTime), + GLOBALVAR_LINK(0x02090C70, "g_StartTime", pg_StartTime), + GLOBALVAR_LINK(0x01E4E98C, "g_FPUCW_Mask_Prec_64Bit", pg_FPUCW_Mask_Prec_64Bit), + GLOBALVAR_LINK(0x01E4E990, "g_FPUCW_Mask_Prec_64Bit_2", pg_FPUCW_Mask_Prec_64Bit_2), + GLOBALVAR_LINK(0x01E4E988, "g_FPUCW_Mask_ZeroDiv_OFlow", pg_FPUCW_Mask_Round_Trunc), + GLOBALVAR_LINK(0x01E4E984, "g_FPUCW_Mask_OFlow", pg_FPUCW_Mask_Round_Up), + GLOBALVAR_LINK(0x021C2244, "g_WinNTOrHigher", pg_WinNTOrHigher), + GLOBALVAR_LINK(0x020914E4, "g_bIsWin95", pg_bIsWin95), + GLOBALVAR_LINK(0x020914E8, "g_bIsWin98", pg_bIsWin98), +#endif // _WIN32 + + GLOBALVAR_LINK(0x02605180, "loadmodel", ploadmodel), + GLOBALVAR_LINK(0x02605160, "loadname", ploadname), + GLOBALVAR_LINK(0x026051A0, "mod_known", pmod_known), + GLOBALVAR_LINK(0x02605144, "mod_numknown", pmod_numknown), + GLOBALVAR_LINK(0x026671A0, "mod_base", pmod_base), + GLOBALVAR_LINK(0x01FF062C, "wadpath", pwadpath), + GLOBALVAR_LINK(0x01FF0630, "tested", ptested), + GLOBALVAR_LINK(0x01FF0634, "ad_enabled", pad_enabled), + GLOBALVAR_LINK(0x026671C0, "ad_wad", pad_wad), + GLOBALVAR_LINK(0x01FED528, "mod_known_info", pmod_known_info), + GLOBALVAR_LINK(0x02095B48, "lumpinfo", plumpinfo), + GLOBALVAR_LINK(0x02095B4C, "nTexLumps", pnTexLumps), + GLOBALVAR_LINK(0x021C2040, "texfiles", ptexfiles), + GLOBALVAR_LINK(0x02095B44, "nTexFiles", pnTexFiles), + GLOBALVAR_LINK(0x021B7660, "texgammatable", ptexgammatable), + GLOBALVAR_LINK(0x025DFCE4, "r_notexture_mip", pr_notexture_mip), + GLOBALVAR_LINK(0x021C2020, "nummiptex", pnummiptex), + GLOBALVAR_LINK(0x021BA020, "miptex", pmiptex), + GLOBALVAR_LINK(0x01E41A30, "r_wadtextures", pr_wadtextures), + GLOBALVAR_LINK(0x01E42270, "r_dointerp", pr_dointerp), + GLOBALVAR_LINK(0x025DFE40, "r_origin", pr_origin), + GLOBALVAR_LINK(0x01E415BC, "r_pixbytes", pr_pixbytes), + GLOBALVAR_LINK(0x01E43090, "gl_vsync", pgl_vsync), + GLOBALVAR_LINK(0x023FF0D0, "scr_con_current", pscr_con_current), + GLOBALVAR_LINK(0x0208F7EC, "g_ServerRemoteAccess", pg_ServerRemoteAccess), + GLOBALVAR_LINK(0x01FED1E8, "cpuPercent", pcpuPercent), + GLOBALVAR_LINK(0x01FED1D4, "startTime", pstartTime), + GLOBALVAR_LINK(0x01FED1E4, "g_bMajorMapChange", pg_bMajorMapChange), + GLOBALVAR_LINK(0x01E3A97C, "voice_recordtofile", pvoice_recordtofile), + GLOBALVAR_LINK(0x01E3A9A8, "voice_inputfromfile", pvoice_inputfromfile), + GLOBALVAR_LINK(0x01E3B250, "gTitleComments", pgTitleComments), + GLOBALVAR_LINK(0x01E3A9D8, "gGameHeaderDescription", pgGameHeaderDescription), + GLOBALVAR_LINK(0x01E3AAA0, "gSaveHeaderDescription", pgSaveHeaderDescription), + GLOBALVAR_LINK(0x01E3ABB0, "gAdjacencyDescription", pgAdjacencyDescription), + GLOBALVAR_LINK(0x01E3AC20, "gEntityTableDescription", pgEntityTableDescription), + GLOBALVAR_LINK(0x01E3AC80, "gLightstyleDescription", pgLightstyleDescription), + GLOBALVAR_LINK(0x01E3ACB0, "gHostMap", pgHostMap), + GLOBALVAR_LINK(0x01FED208, "g_iQuitCommandIssued", pg_iQuitCommandIssued), + GLOBALVAR_LINK(0x01FED20C, "g_pPostRestartCmdLineArgs", pg_pPostRestartCmdLineArgs), + GLOBALVAR_LINK(0x021CABA0, "g_rg_sv_challenges", pg_rg_sv_challenges), + GLOBALVAR_LINK(0x0239BCC0, "g_svdeltacallback", pg_svdeltacallback), + GLOBALVAR_LINK(0x01FED4D0, "_ZL11rateChecker", prateChecker), + GLOBALVAR_LINK(0x01FEC7F4, "gp_hpak_queue", pgp_hpak_queue), + GLOBALVAR_LINK(0x01FEC7F8, "hash_pack_dir", phash_pack_dir), + GLOBALVAR_LINK(0x0266AFB0, "hash_pack_header", phash_pack_header), + GLOBALVAR_LINK(0x020891D8, "firstLog", pfirstLog), + GLOBALVAR_LINK(0x01E4C6C4, "game", pgame), + GLOBALVAR_LINK(0x01E4BB44, "eng", peng), + GLOBALVAR_LINK(0x021B1468, "wads", pwads), + GLOBALVAR_LINK(0x01FF06B0, "g_module", pg_module), + GLOBALVAR_LINK(0x020914E0, "dedicated", pdedicated), + GLOBALVAR_LINK(0x020914E4, "g_bIsWin95", pg_bIsWin95), + GLOBALVAR_LINK(0x020914E8, "g_bIsWin98", pg_bIsWin98), + GLOBALVAR_LINK(0x020914F8, "g_flLastSteamProgressUpdateTime", pg_flLastSteamProgressUpdateTime), + GLOBALVAR_LINK(0x01E4B3E0, "szCommonPreloads", pszCommonPreloads), + GLOBALVAR_LINK(0x01E4B3F0, "szReslistsBaseDir", pszReslistsBaseDir), + GLOBALVAR_LINK(0x01E4B3FC, "szReslistsExt", pszReslistsExt), + GLOBALVAR_LINK(0x02095C98, "g_InitTracker", pg_InitTracker), + +#ifndef _WIN32 + //GLOBALVAR_LINK(0x0, "gHasMMXTechnology", pgHasMMXTechnology), +#endif + +#endif // Data_References_region + + { NULL, NULL, NULL }, +}; diff --git a/rehlds/hookers/engine/hooklist.h b/rehlds/hookers/engine/hooklist.h new file mode 100644 index 0000000..9016390 --- /dev/null +++ b/rehlds/hookers/engine/hooklist.h @@ -0,0 +1,5 @@ +#pragma once + +#include "hookers/memory.h" +#include "hookers/helper.h" +#include "hookers/hooker.h" diff --git a/rehlds/hookers/main.cpp b/rehlds/hookers/engine/main.cpp similarity index 92% rename from rehlds/hookers/main.cpp rename to rehlds/hookers/engine/main.cpp index e68c643..0f0d9ab 100644 --- a/rehlds/hookers/main.cpp +++ b/rehlds/hookers/engine/main.cpp @@ -1,120 +1,115 @@ -/* -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2 of the License, or (at -* your option) any later version. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* In addition, as a special exception, the author gives permission to -* link the code of this program with the Half-Life Game Engine ("HL -* Engine") and Modified Game Libraries ("MODs") developed by Valve, -* L.L.C ("Valve"). You must obey the GNU General Public License in all -* respects for all of the code used other than the HL Engine and MODs -* from Valve. If you modify this file, you may extend this exception -* to your version of the file, but you are not obligated to do so. If -* you do not wish to do so, delete this exception statement from your -* version. -* -*/ - -#include "precompiled.h" - - -int HookEngine(size_t addr); - - -IBaseInterface* CreateFileSystemInterface(void); -InterfaceReg iface = InterfaceReg(CreateFileSystemInterface, "VFileSystem009"); - -#ifdef _WIN32 -#define ORIGINAL_ENGINE_DLL_NAME "swds.dll" -#define ORIGINAL_FILESYSTEM_DLL_NAME "filesystem_stdio2.dll" -#else -#define ORIGINAL_ENGINE_DLL_NAME "engine_i486.so" -#define ORIGINAL_FILESYSTEM_DLL_NAME "filesystem_stdio2.so" -#endif - -CSysModule *g_pOriginalFileSystemModule = NULL; -CreateInterfaceFn g_OriginalFileSystemFactory = NULL; -IFileSystem *g_pOriginalFileSystem = NULL; - - -IBaseInterface *CreateFileSystemInterface(void) -{ - if (g_pOriginalFileSystem) - return g_pOriginalFileSystem; - - if (g_pOriginalFileSystemModule) - { - g_OriginalFileSystemFactory = Sys_GetFactory(g_pOriginalFileSystemModule); - if (g_OriginalFileSystemFactory) - { - int returnCode = 0; - g_pOriginalFileSystem = reinterpret_cast(g_OriginalFileSystemFactory(FILESYSTEM_INTERFACE_VERSION, &returnCode)); - return g_pOriginalFileSystem; - } - } - - return NULL; -} - -#ifdef _WIN32 - -// DLL entry point -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - if (fdwReason == DLL_PROCESS_ATTACH) - { - g_RehldsRuntimeConfig.parseFromCommandLine(GetCommandLineA()); - -#ifdef HOOK_ENGINE - size_t addr = (size_t)Sys_GetProcAddress(ORIGINAL_ENGINE_DLL_NAME, CREATEINTERFACE_PROCNAME); - HookEngine(addr); - - g_pOriginalFileSystemModule = Sys_LoadModule(ORIGINAL_FILESYSTEM_DLL_NAME); -#endif // HOOK_ENGINE - } - else if (fdwReason == DLL_PROCESS_DETACH) - { - if (g_pOriginalFileSystemModule) - { - Sys_UnloadModule(g_pOriginalFileSystemModule); - g_pOriginalFileSystemModule = NULL; - g_OriginalFileSystemFactory = NULL; - g_pOriginalFileSystem = NULL; - } - } - return TRUE; -} - -#else // _WIN32 - -void __attribute__((constructor)) DllMainLoad() -{ - size_t addr = (size_t)Sys_GetProcAddress(ORIGINAL_ENGINE_DLL_NAME, CREATEINTERFACE_PROCNAME); - HookEngine(addr); - - g_pOriginalFileSystemModule = Sys_LoadModule(ORIGINAL_FILESYSTEM_DLL_NAME); -} - -void __attribute__((destructor)) DllMainUnload() -{ - if (g_pOriginalFileSystemModule) - { - Sys_UnloadModule(g_pOriginalFileSystemModule); - g_pOriginalFileSystemModule = NULL; - g_OriginalFileSystemFactory = NULL; - g_pOriginalFileSystem = NULL; - } -} - -#endif // _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +IBaseInterface *CreateFileSystemInterface(); +InterfaceReg iface = InterfaceReg(CreateFileSystemInterface, "VFileSystem009"); + +#ifdef _WIN32 +#define ORIGINAL_ENGINE_DLL_NAME "swds.dll" +#define ORIGINAL_FILESYSTEM_DLL_NAME "filesystem_stdio2.dll" +#else +#define ORIGINAL_ENGINE_DLL_NAME "engine_i486.so" +#define ORIGINAL_FILESYSTEM_DLL_NAME "filesystem_stdio2.so" +#endif + +CSysModule *g_pOriginalFileSystemModule = NULL; +CreateInterfaceFn g_OriginalFileSystemFactory = NULL; +IFileSystem *g_pOriginalFileSystem = NULL; + +IBaseInterface *CreateFileSystemInterface() +{ + if (g_pOriginalFileSystem) + return g_pOriginalFileSystem; + + if (g_pOriginalFileSystemModule) + { + g_OriginalFileSystemFactory = Sys_GetFactory(g_pOriginalFileSystemModule); + if (g_OriginalFileSystemFactory) + { + int returnCode = 0; + g_pOriginalFileSystem = reinterpret_cast(g_OriginalFileSystemFactory(FILESYSTEM_INTERFACE_VERSION, &returnCode)); + return g_pOriginalFileSystem; + } + } + + return NULL; +} + +#ifdef _WIN32 + +// DLL entry point +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + g_RehldsRuntimeConfig.parseFromCommandLine(GetCommandLineA()); + +#ifdef HOOK_ENGINE + size_t addr = (size_t)Sys_GetProcAddress(ORIGINAL_ENGINE_DLL_NAME, CREATEINTERFACE_PROCNAME); + HookModule("hlds.exe", addr); + + g_pOriginalFileSystemModule = Sys_LoadModule(ORIGINAL_FILESYSTEM_DLL_NAME); +#endif // HOOK_ENGINE + } + else if (fdwReason == DLL_PROCESS_DETACH) + { + if (g_pOriginalFileSystemModule) + { + Sys_UnloadModule(g_pOriginalFileSystemModule); + g_pOriginalFileSystemModule = NULL; + g_OriginalFileSystemFactory = NULL; + g_pOriginalFileSystem = NULL; + } + } + return TRUE; +} + +#else // _WIN32 + +void __attribute__((constructor)) DllMainLoad() +{ + size_t addr = (size_t)Sys_GetProcAddress(ORIGINAL_ENGINE_DLL_NAME, CREATEINTERFACE_PROCNAME); + HookModule("hlds.exe", addr); + + g_pOriginalFileSystemModule = Sys_LoadModule(ORIGINAL_FILESYSTEM_DLL_NAME); +} + +void __attribute__((destructor)) DllMainUnload() +{ + if (g_pOriginalFileSystemModule) + { + Sys_UnloadModule(g_pOriginalFileSystemModule); + g_pOriginalFileSystemModule = NULL; + g_OriginalFileSystemFactory = NULL; + g_pOriginalFileSystem = NULL; + } +} + +#endif // _WIN32 diff --git a/rehlds/hookers/main_swds.cpp b/rehlds/hookers/engine/main_swds.cpp similarity index 95% rename from rehlds/hookers/main_swds.cpp rename to rehlds/hookers/engine/main_swds.cpp index 35fcd79..8eb96fe 100644 --- a/rehlds/hookers/main_swds.cpp +++ b/rehlds/hookers/engine/main_swds.cpp @@ -1,70 +1,70 @@ -/* -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2 of the License, or (at -* your option) any later version. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* In addition, as a special exception, the author gives permission to -* link the code of this program with the Half-Life Game Engine ("HL -* Engine") and Modified Game Libraries ("MODs") developed by Valve, -* L.L.C ("Valve"). You must obey the GNU General Public License in all -* respects for all of the code used other than the HL Engine and MODs -* from Valve. If you modify this file, you may extend this exception -* to your version of the file, but you are not obligated to do so. If -* you do not wish to do so, delete this exception statement from your -* version. -* -*/ - -#include "precompiled.h" - -#ifdef _WIN32 - -// DLL entry point -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - if (fdwReason == DLL_PROCESS_ATTACH) - { - g_RehldsRuntimeConfig.parseFromCommandLine(GetCommandLineA()); - -#ifdef _WIN32 - Module hlds_exe; - if (!FindModuleByName("hlds.exe", &hlds_exe)) - printf("%s: launcher is not hlds.exe, tests playing/recording disabled!\n", __FUNCTION__); - else - TestSuite_Init(NULL, &hlds_exe, NULL); - - Rehlds_Debug_Init(NULL); -#endif - - } - else if (fdwReason == DLL_PROCESS_DETACH) - { - - } - return TRUE; -} - -#else // _WIN32 - -void __attribute__((constructor)) DllMainLoad() -{ - -} - -void __attribute__((destructor)) DllMainUnload() -{ - -} - -#endif // _WIN32 +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#ifdef _WIN32 + +// DLL entry point +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + g_RehldsRuntimeConfig.parseFromCommandLine(GetCommandLineA()); + +#ifdef _WIN32 + Module hlds_exe; + if (!FindModuleByName("hlds.exe", &hlds_exe)) + printf("%s: launcher is not hlds.exe, tests playing/recording disabled!\n", __func__); + else + TestSuite_Init(NULL, &hlds_exe, NULL); + + Rehlds_Debug_Init(NULL); +#endif + + } + else if (fdwReason == DLL_PROCESS_DETACH) + { + + } + return TRUE; +} + +#else // _WIN32 + +void __attribute__((constructor)) DllMainLoad() +{ + +} + +void __attribute__((destructor)) DllMainUnload() +{ + +} + +#endif // _WIN32 diff --git a/rehlds/hookers/helper.h b/rehlds/hookers/helper.h new file mode 100644 index 0000000..e3e2c4c --- /dev/null +++ b/rehlds/hookers/helper.h @@ -0,0 +1,159 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#if defined(HOOK_ENGINE) || defined(HOOK_HLTV) + +#define private public +#define protected public + +template +class MethodThunk { +public: + void Constructor(TArgs ... args) { + new(this) T(args ...); + } + + void Destructor() { + (*(T *)this).~T(); + } +}; + +namespace MsvcMethod { + namespace Detail { + using Counter = std::size_t(*)(); + + template + std::size_t GetIndex() { + return N; + } + + template + constexpr auto GenerateCounters_Helper(std::index_sequence) { + // There is no make_array (and/or deduction guides), so we need to explicitly define array template params + return std::array { &GetIndex ... }; + } + + template + auto counters = GenerateCounters_Helper(std::make_index_sequence{}); + + struct VIndexGetter {}; + struct ThisGetter { + decltype(auto) GetThis() const { + return this; + } + + decltype(auto) GetThis(...) const { + return this; + } + }; + + template + class Singleton { + public: + static T &GetInstance() { + static T instance = {}; + return instance; + } + }; + + // primary template + template + struct is_variadic_function : std::false_type {}; + template + struct is_variadic_function : std::true_type {}; + template + struct is_variadic_function : std::true_type {}; + template + struct is_variadic_function : std::true_type {}; + template + struct is_variadic_function : std::true_type {}; + template + struct is_variadic_function : std::true_type {}; + template + struct is_variadic_function : std::true_type {}; + template + struct is_variadic_function : std::true_type {}; + template + struct is_variadic_function : std::true_type {}; + template + struct is_variadic_function : std::true_type {}; + template + struct is_variadic_function : std::true_type {}; + template + struct is_variadic_function : std::true_type {}; + template + struct is_variadic_function : std::true_type {}; + + template + constexpr bool is_variadic_function_v = is_variadic_function::value; + + template + constexpr bool is_function_v = std::is_function::value; + } // namespace Detail + + static constexpr auto& counters = Detail::counters<256>; + + template + std::enable_if_t, std::uintptr_t> + GetVirtualIndex(TMethod T::*method) + { + decltype(auto) pcounters = counters.data(); + decltype(auto) vIndexGetter = (Detail::VIndexGetter *)&pcounters; + + using VIndexGetterFunction = std::conditional_t, std::size_t (Detail::VIndexGetter::*)(...) const, std::size_t(Detail::VIndexGetter::*)() const>; + VIndexGetterFunction vIndexGetterFunction; + { + *(std::uintptr_t *)&vIndexGetterFunction = *(std::uintptr_t *)&method; + } + + return (vIndexGetter->*vIndexGetterFunction)(); + } + + template + std::enable_if_t, std::uintptr_t> + GetVirtualAddress(TMethod T::*method) + { + using ThisGetterFunction = std::conditional_t, const T *(T::*)(...) const, const T *(T::*)() const>; + ThisGetterFunction thisGetterFunction = *(ThisGetterFunction *)&method; + { + decltype(auto) m = static_cast, const Detail::ThisGetter *(Detail::ThisGetter::*)(...) const, const Detail::ThisGetter *(Detail::ThisGetter::*)() const>>(&Detail::ThisGetter::GetThis); + *(std::uintptr_t *)&thisGetterFunction = *(std::uintptr_t *)&m; + } + + return *(*(std::uintptr_t **)(Detail::Singleton::GetInstance().*thisGetterFunction)() + GetVirtualIndex(method)); + } + + template + std::enable_if_t, std::uintptr_t> + GetAddress(TMethod (T::*method)) { + return (std::uintptr_t &)method; + } + + template + std::enable_if_t, std::uintptr_t> + GetAddress(TMethod (*method)) { + return (std::uintptr_t &)method; + } + +} // namespace MsvcMethod + +#ifdef _MSC_VER + #define GLOBALVAR_LINK(offset, symbol, var, ...) { offset, #symbol, (size_t)&##var, __VA_ARGS__ } + #define HOOK_SYMBOLDEF(offset, symbol, func, ...) { offset, #symbol, MsvcMethod::GetAddress<__VA_ARGS__>(&func) } + #define HOOK_SYMBOL_VIRTUAL_DEF(offset, symbol, func, ...) { offset, #symbol, MsvcMethod::GetVirtualAddress<__VA_ARGS__>(&func) } + + #define HOOK_DEF(offset, func, ...) HOOK_SYMBOLDEF(offset, func, func, __VA_ARGS__) + #define HOOK_VIRTUAL_DEF(offset, func, ...) HOOK_SYMBOL_VIRTUAL_DEF(offset, func, func, __VA_ARGS__) + +#else + #error Hooking stuff is only available using MSVC compiler. +#endif // _MSC_VER + +#endif // #if defined(HOOK_ENGINE) || defined(HOOK_HLTV) diff --git a/rehlds/hookers/hooker.cpp b/rehlds/hookers/hooker.cpp index f4914af..2927c60 100644 --- a/rehlds/hookers/hooker.cpp +++ b/rehlds/hookers/hooker.cpp @@ -28,13 +28,14 @@ #include "precompiled.h" +Module g_Module = { NULL, NULL, NULL, NULL }; -HIDDEN Module g_EngineModule = { NULL, NULL, NULL, NULL }; - -extern const size_t g_BaseOffset; -extern FunctionHook g_FunctionHooks[]; -extern AddressRef g_FunctionRefs[]; -extern AddressRef g_DataRefs[]; +// Offset where module assumed be loaded to ajust hooks offsets. NULL for the Linux to trigger symbols searching. +#ifdef _WIN32 +const size_t g_BaseOffset = 0x01D00000; +#else +const size_t g_BaseOffset = NULL; +#endif void *GetOriginalFuncAddrOrDie(const char *funcName) { @@ -80,10 +81,9 @@ void *GetFuncRefAddrOrDefault(const char *funcName, void *def) return def; } -int HookEngine(size_t addr) +int HookModule(const char *pszAppName, size_t addr) { - if (addr == NULL || !FindModuleByAddress(addr, &g_EngineModule)) - { + if (addr == NULL || !FindModuleByAddress(addr, &g_Module)) { return (FALSE); } @@ -93,7 +93,7 @@ int HookEngine(size_t addr) AddressRef *refData = g_DataRefs; while (refData->symbolName != NULL) { - if (!GetAddress(&g_EngineModule, (Address*)refData, g_BaseOffset)) + if (!GetAddress(&g_Module, (Address*)refData, g_BaseOffset)) { #if _DEBUG printf("%s: symbol not found \"%s\", symbol index: %i\n", __func__, refData->symbolName, refData->symbolIndex); @@ -106,7 +106,7 @@ int HookEngine(size_t addr) AddressRef *refFunc = g_FunctionRefs; while (refFunc->symbolName != NULL) { - if (!GetAddress(&g_EngineModule, (Address*)refFunc, g_BaseOffset)) + if (!GetAddress(&g_Module, (Address*)refFunc, g_BaseOffset)) { #if _DEBUG printf("%s: symbol not found \"%s\", symbol index: %i\n", __func__, refData->symbolName, refData->symbolIndex); @@ -119,7 +119,7 @@ int HookEngine(size_t addr) FunctionHook *hookFunc = g_FunctionHooks; while (hookFunc->handlerFunc != NULL) { - if (!GetAddress(&g_EngineModule, (Address*)hookFunc, g_BaseOffset)) + if (!GetAddress(&g_Module, (Address*)hookFunc, g_BaseOffset)) { #if _DEBUG printf("%s: symbol not found \"%s\", symbol index: %i\n", __func__, refData->symbolName, refData->symbolIndex); @@ -132,24 +132,23 @@ int HookEngine(size_t addr) if (!success) { #if _DEBUG - printf("%s: failed to hook engine!\n", __func__); + printf("%s: failed to hook module!\n", __func__); #endif return (FALSE); } -#ifdef _WIN32 - Module hlds_exe; - if (!FindModuleByName("hlds.exe", &hlds_exe)) - printf("%s: launcher is not hlds.exe, tests playing/recording is disabled!\n", __FUNCTION__); +#if defined(_WIN32) && defined(HOOK_ENGINE) + Module application; + if (!FindModuleByName(pszAppName, &application)) + printf("%s: launcher is not %s, tests playing/recording is disabled!\n", __func__, pszAppName); else - TestSuite_Init(&g_EngineModule, &hlds_exe, g_FunctionRefs); + TestSuite_Init(&g_Module, &application, g_FunctionRefs); #endif - refData = g_DataRefs; while (refData->addressRef != NULL) { - if (!FindDataRef(&g_EngineModule, refData)) + if (!FindDataRef(&g_Module, refData)) return (FALSE); refData++; } @@ -157,26 +156,89 @@ int HookEngine(size_t addr) refFunc = g_FunctionRefs; while (refFunc->addressRef != NULL) { - if (!FindDataRef(&g_EngineModule, refFunc)) + if (!FindDataRef(&g_Module, refFunc)) return (FALSE); refFunc++; } +#ifdef HOOK_ENGINE // Actually hook all things if (!g_RehldsRuntimeConfig.disableAllHooks) +#endif // SWDS { hookFunc = g_FunctionHooks; while (hookFunc->handlerFunc != NULL) { - if (!HookFunction(&g_EngineModule, hookFunc)) + if (!HookFunction(&g_Module, hookFunc)) return (FALSE); hookFunc++; } } -#ifdef _WIN32 - Rehlds_Debug_Init(&g_EngineModule); -#endif +#if defined(_WIN32) && defined(HOOK_ENGINE) + Rehlds_Debug_Init(&g_Module); +#endif // _WIN32 return (TRUE); } + +#ifdef _WIN32 + +void *malloc_wrapper(size_t size) { + void *res = malloc(size); +#ifdef HOOK_ENGINE + //Rehlds_Debug_logAlloc(size, res); +#endif // HOOK_ENGINE + return res; +} + +void *realloc_wrapper(void *orig, size_t newSize) { + void *res = realloc(orig, newSize); +#ifdef HOOK_ENGINE + //Rehlds_Debug_logRealloc(newSize, orig, res); +#endif // HOOK_ENGINE + return res; +} + +void free_wrapper(void *mem) { +#ifdef HOOK_ENGINE + //Rehlds_Debug_logFree(mem); +#endif // HOOK_ENGINE + free(mem); +} + +void *calloc_wrapper(size_t count, size_t size) { + void *res = calloc(count, size); +#ifdef HOOK_ENGINE + //Rehlds_Debug_logAlloc(size * count, res); +#endif // HOOK_ENGINE + return res; +} + +void *__nh_malloc_wrapper(size_t sz, int unk) { + void *res = malloc(sz); +#ifdef HOOK_ENGINE + //Rehlds_Debug_logAlloc(sz, res); +#endif // HOOK_ENGINE + return res; +} + +char *strdup_wrapper(const char *s) { + return _strdup(s); +} + +#endif // _WIN32 + +void logf(const char *fmt, ...) +{ + va_list argptr; + static char string[8192]; + + va_start(argptr, fmt); + _vsnprintf(string, sizeof(string), fmt, argptr); + string[sizeof(string) - 1] = 0; + + FILE *fl = fopen("hooker.log", "a"); + fprintf(fl, "%s\n", string); + fclose(fl); +} diff --git a/rehlds/hookers/hooker.h b/rehlds/hookers/hooker.h index 937007a..8f5eeac 100644 --- a/rehlds/hookers/hooker.h +++ b/rehlds/hookers/hooker.h @@ -2,7 +2,24 @@ #include "osconfig.h" +extern int HookModule(const char *pszAppName, size_t addr); extern void *GetOriginalFuncAddrOrDie(const char *funcName); extern void *GetOriginalFuncAddrOrDefault(const char *funcName, void *def); extern void *GetFuncRefAddrOrDie(const char *funcName); extern void *GetFuncRefAddrOrDefault(const char *funcName, void *def); +extern void logf(const char *fmt, ...); + +extern FunctionHook g_FunctionHooks[]; +extern AddressRef g_FunctionRefs[]; +extern AddressRef g_DataRefs[]; + +#ifdef _WIN32 + +void *malloc_wrapper(size_t size); +void *realloc_wrapper(void *orig, size_t newSize); +void free_wrapper(void *mem); +void *calloc_wrapper(size_t count, size_t size); +void *__nh_malloc_wrapper(size_t sz, int unk); +char *strdup_wrapper(const char *s); + +#endif // _WIN32 diff --git a/rehlds/hookers/memory.h b/rehlds/hookers/memory.h index 56b88e1..3f3d6fd 100644 --- a/rehlds/hookers/memory.h +++ b/rehlds/hookers/memory.h @@ -31,10 +31,8 @@ #include "osconfig.h" - #define MAX_PATTERN 128 - struct Section; struct Section { @@ -62,7 +60,7 @@ struct Module struct Address { - // Keeps offset for SWDS on application start; during HookEngine() an real address is written here. + // Keeps offset for SWDS on application start; during HookModule() an real address is written here. size_t originalAddress; const char *symbolName; size_t address; @@ -71,7 +69,7 @@ struct Address struct FunctionHook { - // Keeps offset for SWDS on application start; during HookEngine() an real address is written here. + // Keeps offset for SWDS on application start; during HookModule() an real address is written here. size_t originalAddress; const char *symbolName; size_t handlerFunc; @@ -80,7 +78,7 @@ struct FunctionHook struct AddressRef { - // Keeps offset for SWDS on application start; during HookEngine() an real address is written here. + // Keeps offset for SWDS on application start; during HookModule() an real address is written here. size_t originalAddress; const char *symbolName; size_t addressRef; diff --git a/rehlds/msvc/ReHLDS.vcxproj b/rehlds/msvc/ReHLDS.vcxproj index 08e33fb..f894b94 100644 --- a/rehlds/msvc/ReHLDS.vcxproj +++ b/rehlds/msvc/ReHLDS.vcxproj @@ -100,39 +100,28 @@ - + true true true true true - - true - true + true true true - - true - true - true - - + true true true - false true true true - false true - - false - + true @@ -471,8 +460,7 @@ - - + @@ -548,6 +536,7 @@ + @@ -745,7 +734,7 @@ Level3 Disabled true - REHLDS_FLIGHT_REC;REHLDS_OPT_PEDANTIC;REHLDS_SELF;HOOK_ENGINE;REHLDS_FIXES;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + REHLDS_OPT_PEDANTIC;REHLDS_SELF;HOOK_ENGINE;REHLDS_FIXES;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) Precise /arch:IA32 %(AdditionalOptions) MultiThreadedDebug @@ -820,7 +809,7 @@ Level3 Disabled true - REHLDS_FLIGHT_REC;REHLDS_SELF;HOOK_ENGINE;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + REHLDS_SELF;HOOK_ENGINE;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) Precise /arch:IA32 %(AdditionalOptions) MultiThreadedDebug @@ -895,7 +884,7 @@ Level3 Disabled true - REHLDS_FLIGHT_REC;REHLDS_SELF;HOOK_ENGINE;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + REHLDS_SELF;HOOK_ENGINE;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) Precise /arch:IA32 %(AdditionalOptions) MultiThreadedDebug @@ -1004,7 +993,7 @@ true true true - REHLDS_FLIGHT_REC;REHLDS_OPT_PEDANTIC;REHLDS_SELF;HOOK_ENGINE;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + REHLDS_OPT_PEDANTIC;REHLDS_SELF;HOOK_ENGINE;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreaded /arch:IA32 %(AdditionalOptions) Use @@ -1043,7 +1032,7 @@ true true true - REHLDS_FLIGHT_REC;REHLDS_SELF;HOOK_ENGINE;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + REHLDS_SELF;HOOK_ENGINE;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreaded /arch:IA32 %(AdditionalOptions) Use diff --git a/rehlds/msvc/ReHLDS.vcxproj.filters b/rehlds/msvc/ReHLDS.vcxproj.filters index 82168c5..ec21cd1 100644 --- a/rehlds/msvc/ReHLDS.vcxproj.filters +++ b/rehlds/msvc/ReHLDS.vcxproj.filters @@ -1,11 +1,6 @@  - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - false - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms @@ -61,15 +56,6 @@ - - hookers - - - hookers - - - hookers - engine\common @@ -106,9 +92,6 @@ engine\common - - hookers - public @@ -202,9 +185,6 @@ engine\common - - hookers - unittests @@ -289,9 +269,6 @@ engine\common - - hookers - rehlds @@ -355,20 +332,29 @@ engine\common + + hookers + + + hookers + + + hookers + + + hookers + + + hookers + - - hookers - version engine\common - - hookers - engine\common @@ -738,15 +724,9 @@ engine\common - - hookers - rehlds - - hookers - engine\common @@ -1092,6 +1072,18 @@ public\rehlds + + hookers + + + rehlds + + + hookers + + + hookers + diff --git a/rehlds/public/engine_hlds_api.h b/rehlds/public/engine_hlds_api.h index 75708fd..9613a0b 100644 --- a/rehlds/public/engine_hlds_api.h +++ b/rehlds/public/engine_hlds_api.h @@ -28,7 +28,6 @@ #pragma once -#include "maintypes.h" #include "interface.h" #ifdef _WIN32 diff --git a/rehlds/public/engine_launcher_api.h b/rehlds/public/engine_launcher_api.h index 982afed..bd5cf42 100644 --- a/rehlds/public/engine_launcher_api.h +++ b/rehlds/public/engine_launcher_api.h @@ -26,19 +26,21 @@ * */ -#ifndef ENGINE_LAUNCHER_API_H -#define ENGINE_LAUNCHER_API_H -#ifdef _WIN32 #pragma once -#endif -#include "maintypes.h" #include "interface.h" +#ifdef _WIN32 + #define ENGINE_CLIENT_LIB "hw.dll" // OpenGL/D3D video mode + #define ENGINE_CLIENT_SOFT_LIB "sw.dll" // Software video mode +#else + #define ENGINE_CLIENT_LIB "hw.so" +#endif // _WIN32 + class IEngineAPI : public IBaseInterface { public: virtual int Run(void *instance, char *basedir, char *cmdline, char *postRestartCmdLineArgs, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory) = 0; }; -#endif // ENGINE_LAUNCHER_API_H +#define VENGINE_LAUNCHER_API_VERSION "VENGINE_LAUNCHER_API_VERSION002" diff --git a/rehlds/public/icommandline.h b/rehlds/public/icommandline.h new file mode 100644 index 0000000..a06ba94 --- /dev/null +++ b/rehlds/public/icommandline.h @@ -0,0 +1,47 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +// Interface to engine command line +class ICommandLine { +public: + virtual void CreateCmdLine(const char *commandline) = 0; + virtual void CreateCmdLine(int argc, const char **argv) = 0; + virtual const char *GetCmdLine() const = 0; + + // Check whether a particular parameter exists + virtual const char *CheckParm(const char *psz, char **ppszValue = nullptr) const = 0; + virtual void RemoveParm(const char *pszParm) = 0; + virtual void AppendParm(const char *pszParm, const char *pszValues) = 0; + + virtual void SetParm(const char *pszParm, const char *pszValues) = 0; + virtual void SetParm(const char *pszParm, int iValue) = 0; +}; + +ICommandLine *CommandLine(); diff --git a/rehlds/public/interface.cpp b/rehlds/public/interface.cpp index 440e719..2b62260 100644 --- a/rehlds/public/interface.cpp +++ b/rehlds/public/interface.cpp @@ -133,48 +133,55 @@ void *Sys_GetProcAddress( void *pModuleHandle, const char *pName ) // Input : *pModuleName - filename of the component // Output : opaque handle to the module (hides system dependency) //----------------------------------------------------------------------------- -CSysModule *Sys_LoadModule( const char *pModuleName ) +CSysModule *Sys_LoadModule(const char *pModuleName) { -#if defined ( _WIN32 ) - HMODULE hDLL = LoadLibrary( pModuleName ); +#if defined (_WIN32) + HMODULE hDLL = LoadLibrary(pModuleName); #else HMODULE hDLL = NULL; - char szAbsoluteModuleName[1024]; - szAbsoluteModuleName[0] = 0; - if ( pModuleName[0] != '/' ) + if (pModuleName[0] != '/') { char szCwd[1024]; char szAbsoluteModuleName[1024]; - getcwd( szCwd, sizeof( szCwd ) ); - if ( szCwd[ strlen( szCwd ) - 1 ] == '/' ) - szCwd[ strlen( szCwd ) - 1 ] = 0; + getcwd(szCwd, sizeof(szCwd)); + if (szCwd[strlen(szCwd) - 1] == '/') + szCwd[strlen(szCwd) - 1] = '\0'; - _snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s", szCwd, pModuleName ); - - hDLL = dlopen( szAbsoluteModuleName, RTLD_NOW ); + _snprintf(szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s", szCwd, pModuleName); + hDLL = dlopen(szAbsoluteModuleName, RTLD_NOW); } else { - _snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s", pModuleName ); - hDLL = dlopen( pModuleName, RTLD_NOW ); + hDLL = dlopen(pModuleName, RTLD_NOW); } #endif - if( !hDLL ) + if(!hDLL) { - char str[512]; -#if defined ( _WIN32 ) - _snprintf( str, sizeof(str), "%s.dll", pModuleName ); - hDLL = LoadLibrary( str ); + char szPathModule[MAX_PATH]; + char szModuleName[64]; + + strncpy(szModuleName, pModuleName, sizeof szModuleName - 1); + szModuleName[sizeof szModuleName - 1] = '\0'; + + // remove extension if provided. + char *ext = strrchr(szModuleName, '.'); + if (ext) { + *ext = '\0'; + } + +#if defined (_WIN32) + _snprintf(szPathModule, sizeof(szPathModule), "%s.dll", szModuleName); + hDLL = LoadLibrary(szPathModule); #elif defined(OSX) - printf("Error:%s\n",dlerror()); - _snprintf( str, sizeof(str), "%s.dylib", szAbsoluteModuleName ); - hDLL = dlopen(str, RTLD_NOW); + printf("Error: %s\n", dlerror()); + _snprintf(szPathModule, sizeof(szPathModule), "%s.dylib", szModuleName); + hDLL = dlopen(szPathModule, RTLD_NOW); #else - printf("Error:%s\n",dlerror()); - _snprintf( str, sizeof(str), "%s.so", szAbsoluteModuleName ); - hDLL = dlopen(str, RTLD_NOW); + printf("Error: %s\n", dlerror()); + _snprintf(szPathModule, sizeof(szPathModule), "%s.so", szModuleName); + hDLL = dlopen(szPathModule, RTLD_NOW); #endif } diff --git a/rehlds/public/interface.h b/rehlds/public/interface.h index 980a5af..cdd361e 100644 --- a/rehlds/public/interface.h +++ b/rehlds/public/interface.h @@ -8,10 +8,10 @@ // Versioning // There are two versioning cases that are handled by this: -// 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case, +// 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case, // you need two EXPOSE_INTERFACEs: one to expose your class as the old interface and one to expose it as the new interface. -// 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface -// for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and +// 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface +// for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and // expose it for the old interface. //#if _MSC_VER >= 1300 // VC7 @@ -108,7 +108,7 @@ public: // This function is automatically exported and allows you to access any interfaces exposed with the above macros. // if pReturnCode is set, it will return one of the following values // extend this for other error conditions/code -enum +enum { IFACE_OK = 0, IFACE_FAILED diff --git a/rehlds/public/rehlds/custom.h b/rehlds/public/rehlds/custom.h index 190d769..7422638 100644 --- a/rehlds/public/rehlds/custom.h +++ b/rehlds/public/rehlds/custom.h @@ -1,9 +1,9 @@ /*** * * Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. * All Rights Reserved. * * Use, distribution, and modification of this source code and/or resulting @@ -75,14 +75,19 @@ typedef struct resource_s unsigned char rguc_reserved[ 32 ]; // For future expansion struct resource_s *pNext; // Next in chain. + +#if !defined(HLTV) struct resource_s *pPrev; +#else + unsigned char *data; +#endif // !defined(HLTV) } resource_t; typedef struct customization_s { qboolean bInUse; // Is this customization in use; resource_t resource; // The resource_t for this customization - qboolean bTranslated; // Has the raw data been translated into a useable format? + qboolean bTranslated; // Has the raw data been translated into a useable format? // (e.g., raw decal .wad make into texture_t *) int nUserData1; // Customization specific data int nUserData2; // Customization specific data diff --git a/rehlds/public/rehlds/maintypes.h b/rehlds/public/rehlds/maintypes.h index dbb69e3..b211e2d 100644 --- a/rehlds/public/rehlds/maintypes.h +++ b/rehlds/public/rehlds/maintypes.h @@ -32,11 +32,9 @@ #pragma once #endif - #include "osconfig.h" #include "mathlib.h" - // Has no references on server side. #define NOXREF // Function body is not implemented. @@ -44,13 +42,24 @@ // Function is not tested at all. #define UNTESTED -#define BIT(n) (1<<(n)) +#define CONST_INTEGER_AS_STRING(x) #x //Wraps the integer in quotes, allowing us to form constant strings with it +#define __HACK_LINE_AS_STRING__(x) CONST_INTEGER_AS_STRING(x) //__LINE__ can only be converted to an actual number by going through this, otherwise the output is literally "__LINE__" +#define __LINE__AS_STRING __HACK_LINE_AS_STRING__(__LINE__) //Gives you the line number in constant string form +#if defined _MSC_VER || defined __INTEL_COMPILER +#define NOXREFCHECK int __retAddr; __asm { __asm mov eax, [ebp + 4] __asm mov __retAddr, eax }; Sys_Error("[NOXREFCHECK]: %s: (" __FILE__ ":" __LINE__AS_STRING ") NOXREF, but called from 0x%.08x", __func__, __retAddr) +#else +// For EBP based stack (older gcc) (uncomment version apropriate for your compiler) +//#define NOXREFCHECK int __retAddr; __asm__ __volatile__("movl 4(%%ebp), %%eax;" "movl %%eax, %0":"=r"(__retAddr)::"%eax"); Sys_Error("[NOXREFCHECK]: %s: (" __FILE__ ":" __LINE__AS_STRING ") NOXREF, but called from 0x%.08x", __func__, __retAddr); +// For ESP based stack (newer gcc) (uncomment version apropriate for your compiler) +#define NOXREFCHECK int __retAddr; __asm__ __volatile__("movl 16(%%esp), %%eax;" "movl %%eax, %0":"=r"(__retAddr)::"%eax"); Sys_Error("[NOXREFCHECK]: %s: (" __FILE__ ":" __LINE__AS_STRING ") NOXREF, but called from 0x%.08x", __func__, __retAddr); +#endif + +#define BIT(n) (1<<(n)) // From engine/pr_comp.h; typedef unsigned int string_t; - // From engine/server.h typedef enum sv_delta_s { @@ -58,5 +67,4 @@ typedef enum sv_delta_s sv_packet_delta, } sv_delta_t; - #endif // MAINTYPES_H diff --git a/rehlds/public/rehlds/model.h b/rehlds/public/rehlds/model.h index 7837482..bcb952a 100644 --- a/rehlds/public/rehlds/model.h +++ b/rehlds/public/rehlds/model.h @@ -74,7 +74,7 @@ typedef struct texture_s char name[16]; unsigned width, height; -#ifndef SWDS +#if !defined(SWDS) && !defined(HLTV) int gl_texturenum; struct msurface_s * texturechain; #endif @@ -85,7 +85,7 @@ typedef struct texture_s struct texture_s *alternate_anims; // bmodels in frame 1 use these unsigned offsets[MIPLEVELS]; // four mip maps stored -#ifdef SWDS +#if defined(SWDS) || defined(HLTV) unsigned paloffset; #else byte *pPal; diff --git a/rehlds/public/rehlds/osconfig.h b/rehlds/public/rehlds/osconfig.h index ad22f95..3e62ee5 100644 --- a/rehlds/public/rehlds/osconfig.h +++ b/rehlds/public/rehlds/osconfig.h @@ -172,6 +172,10 @@ #define SOCKET_AGAIN() (errno == EAGAIN) #define SOCKET_ERROR -1 + inline int ioctlsocket(int fd, int cmd, unsigned int *argp) { return ioctl(fd, cmd, argp); } + inline int closesocket(int fd) { return close(fd); } + inline int WSAGetLastError() { return errno; } + inline void* sys_allocmem(unsigned int size) { return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } diff --git a/rehlds/hookers/engine.h b/rehlds/rehlds/engine.h similarity index 96% rename from rehlds/hookers/engine.h rename to rehlds/rehlds/engine.h index a00b083..22d64c2 100644 --- a/rehlds/hookers/engine.h +++ b/rehlds/rehlds/engine.h @@ -1,83 +1,83 @@ -/* -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2 of the License, or (at -* your option) any later version. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* In addition, as a special exception, the author gives permission to -* link the code of this program with the Half-Life Game Engine ("HL -* Engine") and Modified Game Libraries ("MODs") developed by Valve, -* L.L.C ("Valve"). You must obey the GNU General Public License in all -* respects for all of the code used other than the HL Engine and MODs -* from Valve. If you modify this file, you may extend this exception -* to your version of the file, but you are not obligated to do so. If -* you do not wish to do so, delete this exception statement from your -* version. -* -*/ - -#include "common.h" -#include "keys.h" -#include "decal.h" -#include "delta.h" -#include "delta_jit.h" -#include "server.h" -#include "sys_dll.h" -#include "sys_dll2.h" -#include "sys_engine.h" -#include "zone.h" -#include "client.h" -#include "cmd.h" -#include "cvar.h" -#include "filesystem_internal.h" -#include "mem.h" -#include "unicode_strtools.h" -#include "host.h" -#include "filesystem_.h" -#include "info.h" -#include "iregistry.h" -#include "cmodel.h" -#include "model_rehlds.h" -#include "sv_log.h" -#include "sv_steam3.h" -#include "host_cmd.h" -#include "sv_user.h" -#include "pmove.h" -#include "pmovetst.h" -#include "pr_edict.h" -#include "pr_cmds.h" -#include "mathlib_e.h" -#include "world.h" -#include "sv_phys.h" -#include "sv_move.h" -#include "sv_pmove.h" -#include "studio_rehlds.h" -#include "net_ws.h" -#include "net_chan.h" - -#include "tmessage.h" -#include "traceinit.h" -#include "wad.h" -#include "textures.h" -#include "vid_null.h" -#include "l_studio.h" -#include "crc.h" -#include "md5.h" -#include "sv_remoteaccess.h" -#include "sv_upld.h" -#include "com_custom.h" -#include "hashpak.h" -#include "ipratelimit.h" -#include "ipratelimitWrapper.h" -#include "savegame_version.h" -#include "sys_linuxwnd.h" +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "common.h" +#include "keys.h" +#include "decal.h" +#include "delta.h" +#include "delta_jit.h" +#include "server.h" +#include "sys_dll.h" +#include "sys_dll2.h" +#include "sys_engine.h" +#include "zone.h" +#include "client.h" +#include "cmd.h" +#include "cvar.h" +#include "filesystem_internal.h" +#include "mem.h" +#include "unicode_strtools.h" +#include "host.h" +#include "filesystem_.h" +#include "info.h" +#include "iregistry.h" +#include "cmodel.h" +#include "model_rehlds.h" +#include "sv_log.h" +#include "sv_steam3.h" +#include "host_cmd.h" +#include "sv_user.h" +#include "pmove.h" +#include "pmovetst.h" +#include "pr_edict.h" +#include "pr_cmds.h" +#include "mathlib_e.h" +#include "world.h" +#include "sv_phys.h" +#include "sv_move.h" +#include "sv_pmove.h" +#include "studio_rehlds.h" +#include "net_ws.h" +#include "net_chan.h" + +#include "tmessage.h" +#include "traceinit.h" +#include "wad.h" +#include "textures.h" +#include "vid_null.h" +#include "l_studio.h" +#include "crc.h" +#include "md5.h" +#include "sv_remoteaccess.h" +#include "sv_upld.h" +#include "com_custom.h" +#include "hashpak.h" +#include "ipratelimit.h" +#include "ipratelimitWrapper.h" +#include "savegame_version.h" +#include "sys_linuxwnd.h" diff --git a/rehlds/rehlds/precompiled.h b/rehlds/rehlds/precompiled.h index 7c05286..876f46f 100644 --- a/rehlds/rehlds/precompiled.h +++ b/rehlds/rehlds/precompiled.h @@ -21,11 +21,10 @@ #include "RehldsRuntimeConfig.h" #include "rehlds_debug.h" -#ifdef HOOK_ENGINE -#include "hooker.h" -#endif +// Hook stuff +#include "hookers/engine/hooklist.h" -//valve libs stuff +// Valve libs stuff #include "tier0/platform.h" #include "tier0/dbg.h" @@ -37,7 +36,7 @@ #include "iosutil.h" -//testsuite +// Testsuite #include "testsuite.h" #include "funccalls.h" #include "recorder.h" diff --git a/rehlds/unittests/security_tests.cpp b/rehlds/unittests/security_tests.cpp index ebf67eb..859c1dc 100644 --- a/rehlds/unittests/security_tests.cpp +++ b/rehlds/unittests/security_tests.cpp @@ -7,51 +7,51 @@ TEST(IsSafeFileExtension, SecurityChecks, 1000) struct testdata_t { const char* filename; - bool safe; + qboolean safe; }; testdata_t testdata[] = { - {"radio/go.wav", true}, - {"radio/go.WAV", true}, - {"textures.wad", true}, + {"radio/go.wav", TRUE}, + {"radio/go.WAV", TRUE}, + {"textures.wad", TRUE}, #ifdef REHLDS_FIXES - {"!QWERTY", true}, + {"!QWERTY", TRUE}, // TODO: - //{"file.dll2", true}, - //{"noext", false}, - //{".hidden", false}, - //{"subdir/.hidden", false}, + //{"file.dll2", TRUE}, + //{"noext", FALSE}, + //{".hidden", FALSE}, + //{"subdir/.hidden", FALSE}, #else - {"file.dll2", false}, + {"file.dll2", FALSE}, #endif - {"../file.txt", false}, - {"/home/file.txt", false}, - {"C:/Windows/file.txt", false}, - {"models\\terror.mdl", false}, - {"file~.mdl", false}, - {"file.wav.", false}, - {"file.dll.txt", false}, - {"halflife.wad", false}, - {"pak0.pak", false}, - {"xeno.wad", false}, - {"file.cfg", false}, - {"file.lst", false}, - {"file.exe", false}, - {"file.vbs", false}, - {"file.com", false}, - {"file.bat", false}, - {"file.dll", false}, - {"file.ini", false}, - {"file.log", false}, - {"file.so", false}, - {"file.dylib", false}, - {"file.sys", false}, - {"file.SYS", false}, + {"../file.txt", FALSE}, + {"/home/file.txt", FALSE}, + {"C:/Windows/file.txt", FALSE}, + {"models\\terror.mdl", FALSE}, + {"file~.mdl", FALSE}, + {"file.wav.", FALSE}, + {"file.dll.txt", FALSE}, + {"halflife.wad", FALSE}, + {"pak0.pak", FALSE}, + {"xeno.wad", FALSE}, + {"file.cfg", FALSE}, + {"file.lst", FALSE}, + {"file.exe", FALSE}, + {"file.vbs", FALSE}, + {"file.com", FALSE}, + {"file.bat", FALSE}, + {"file.dll", FALSE}, + {"file.ini", FALSE}, + {"file.log", FALSE}, + {"file.so", FALSE}, + {"file.dylib", FALSE}, + {"file.sys", FALSE}, + {"file.SYS", FALSE}, }; for (int i = 0; i < ARRAYSIZE(testdata); i++) { testdata_t* d = &testdata[i]; - bool result = IsSafeFileToDownload(d->filename); + qboolean result = IsSafeFileToDownload(d->filename); char msg[256]; Q_snprintf(msg, sizeof msg, "IsSafeFileToDownload(%s) check", d->filename); diff --git a/shared_msvc.gradle b/shared_msvc.gradle index 56821d9..bf8f548 100644 --- a/shared_msvc.gradle +++ b/shared_msvc.gradle @@ -120,7 +120,7 @@ rootProject.ext.createMsvcConfig = { boolean release, BinaryKind binKind -> } // Detect and setup UCRT paths - def ucrtInfo = "getucrtinfo.bat".execute().text + def ucrtInfo = "getucrtinfo.bat".execute().text def m = ucrtInfo =~ /^(.*)\r\n(.*)?$/ if (!m.find()) { return cfg From 46cd13fcd65d430ea127009995c2c414369680b8 Mon Sep 17 00:00:00 2001 From: s1lent Date: Mon, 24 Apr 2017 04:26:43 +0700 Subject: [PATCH 2/2] Add project HLTV --- publish.gradle | 32 +- rehlds/HLTV/Console/build.gradle | 153 + rehlds/HLTV/Console/msvc/Console.sln | 22 + rehlds/HLTV/Console/msvc/Console.vcxproj | 186 ++ .../HLTV/Console/msvc/Console.vcxproj.filters | 106 + rehlds/HLTV/Console/msvc/PostBuild.bat | 39 + rehlds/HLTV/Console/msvc/hltv.rc | Bin 0 -> 5136 bytes rehlds/HLTV/Console/msvc/icon.ico | Bin 0 -> 120505 bytes rehlds/HLTV/Console/msvc/resource.h | 16 + rehlds/HLTV/Console/src/System.cpp | 1147 +++++++ rehlds/HLTV/Console/src/System.h | 188 ++ rehlds/HLTV/Console/src/precompiled.cpp | 1 + rehlds/HLTV/Console/src/precompiled.h | 19 + .../HLTV/Console/src/public_amalgamation.cpp | 3 + rehlds/HLTV/Core/build.gradle | 154 + rehlds/HLTV/Core/msvc/Core.sln | 28 + rehlds/HLTV/Core/msvc/Core.vcxproj | 251 ++ rehlds/HLTV/Core/msvc/Core.vcxproj.filters | 192 ++ rehlds/HLTV/Core/msvc/PostBuild.bat | 39 + rehlds/HLTV/Core/src/BSPModel.cpp | 1163 +++++++ rehlds/HLTV/Core/src/BSPModel.h | 99 + rehlds/HLTV/Core/src/Delta.cpp | 1514 +++++++++ rehlds/HLTV/Core/src/Delta.h | 208 ++ rehlds/HLTV/Core/src/NetSocket.cpp | 555 ++++ rehlds/HLTV/Core/src/NetSocket.h | 108 + rehlds/HLTV/Core/src/Network.cpp | 445 +++ rehlds/HLTV/Core/src/Network.h | 130 + rehlds/HLTV/Core/src/Server.cpp | 2388 ++++++++++++++ rehlds/HLTV/Core/src/Server.h | 266 ++ rehlds/HLTV/Core/src/World.cpp | 2380 ++++++++++++++ rehlds/HLTV/Core/src/World.h | 310 ++ rehlds/HLTV/Core/src/precompiled.cpp | 1 + rehlds/HLTV/Core/src/precompiled.h | 44 + rehlds/HLTV/Core/src/public_amalgamation.cpp | 3 + rehlds/HLTV/DemoPlayer/build.gradle | 139 + rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.sln | 22 + .../HLTV/DemoPlayer/msvc/DemoPlayer.vcxproj | 175 ++ .../msvc/DemoPlayer.vcxproj.filters | 114 + rehlds/HLTV/DemoPlayer/msvc/PostBuild.bat | 39 + rehlds/HLTV/DemoPlayer/src/DemoPlayer.cpp | 1060 +++++++ rehlds/HLTV/DemoPlayer/src/DemoPlayer.h | 193 ++ rehlds/HLTV/DemoPlayer/src/precompiled.cpp | 1 + rehlds/HLTV/DemoPlayer/src/precompiled.h | 23 + .../DemoPlayer/src/public_amalgamation.cpp | 3 + rehlds/HLTV/Director/build.gradle | 139 + rehlds/HLTV/Director/msvc/Director.sln | 22 + rehlds/HLTV/Director/msvc/Director.vcxproj | 157 + .../Director/msvc/Director.vcxproj.filters | 108 + rehlds/HLTV/Director/msvc/PostBuild.bat | 39 + rehlds/HLTV/Director/src/Director.cpp | 771 +++++ rehlds/HLTV/Director/src/Director.h | 126 + rehlds/HLTV/Director/src/DirectorNull.h | 57 + rehlds/HLTV/Director/src/precompiled.cpp | 1 + rehlds/HLTV/Director/src/precompiled.h | 24 + .../HLTV/Director/src/public_amalgamation.cpp | 3 + rehlds/HLTV/Proxy/build.gradle | 165 + rehlds/HLTV/Proxy/msvc/PostBuild.bat | 39 + rehlds/HLTV/Proxy/msvc/Proxy.sln | 28 + rehlds/HLTV/Proxy/msvc/Proxy.vcxproj | 377 +++ rehlds/HLTV/Proxy/msvc/Proxy.vcxproj.filters | 195 ++ rehlds/HLTV/Proxy/src/DemoClient.cpp | 294 ++ rehlds/HLTV/Proxy/src/DemoClient.h | 78 + rehlds/HLTV/Proxy/src/FakeClient.cpp | 156 + rehlds/HLTV/Proxy/src/FakeClient.h | 63 + rehlds/HLTV/Proxy/src/Master.cpp | 293 ++ rehlds/HLTV/Proxy/src/Master.h | 115 + rehlds/HLTV/Proxy/src/Proxy.cpp | 2770 +++++++++++++++++ rehlds/HLTV/Proxy/src/Proxy.h | 377 +++ rehlds/HLTV/Proxy/src/ProxyClient.cpp | 317 ++ rehlds/HLTV/Proxy/src/ProxyClient.h | 82 + rehlds/HLTV/Proxy/src/Status.cpp | 318 ++ rehlds/HLTV/Proxy/src/Status.h | 85 + rehlds/HLTV/Proxy/src/precompiled.cpp | 1 + rehlds/HLTV/Proxy/src/precompiled.h | 49 + rehlds/HLTV/Proxy/src/public_amalgamation.cpp | 3 + rehlds/HLTV/README.md | 333 ++ rehlds/HLTV/build.gradle | 13 + rehlds/HLTV/common/BaseClient.cpp | 776 +++++ rehlds/HLTV/common/BaseClient.h | 176 ++ rehlds/HLTV/common/BitBuffer.cpp | 887 ++++++ rehlds/HLTV/common/BitBuffer.h | 117 + rehlds/HLTV/common/DemoFile.cpp | 604 ++++ rehlds/HLTV/common/DemoFile.h | 135 + rehlds/HLTV/common/DirectorCmd.cpp | 683 ++++ rehlds/HLTV/common/DirectorCmd.h | 89 + rehlds/HLTV/common/InfoString.cpp | 431 +++ rehlds/HLTV/common/InfoString.h | 65 + rehlds/HLTV/common/NetAddress.cpp | 170 + rehlds/HLTV/common/NetAddress.h | 74 + rehlds/HLTV/common/NetChannel.cpp | 1286 ++++++++ rehlds/HLTV/common/NetChannel.h | 237 ++ rehlds/HLTV/common/ServerInfo.h | 85 + rehlds/HLTV/common/byteorder.cpp | 89 + rehlds/HLTV/common/byteorder.h | 42 + rehlds/HLTV/common/common.cpp | 468 +++ rehlds/HLTV/common/common_hltv.h | 55 + rehlds/HLTV/common/mathlib.cpp | 390 +++ rehlds/HLTV/common/mathlib_internal.h | 65 + rehlds/HLTV/common/md5.cpp | 317 ++ rehlds/HLTV/common/md5.h | 45 + rehlds/HLTV/common/munge.cpp | 235 ++ rehlds/HLTV/common/munge.h | 36 + rehlds/HLTV/common/net_internal.h | 181 ++ rehlds/HLTV/common/random.cpp | 144 + rehlds/HLTV/common/random.h | 33 + rehlds/HLTV/msvc/hltv.sln | 52 + rehlds/common/BaseSystemModule.h | 2 +- rehlds/common/IBaseSystem.h | 12 +- rehlds/common/IDemoPlayer.h | 93 + rehlds/common/IEngineWrapper.h | 71 + rehlds/common/IObjectContainer.h | 2 +- rehlds/common/IVGuiModule.h | 2 +- rehlds/common/entity_state.h | 5 +- rehlds/common/hltv.h | 2 - rehlds/dedicated/README.md | 16 + rehlds/dedicated/src/dedicated_exports.cpp | 2 +- rehlds/engine/mathlib.cpp | 2 +- rehlds/engine/textures.cpp | 2 +- rehlds/engine/unicode_strtools.h | 2 +- rehlds/engine/zone.cpp | 4 +- rehlds/game_shared/bitvec.h | 164 + rehlds/game_shared/counter.h | 187 ++ rehlds/game_shared/voice_common.h | 43 + rehlds/hookers/HLTV/Core/DeltaEx.cpp | 1537 +++++++++ rehlds/hookers/HLTV/Core/DeltaEx.h | 163 + rehlds/hookers/HLTV/Core/hooklist.cpp | 617 ++++ rehlds/hookers/HLTV/Core/hooklist.h | 18 + rehlds/hookers/HLTV/Core/main.cpp | 102 + rehlds/hookers/HLTV/DemoPlayer/hooklist.cpp | 152 + rehlds/hookers/HLTV/DemoPlayer/hooklist.h | 11 + rehlds/hookers/HLTV/DemoPlayer/main.cpp | 55 + rehlds/hookers/HLTV/Proxy/hooklist.cpp | 427 +++ rehlds/hookers/HLTV/Proxy/hooklist.h | 11 + rehlds/hookers/HLTV/Proxy/main.cpp | 55 + rehlds/public/FileSystem.h | 183 +- rehlds/public/HLTV/IBSPModel.h | 45 + rehlds/public/HLTV/IClient.h | 51 + rehlds/public/HLTV/IDirector.h | 52 + rehlds/public/HLTV/INetChannel.h | 60 + rehlds/public/HLTV/INetSocket.h | 55 + rehlds/public/HLTV/INetwork.h | 62 + rehlds/public/HLTV/IProxy.h | 107 + rehlds/public/HLTV/IServer.h | 101 + rehlds/public/HLTV/IWorld.h | 163 + rehlds/public/engine_hlds_api.h | 5 +- rehlds/public/idedicatedexports.h | 43 +- rehlds/public/interface.cpp | 314 +- rehlds/public/interface.h | 87 +- rehlds/public/rehlds/custom.h | 7 + rehlds/public/savegame_version.h | 41 +- rehlds/public/vgui/VGUI.h | 15 +- settings.gradle | 1 + shared_gcc.gradle | 1 + shared_icc.gradle | 1 + 154 files changed, 34295 insertions(+), 382 deletions(-) create mode 100644 rehlds/HLTV/Console/build.gradle create mode 100644 rehlds/HLTV/Console/msvc/Console.sln create mode 100644 rehlds/HLTV/Console/msvc/Console.vcxproj create mode 100644 rehlds/HLTV/Console/msvc/Console.vcxproj.filters create mode 100644 rehlds/HLTV/Console/msvc/PostBuild.bat create mode 100644 rehlds/HLTV/Console/msvc/hltv.rc create mode 100644 rehlds/HLTV/Console/msvc/icon.ico create mode 100644 rehlds/HLTV/Console/msvc/resource.h create mode 100644 rehlds/HLTV/Console/src/System.cpp create mode 100644 rehlds/HLTV/Console/src/System.h create mode 100644 rehlds/HLTV/Console/src/precompiled.cpp create mode 100644 rehlds/HLTV/Console/src/precompiled.h create mode 100644 rehlds/HLTV/Console/src/public_amalgamation.cpp create mode 100644 rehlds/HLTV/Core/build.gradle create mode 100644 rehlds/HLTV/Core/msvc/Core.sln create mode 100644 rehlds/HLTV/Core/msvc/Core.vcxproj create mode 100644 rehlds/HLTV/Core/msvc/Core.vcxproj.filters create mode 100644 rehlds/HLTV/Core/msvc/PostBuild.bat create mode 100644 rehlds/HLTV/Core/src/BSPModel.cpp create mode 100644 rehlds/HLTV/Core/src/BSPModel.h create mode 100644 rehlds/HLTV/Core/src/Delta.cpp create mode 100644 rehlds/HLTV/Core/src/Delta.h create mode 100644 rehlds/HLTV/Core/src/NetSocket.cpp create mode 100644 rehlds/HLTV/Core/src/NetSocket.h create mode 100644 rehlds/HLTV/Core/src/Network.cpp create mode 100644 rehlds/HLTV/Core/src/Network.h create mode 100644 rehlds/HLTV/Core/src/Server.cpp create mode 100644 rehlds/HLTV/Core/src/Server.h create mode 100644 rehlds/HLTV/Core/src/World.cpp create mode 100644 rehlds/HLTV/Core/src/World.h create mode 100644 rehlds/HLTV/Core/src/precompiled.cpp create mode 100644 rehlds/HLTV/Core/src/precompiled.h create mode 100644 rehlds/HLTV/Core/src/public_amalgamation.cpp create mode 100644 rehlds/HLTV/DemoPlayer/build.gradle create mode 100644 rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.sln create mode 100644 rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.vcxproj create mode 100644 rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.vcxproj.filters create mode 100644 rehlds/HLTV/DemoPlayer/msvc/PostBuild.bat create mode 100644 rehlds/HLTV/DemoPlayer/src/DemoPlayer.cpp create mode 100644 rehlds/HLTV/DemoPlayer/src/DemoPlayer.h create mode 100644 rehlds/HLTV/DemoPlayer/src/precompiled.cpp create mode 100644 rehlds/HLTV/DemoPlayer/src/precompiled.h create mode 100644 rehlds/HLTV/DemoPlayer/src/public_amalgamation.cpp create mode 100644 rehlds/HLTV/Director/build.gradle create mode 100644 rehlds/HLTV/Director/msvc/Director.sln create mode 100644 rehlds/HLTV/Director/msvc/Director.vcxproj create mode 100644 rehlds/HLTV/Director/msvc/Director.vcxproj.filters create mode 100644 rehlds/HLTV/Director/msvc/PostBuild.bat create mode 100644 rehlds/HLTV/Director/src/Director.cpp create mode 100644 rehlds/HLTV/Director/src/Director.h create mode 100644 rehlds/HLTV/Director/src/DirectorNull.h create mode 100644 rehlds/HLTV/Director/src/precompiled.cpp create mode 100644 rehlds/HLTV/Director/src/precompiled.h create mode 100644 rehlds/HLTV/Director/src/public_amalgamation.cpp create mode 100644 rehlds/HLTV/Proxy/build.gradle create mode 100644 rehlds/HLTV/Proxy/msvc/PostBuild.bat create mode 100644 rehlds/HLTV/Proxy/msvc/Proxy.sln create mode 100644 rehlds/HLTV/Proxy/msvc/Proxy.vcxproj create mode 100644 rehlds/HLTV/Proxy/msvc/Proxy.vcxproj.filters create mode 100644 rehlds/HLTV/Proxy/src/DemoClient.cpp create mode 100644 rehlds/HLTV/Proxy/src/DemoClient.h create mode 100644 rehlds/HLTV/Proxy/src/FakeClient.cpp create mode 100644 rehlds/HLTV/Proxy/src/FakeClient.h create mode 100644 rehlds/HLTV/Proxy/src/Master.cpp create mode 100644 rehlds/HLTV/Proxy/src/Master.h create mode 100644 rehlds/HLTV/Proxy/src/Proxy.cpp create mode 100644 rehlds/HLTV/Proxy/src/Proxy.h create mode 100644 rehlds/HLTV/Proxy/src/ProxyClient.cpp create mode 100644 rehlds/HLTV/Proxy/src/ProxyClient.h create mode 100644 rehlds/HLTV/Proxy/src/Status.cpp create mode 100644 rehlds/HLTV/Proxy/src/Status.h create mode 100644 rehlds/HLTV/Proxy/src/precompiled.cpp create mode 100644 rehlds/HLTV/Proxy/src/precompiled.h create mode 100644 rehlds/HLTV/Proxy/src/public_amalgamation.cpp create mode 100644 rehlds/HLTV/README.md create mode 100644 rehlds/HLTV/build.gradle create mode 100644 rehlds/HLTV/common/BaseClient.cpp create mode 100644 rehlds/HLTV/common/BaseClient.h create mode 100644 rehlds/HLTV/common/BitBuffer.cpp create mode 100644 rehlds/HLTV/common/BitBuffer.h create mode 100644 rehlds/HLTV/common/DemoFile.cpp create mode 100644 rehlds/HLTV/common/DemoFile.h create mode 100644 rehlds/HLTV/common/DirectorCmd.cpp create mode 100644 rehlds/HLTV/common/DirectorCmd.h create mode 100644 rehlds/HLTV/common/InfoString.cpp create mode 100644 rehlds/HLTV/common/InfoString.h create mode 100644 rehlds/HLTV/common/NetAddress.cpp create mode 100644 rehlds/HLTV/common/NetAddress.h create mode 100644 rehlds/HLTV/common/NetChannel.cpp create mode 100644 rehlds/HLTV/common/NetChannel.h create mode 100644 rehlds/HLTV/common/ServerInfo.h create mode 100644 rehlds/HLTV/common/byteorder.cpp create mode 100644 rehlds/HLTV/common/byteorder.h create mode 100644 rehlds/HLTV/common/common.cpp create mode 100644 rehlds/HLTV/common/common_hltv.h create mode 100644 rehlds/HLTV/common/mathlib.cpp create mode 100644 rehlds/HLTV/common/mathlib_internal.h create mode 100644 rehlds/HLTV/common/md5.cpp create mode 100644 rehlds/HLTV/common/md5.h create mode 100644 rehlds/HLTV/common/munge.cpp create mode 100644 rehlds/HLTV/common/munge.h create mode 100644 rehlds/HLTV/common/net_internal.h create mode 100644 rehlds/HLTV/common/random.cpp create mode 100644 rehlds/HLTV/common/random.h create mode 100644 rehlds/HLTV/msvc/hltv.sln create mode 100644 rehlds/common/IDemoPlayer.h create mode 100644 rehlds/common/IEngineWrapper.h create mode 100644 rehlds/dedicated/README.md create mode 100644 rehlds/game_shared/bitvec.h create mode 100644 rehlds/game_shared/counter.h create mode 100644 rehlds/game_shared/voice_common.h create mode 100644 rehlds/hookers/HLTV/Core/DeltaEx.cpp create mode 100644 rehlds/hookers/HLTV/Core/DeltaEx.h create mode 100644 rehlds/hookers/HLTV/Core/hooklist.cpp create mode 100644 rehlds/hookers/HLTV/Core/hooklist.h create mode 100644 rehlds/hookers/HLTV/Core/main.cpp create mode 100644 rehlds/hookers/HLTV/DemoPlayer/hooklist.cpp create mode 100644 rehlds/hookers/HLTV/DemoPlayer/hooklist.h create mode 100644 rehlds/hookers/HLTV/DemoPlayer/main.cpp create mode 100644 rehlds/hookers/HLTV/Proxy/hooklist.cpp create mode 100644 rehlds/hookers/HLTV/Proxy/hooklist.h create mode 100644 rehlds/hookers/HLTV/Proxy/main.cpp create mode 100644 rehlds/public/HLTV/IBSPModel.h create mode 100644 rehlds/public/HLTV/IClient.h create mode 100644 rehlds/public/HLTV/IDirector.h create mode 100644 rehlds/public/HLTV/INetChannel.h create mode 100644 rehlds/public/HLTV/INetSocket.h create mode 100644 rehlds/public/HLTV/INetwork.h create mode 100644 rehlds/public/HLTV/IProxy.h create mode 100644 rehlds/public/HLTV/IServer.h create mode 100644 rehlds/public/HLTV/IWorld.h diff --git a/publish.gradle b/publish.gradle index da624f1..ee78197 100644 --- a/publish.gradle +++ b/publish.gradle @@ -35,20 +35,32 @@ task publishPrepareFiles { } pubRootDir.mkdirs() + project.file('publish/publishRoot/bin/win32/valve/dlls').mkdirs() + project.file('publish/publishRoot/bin/linux32/valve/dlls').mkdirs() // bugfixed binaries - _copyFileToDir('publish/releaseRehldsFixes/swds.dll', 'publish/publishRoot/bin/bugfixed/') - _copyFileToDir('publish/releaseRehldsFixes/swds.pdb', 'publish/publishRoot/bin/bugfixed/') - _copyFile('publish/releaseRehldsFixes/libengine_i486.so', 'publish/publishRoot/bin/bugfixed/engine_i486.so') - - // pure binaries - _copyFileToDir('publish/releaseRehldsNofixes/swds.dll', 'publish/publishRoot/bin/pure/') - _copyFileToDir('publish/releaseRehldsNofixes/swds.pdb', 'publish/publishRoot/bin/pure/') - _copyFile('publish/releaseRehldsNofixes/libengine_i486.so', 'publish/publishRoot/bin/pure/engine_i486.so') + _copyFile('publish/releaseRehldsFixes/swds.dll', 'publish/publishRoot/bin/win32/swds.dll') + _copyFile('publish/releaseRehldsFixes/libengine_i486.so', 'publish/publishRoot/bin/linux32/engine_i486.so') // dedicated binaries - _copyFile('publish/hlds.exe', 'publish/publishRoot/bin/hlds.exe') - _copyFile('publish/hlds_linux', 'publish/publishRoot/bin/hlds_linux') + _copyFile('publish/hlds.exe', 'publish/publishRoot/bin/win32/hlds.exe') + _copyFile('publish/hlds_linux', 'publish/publishRoot/bin/linux32/hlds_linux') + + // HLTV binaries + _copyFile('publish/hltv.exe', 'publish/publishRoot/bin/win32/hltv.exe') + _copyFile('publish/hltv', 'publish/publishRoot/bin/linux32/hltv') + + _copyFile('publish/core.dll', 'publish/publishRoot/bin/win32/core.dll') + _copyFile('publish/libcore.so', 'publish/publishRoot/bin/linux32/core.so') + + _copyFile('publish/proxy.dll', 'publish/publishRoot/bin/win32/proxy.dll') + _copyFile('publish/libproxy.so', 'publish/publishRoot/bin/linux32/proxy.so') + + _copyFile('publish/demoplayer.dll', 'publish/publishRoot/bin/win32/demoplayer.dll') + _copyFile('publish/libdemoplayer.so', 'publish/publishRoot/bin/linux32/demoplayer.so') + + _copyFile('publish/director.dll', 'publish/publishRoot/bin/win32/valve/dlls/director.dll') + _copyFile('publish/libdirector.so', 'publish/publishRoot/bin/linux32/valve/dlls/director.so') // hlsdk project.file('publish/publishRoot/hlsdk').mkdirs() diff --git a/rehlds/HLTV/Console/build.gradle b/rehlds/HLTV/Console/build.gradle new file mode 100644 index 0000000..31d9a2a --- /dev/null +++ b/rehlds/HLTV/Console/build.gradle @@ -0,0 +1,153 @@ +import org.doomedsociety.gradlecpp.cfg.ToolchainConfigUtils +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.gcc.GccToolchainConfig +import org.doomedsociety.gradlecpp.toolchain.icc.Icc +import org.doomedsociety.gradlecpp.toolchain.icc.IccCompilerPlugin +import org.doomedsociety.gradlecpp.GradleCppUtils +import org.gradle.nativeplatform.NativeExecutableSpec +import org.gradle.nativeplatform.NativeExecutableBinarySpec + +apply plugin: 'cpp' +apply plugin: 'windows-resources' +apply plugin: IccCompilerPlugin +apply plugin: GccCompilerPlugin + +List getRcCompileTasks(NativeBinarySpec binary) +{ + def linkTask = GradleCppUtils.getLinkTask(binary) + def res = linkTask.taskDependencies.getDependencies(linkTask).findAll { Task t -> t instanceof WindowsResourceCompile } + return res as List +} + +void setupToolchain(NativeBinarySpec b) { + def cfg = rootProject.createToolchainConfig(b); + cfg.projectInclude(project, '/..', '/../..', '/src', '/../../common', '/../../engine', '/../../public', '/../../public/rehlds'); + cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', '_CONSOLE' + + if (cfg instanceof MsvcToolchainConfig) { + cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig( + enabled: true, + pchHeader: 'precompiled.h', + pchSourceSet: 'hltv_pch' + ); + + cfg.singleDefines('_CRT_SECURE_NO_WARNINGS') + cfg.compilerOptions.args '/Ob2', '/Oi', '/GF', '/GR-' + cfg.extraLibs "user32.lib" + } + else if (cfg instanceof GccToolchainConfig) { + cfg.compilerOptions.pchConfig = new GccToolchainConfig.PrecompilerHeaderOptions( + enabled: true, + pchSourceSet: 'hltv_pch' + ); + + cfg.compilerOptions.languageStandard = 'c++0x' + cfg.defines([ + '_strdup': 'strdup', + '_stricmp': 'strcasecmp', + '_strnicmp': 'strncasecmp', + '_vsnprintf': 'vsnprintf', + '_snprintf': 'snprintf', + ]); + + cfg.compilerOptions.args '-Qoption,cpp,--treat_func_as_string_literal_cpp', '-fno-rtti', '-fno-exceptions' + cfg.extraLibs 'dl' + } + + ToolchainConfigUtils.apply(project, cfg, b); +} + +model { + buildTypes { + release + } + + platforms { + x86 { + architecture "x86" + } + } + + toolChains { + visualCpp(VisualCpp) { + } + icc(Icc) { + } + } + + components { + hltv(NativeExecutableSpec) { + targetPlatform 'x86' + baseName 'hltv' + + sources { + hltv_main(CppSourceSet) { + source { + srcDir "src" + include "**/*.cpp" + exclude "precompiled.cpp" + } + } + hltv_common(CppSourceSet) { + source { + srcDirs "../../common", "../common" + + // common + include "BaseSystemModule.cpp" + include "ObjectList.cpp" + include "TokenLine.cpp" + include "textconsole.cpp" + if (GradleCppUtils.windows) { + include "TextConsoleWin32.cpp" + } + else { + include "TextConsoleUnix.cpp" + } + + // HLTV common + include "random.cpp" + include "common.cpp" + } + } + hltv_engine(CppSourceSet) { + source { + srcDir "../../engine" + include "mem.cpp" + } + } + hltv_pch(CppSourceSet) { + source { + srcDir "src" + include "precompiled.cpp" + } + } + + rc { + source { + srcDir "msvc" + include "hltv.rc" + } + exportedHeaders { + srcDirs "msvc" + } + } + } + + binaries.all { + NativeExecutableBinarySpec b -> project.setupToolchain(b) + } + } + } +} + +task buildFixes { + dependsOn binaries.withType(NativeExecutableBinarySpec).matching { NativeExecutableBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} + +task buildRelease { + dependsOn binaries.withType(NativeExecutableBinarySpec).matching { NativeExecutableBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} diff --git a/rehlds/HLTV/Console/msvc/Console.sln b/rehlds/HLTV/Console/msvc/Console.sln new file mode 100644 index 0000000..da920d1 --- /dev/null +++ b/rehlds/HLTV/Console/msvc/Console.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Console", "Console.vcxproj", "{D5CAB879-D54F-456F-8592-31D549CFD1D8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D5CAB879-D54F-456F-8592-31D549CFD1D8}.Debug|Win32.ActiveCfg = Debug|Win32 + {D5CAB879-D54F-456F-8592-31D549CFD1D8}.Debug|Win32.Build.0 = Debug|Win32 + {D5CAB879-D54F-456F-8592-31D549CFD1D8}.Release|Win32.ActiveCfg = Release|Win32 + {D5CAB879-D54F-456F-8592-31D549CFD1D8}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/rehlds/HLTV/Console/msvc/Console.vcxproj b/rehlds/HLTV/Console/msvc/Console.vcxproj new file mode 100644 index 0000000..c1bd1ca --- /dev/null +++ b/rehlds/HLTV/Console/msvc/Console.vcxproj @@ -0,0 +1,186 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + Use + Use + + + Use + Use + + + Use + Use + + + Use + Use + + + Use + Use + + + Use + Use + + + + Use + Use + + + Use + Use + + + Create + Create + + + Use + Use + + + Use + Use + + + + + + + + + + {D5CAB879-D54F-456F-8592-31D549CFD1D8} + Win32Proj + Console + 8.1 + Console + + + + Application + true + v120_xp + v140_xp + MultiByte + + + Application + false + v120_xp + v140_xp + true + MultiByte + + + + + + + + + + + + + + + true + hltv + + + false + hltv + + + + Use + Level3 + Disabled + HLTV;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;%(AdditionalIncludeDirectories) + precompiled.h + + + Windows + true + false + user32.lib;%(AdditionalDependencies) + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + echo Empty Action + Force build to run Pre-Build event + git.always.run + git.always.run + + + + + Level3 + Use + Disabled + true + true + HLTV;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;%(AdditionalIncludeDirectories) + precompiled.h + + + Windows + true + true + true + user32.lib;%(AdditionalDependencies) + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + echo Empty Action + Force build to run Pre-Build event + git.always.run + git.always.run + + + + + + \ No newline at end of file diff --git a/rehlds/HLTV/Console/msvc/Console.vcxproj.filters b/rehlds/HLTV/Console/msvc/Console.vcxproj.filters new file mode 100644 index 0000000..0bc41ab --- /dev/null +++ b/rehlds/HLTV/Console/msvc/Console.vcxproj.filters @@ -0,0 +1,106 @@ + + + + + {9111aa50-a4d2-45d9-8e74-ae8045065799} + + + {753dfdd8-0143-4b2f-8da1-0d60981a1388} + + + {2fbfe7d4-1a55-4e00-a1d0-7a0fea11bdc1} + + + {36d6fd93-a7f4-4f53-9a15-9983679abe00} + + + {26672827-46c9-4080-babb-f002c2e71cf8} + + + {6b303ee4-f4a5-4e82-8a4d-a374240de8d0} + + + + + src + + + src + + + game_shared + + + game_shared + + + game_shared + + + HLTV\common + + + + HLTV\common + + + common + + + common + + + common + + + common + + + engine + + + + + src + + + src + + + src + + + HLTV\common + + + HLTV\common + + + common + + + common + + + common + + + common + + + common + + + common + + + engine + + + + + + + + + \ No newline at end of file diff --git a/rehlds/HLTV/Console/msvc/PostBuild.bat b/rehlds/HLTV/Console/msvc/PostBuild.bat new file mode 100644 index 0000000..8583878 --- /dev/null +++ b/rehlds/HLTV/Console/msvc/PostBuild.bat @@ -0,0 +1,39 @@ +@echo OFF +:: +:: Post-build auto-deploy script +:: Create and fill PublishPath.txt file with path to deployment folder +:: I.e. PublishPath.txt should contain one line with a folder path +:: Call it so: +:: IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") +:: + +SET targetDir=%~1 +SET targetName=%~2 +SET targetExt=%~3 +SET projectDir=%~4 +SET destination= + +IF NOT EXIST "%projectDir%\PublishPath.txt" ( + ECHO No deployment path specified. Create PublishPath.txt near PostBuild.bat with paths on separate lines for auto deployment. + exit /B 0 +) + +FOR /f "tokens=* delims= usebackq" %%a IN ("%projectDir%\PublishPath.txt") DO ( + ECHO Deploying to: %%a + IF NOT "%%a" == "" ( + copy /Y "%targetDir%%targetName%%targetExt%" "%%a" + IF NOT ERRORLEVEL 1 ( + IF EXIST "%targetDir%%targetName%.pdb" ( + copy /Y "%targetDir%%targetName%.pdb" "%%a" + ) + ) ELSE ( + ECHO PostBuild.bat ^(27^) : warning : Can't copy '%targetName%%targetExt%' to deploy path '%%a' + ) + ) +) + +IF "%%a" == "" ( + ECHO No deployment path specified. +) + +exit /B 0 \ No newline at end of file diff --git a/rehlds/HLTV/Console/msvc/hltv.rc b/rehlds/HLTV/Console/msvc/hltv.rc new file mode 100644 index 0000000000000000000000000000000000000000..fe2b9fda974fffbdeb37848532da78e2ae07a8a2 GIT binary patch literal 5136 zcmds*ZBH9V5Xa{&mGT|7$D2g007Ig@25i8Ju~BT3L_)GCU}Fgk@&jq5e)hJ%|E~9Z zceV+Tyl|@1dGB^-X6NC*Gjsm;pH15|XUEpJ3me*^3uzCaarKe5i_&4m@5>GA8 zbx+sze3HFuC)TuHJ;=C(qZ+ks9hYL9paaw zkGpv3&Tg@PjCbUR7FK`ew~E#K*eQQhnBV3uM&#Qu`0D)|`11Z=J=0y-x6N=WKr z_sg&mJs;(+))=*O#QBO-GbXy>OctX&%AA?L_s6ffvvX;$@z4RN31_Cs`Dk-`_Q6dD z^whZC;KjeW+)~aKGCqRQ4*FE!f0Lf;ZW@PLbsRl6e&W~@4Xj#oQQKcE;t*)K!=QT?sL>@E3x-GexrUmQMr4*<&=9^e&}N>S~tBG=kPPzn&$BeehdB*mon7z zcUV+85}VIkiJgIsGol@8$V|s&`s}<&pXctf4nAiH3|a|?i?Y@{&SG>{D>r4ek%oGY zqXQ*6mxFXBYr|~S`53CIIl6*7-qcN~1F3=;XAeHxO_+6@?i=3JW2o;?PcWR)j^T9P z!|GX-86A}OoU79Fv(nq#P>J68AoWG{4w~V2} zO5-Y-rAkg!H=?uj*cIs>qsgu%sqP!or-1Qn99HW&8}rrDENT<+8b@`$>TebOMd*!{ z>qphHQ|euZJu6heCdd(PgrGW=x&eCfD{)@h9za!tFHhm@EmgFX-l9A~b^~m-!DZ_S z^ilGGufm7ubxd_`QuiD^M9}zv{X1T=G_QC~M57*5{X?E=mwor`h}H76BG2zpV_7aE24p-*6U0Qq*oOs<%(YpnG=y$RbL*G%P+=jMIG(K=kcHQSQ z@#Smbn(tW}SSc?h=%7wb8KuXLeR9SX@fwh|?xvMV9NB8RWFf>}ZjpZSrn2*pQPvb~yk>5UjT_MX$-P`sjn$r) zA+O!zFGa409pltv^D8wJPlb-fdG7|+@M zlBnb*J})-24sQ+o#cr>NXQ6JG+Wzg+kVkY2UZHt}|7P_(pk|8*Z+UF1@7I|LsGjLE zd(z7CZtQ7aS+RPo-YDy`xBBKTUi-g()qLN-CF=c)-_iMhOQJ7VFVaz?$MHNMOQ?ID K|8HdeE8{=@7iz%( literal 0 HcmV?d00001 diff --git a/rehlds/HLTV/Console/msvc/icon.ico b/rehlds/HLTV/Console/msvc/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4abe0909b1a71d988ded3a2c1c1d067a6a8c3e21 GIT binary patch literal 120505 zcmeEP2Ygh;_MRk!gc?M#AR4ey6b0!eyXhn(B%y{h2&55e=m|A6#R8~U@F`+@_FnPX zqA2=oSWr+AgV=xsf`}v#a{u2qvv>Dqb2r%yp}fEDFJI=)+_^L7%sF$W-nl|}iN>N; zD*?B?n9xXwY#~JZ_R9Yl!aqY;w{AB7BS5cV(JPn(FuMeg%A}EM+l_5WU_+v$|S57>jXUiQLxqeanzv5PX@(}{$XHT zPF3e23wQWu?3j0X&f9mlpYY);B76Tkc)k?a0CWH@0DSQLN<6O-F@pzd!-pnl@k3&? z5KGYBn5c+1Cr-%TGj;OBo5cjJDdLX3i@MGvp+1EhTw@D_0HfRMq<`h~_F?-`L+9%K!B8|kd<9Xa9Yz}WTM+QdHH zbxCHoW-Zc6*5cVefLFa!E6x=Y_W9%4C?MdR`h-GZU&a;3Gt4X z5XC-1l;OFmKq2i69}5O(f8-B_$Jx%P8@2qOs)2XNDCZB$1meI%blMwQmpFI@lYFFKmP_Y=iHZw6w-4$;o~xqY@hT zOIqI4Kl6t$pR8XW^UnHxk9XD{XO_Uw5e&UecGCSv41aeE2sj>*p&5{9}d zZQVqiX=tihodApfnjkw%1thH9{L+7O9oEiNWn zi;0Sa{T-)X*sj5$jr@KI(~A&Yu8TRI9z0xp9g~)-p?pAR&?alpz#9_c#tQ}Fu$;^GnabRQTz=!fcgRo6u; zc#Vo0u8kNm)h2(-PvC#ku%SagLEe8d|2eZ~l_kyC5F7R#^M@@J~riJqu+X3*Mj4 zpEK*T%QLrbK!0El@_rSV2y|?eUV+}#f2j|xfLQ>`;(eeQAo_>JU0}5a+vKnJHzX~G zLC+pwug%@lKRBkmZ^%&Xioq*Uep(ZeQYq%lnIl##nAjwK+GCv?r5yecd9qz5s(`KN z8(bk;mW!72%18s-HMU_(0m?>LLqc0ytikW2kD{T!qIDdy^l0bU`Bez}2>JE}E=Sp1 z9vsx~(tzQg+}3pDcUt4b-wyjF{+u+jkMIu)i}dkM`UCCi(Lu=XPg~yK!2KC`!*_f| zOCgTv`BUZtfb#&-;w5g=#Kpt!9(z{G8%LXs{Z#YH-uHN`)OV-%4~h8-<#MAne9#bU zSY$$QXh{5(gBRs@jJe@Zw}{DF@37QgP$xG9hlI@TG-6$2;kamR>4yP%b%TBY;ZSQtHO6^F}-+kasld<$Guw-UsNuhqBld z7aQ~Y$YBZE$YDdZ5yOVTjeqs5q;1`iU$HI!SKu~noKYbxZyxmudPBlkCuo;wqrU;N z0m>yE(CbG!+8NeMZ{*hkWgh^vBp`zpqf)XWu1a}+%cUtr+GQzkRdi2%0{xkzQ*3!x z!c7O?vaf}_y#YbUpUNu^dFl0ldcge081f${!_*Vi|0kg>PCf=4PeLE?2mn1h_B`_Z zz?T14a4!@iDwt<=-kFlhi~UJG|3X_>ydiA13WI$z`>Fn8GvxEEEzjd{3F`cE5nCZb zHaYUP^PaUw&p!j{v#cqDDJrkho^THU48KR@DBEb3J@Nqm62Wjw0lmJl-uIxcBhTvP z&V&^2blC9%pY4gOGNaEg$xO8xMF5X(2C>Q%W5;V!QVQ{Qg2bYtL8mqxkkio|gmH0Gn<3 z)9#%O=s8w*74H}yLAHu_>K}Dp#Z&ib58t%ir));a`+6M4RQY#;OZ&DLV11+f=K$({ z^_-1zk4AdBj(v=4%G{Vg$K?i)m+FEh)-Q* z8pna}0NRgE7zZ&OUw~!vAi#RX{3t)_4&&?3vHZILwdZZ8!Cnrm6ElHgfO@kDpv~+6 z^aC~k9P8*jI=jE)-co@5P}Xrh2lre>FU$K%U=nbNOeec^G+grPoFDz`>VEAm=gD8ynAW(Cd`!XL8;Ep=d4!3Pi_!mDr`W)sp8H*dM{1{#-L zU)~64Qg(f1v$AEC0maLz0*l`%3w-CDGV43VW!7cIc~+mYz@Pof{R#sry+t5K;8x9F zEY?2s(zGf+Oj}*AaXz#gkPg`ADK4wWJO!S2`J-K-?qgmO;MkWs!m{ERehoLhPx`c^YB4*UxF8fe}RItjOV(BuAzXISUs zeI}GP5#m$v254~Shw%gZ^p~Pfe*#o=&&3OFkaPoNZUk z+OhvxCkvpL^k=|zIZoz1&P(XP9F1lj*x!Mm{#tO*0L@|zsXRaNiAP1wpXs0@6u^A# zADu+jkxp&1KZ))#@vS8n(lVFf@FKme_Qi9k2$w{hSO{m>aLZ|W3n zenGxAFMn<|Ff2PWQ=dOMit#PiN0K3{)WpQZJj`Ql29E0USyQJ@d+Lt6*7?j^awBOX zXyem?&jIS4kq_vboOg|Z`zF9T9}hT}e|BBv9~~7XWk5Mdpv+nB1nP)U_o|TAanOH! z#E219n18d+#gPZnfBPMG`7B+!OwmAEIL^o}4FsrL#&(;$P&TX=ye5AsfHVDBwb9Re zy6&5~X3sJn=+`FJpnvMqx2?UyXNgX~PKlBQ^h&lN`%!m|axh*~=k%up^5&dIo%Ea0 zSX-D*|K!P&HOfFoUS8hQYj3}^(X!<$>@)~R|GGJ7O9plUMw*S+Y97G$w2l7E+GwfI zJ<<>T*Jff4k#m_k^7Heb*|1?lqt&Zdo6*m41=|!Oz0TK5aUbm`>=Aw^NqSy%;OUNb0HFW0t_->;8*5JtGZnTnB04VS}{=3pPWyAJF5|el7(4 zkwF6o4jMCNObY0K5#@eJFaLQ3bDs7~JDi4bG3SCgKi3)X1%ybb5R=gTSctyEoI_O{ z-*g5Z0N9r6^goVk#~5N_RgVrsZ~Kqu^jox$;4m#MZ7J-`6wohqs2uaYQEb1K-?T=| zm^o9-EtuDA&fK{%;NzJ&b7ucID}TubpOhn<%jEn9=NWzh9tTo^i?L?x6Y*a)&*qoM za+d3%X`uNV8xJqT<+xauf3PJ;Sb{^xo9jqTy>^agLBGLj?>~fU9S5(RKC=sww#_>% zUv;a1&WnP1^P8?(I^}{6ncv6Y-hM!zpVQrA2>Tl7ZJVo8eNfV=a2ebUz$<`#o&xmH zevYe77wHbtu-4B$4RvE5@F4In;BH_Ya2Mj--Zy0UBUePo+1r zy9{(F{nY;_Vw5rtHY54y4JNefJba7!wm|lM?PCBnzMw9#AHi`3$G-l6Oj-6nLqdl^ ze~u^}vTA)phiaE5+;qHU+WSYl#Lgoxe}Ko4*8Y8jH6mK4NQe~Blq%Q#v1fqgS+02{ zAJM#%4&B-*W~F~vSWu&&m|nh=n> z=~b*>97K74i8X`nmZ2$UTjEEbYl%w)Mx7TG)Bl`SiCc!BKkTK0R}L!Bh^~>-4-T|O zY{WCqLw>UdhDSAPHtIXlKNg^#==5`bu?;}JsQ*1|WnX>#qV$L3@t**Umr5GJy##0} z3sbE%WMi#ClThmoZ=jFZL`>6~LXUDm%VEf1H`ZmpM*aK-*amC|zO@90?XZLosfY*- z)*?c!Krn1mC=dqQ8h$u3dT^x3)o5d00Cd{v+UF;2`eHtQRPP$D&p5s*0^S1NwBZf7ufx{A78e`)ZEDhJEiGwOH6W}c zEooSP>@VpBdX4kyKfzDiDT3cQDh9kJ=a)J5tzPylU`78$aCh2hJPLOQfVyC(f2Hl7 z&cluH3-6r0!rHeN>$opyZQ=xf`2BnI=-GHo^2p$r)P+x7oASu9?kSII-BTXZa9t6R zdfl|ICkSuQxe_pz{XJ;E7_Qe<(p__Xz(Ic-&|~adU_6KY9r~IC_tR7_|7E0K@+Xz7 zj(^F=q2I^P$GQ!4`WWccQMn2>=VH*g)jpi%>7brJ`y@~4J;Y|F&XvAHdZhuTkADt0Q~^1 zw*p4`pKCt3qUmJqn0vG{6GcC5|8@gyTss-bdv^JC{+aV#oU1n00m?(_kRH#>t-*`Z zp(dc+(cY$19EHv&i?|ALt8Fc|#&gaA*>>AF4s=ukx^C>ib$dWQ5nO~ah7N)LOA$uB z*W*#&@;I+L=%dPNGIuHeadtb3HrG&xQz|}#|2)8%O4oi>_M9Jj%Rm!p`xnOi-f$hy z@;Xbdq21yXcPsp~U3OVH%Rr6;xrZ#dVhpejSPjs|8+B(9{EXwsv$iWmJN1Y4mUBRQ znX=sq12~^pJq7g)=kb3v#OHJ5iS?s;eBH-7J4VvRcFIVze*G)LuXdYu)#oSeTyOds z&}papB%tOL_55{L(NDSD;PedbF53rHpY-^;OZrnK{r9+_|3QS;TnpBpcXm}iTrYjZ ziH;KZgC!k?IoxWGt7iid=ToO=i|x-cj`8Q9e<|qv4&Zo1#}~Nf9wxQV*!Y~;waTCK zaMuB}Gsd!KpV9{~ds2m|=UL8i0O#+G&$G=N2vnDYgZ`GFlXdi51J1#9e2 zRy=UL%=s>7IdU9S2(V8GS*W?NI!RS&HpVj@0FD8b9M%4W0r0a=U~GTL1N&*v1v!^e zXBO2WsPtKnSSCjSW0|l$c^^mw0su7+UM&HeN2No0`vCU?&jXyRWxt>kKzs2!U`(Ia zzW^gpK8$CUa@}Dn?`C*@5kTAPoCo!kx;YiN8lcQjuJ*Q*boT=82KEAcp0*(#SPK*b z#(tTeKI>YPlx=-!*SS+XkPephHbBqA=#sYwfi3{`g7u>Za3`<_Fvg`U|8fe`?^9P_ z0J>r?IArRkZtAqUa!Hfwr*=fz{{qSY=E?G7*@gks3DVsSVA-1KgifcKyA#jM09pYo z16S14KU}5DI!Jo&2ht&9`k5c|y&iBbZ!=o;FzU`vz$&2g3F*4KTsiEWKk{VXh~-ZD z=^qZzj<8Ph+PVF4_E+G!pMj0Q9H2XFI>%6=?M;XDGBBUpH>d98gi_9Id$S~M z7SP9j5Ziv|KD#r2p7^OF)S0J%1fZo~-T{5?ruKQ>lf$)2bvg`OK5BgK;l5a-dKi7n z0|59kgUf!0C*{Dn?BlYIu&?f)uW4Qh-&Bcsz|)^4ayRJ2%RBebxC=eapy0@#+9f_5BqnL-!(xt;YrAPbNm{36 zjTHIg2l-<^VA$lT(-&ptExMs!-fKfp4(ub|3vh0P<8qf}0sdJhZUs2kq55Y`U0$=l zR>FK~m#dYJH7o-BM+AU>>~(QZ_RxC`@6t*Pg)5N&7w>lx!-%0n4f`LFt~L1E;PA+{ zfXu(!wbu&l`4ZzZGMZ&&XGiDe=01sicxBv+hrMA(=gyfOJ8fn@>F4;PJ;1hv^Abma zn&qJOwb9-_3ot&P1*A>p*ykajtqe1ifHf5I4~_JQ|BP|tw55fMwIz!enE>Iqw`@tF zmX(>|s7qGsF09E%p^Uo&J)l25un#C6d_N1G50Y;k`|l;o7ZocCes@(2HMGiKQM*D03eAorICf{!%-=SCc5Q2m-^ z^n>9(+fJ5;o|<%({ztZi{(lIXjP%xe?P>itOFKC^S?+(-<*vJvr2J=t{~6V2wR>ba z$g?|WA7~p?8C2H+=W;1SJkEF7li`J}{(H>789$zex#WKm^?!D}Oa4hX%V2`kg`VJP zGxh^%uz}7z8~v;U!8Q4p_MiNJ;3@ql8s8QFs{Yr-Kjf&!7Z-!4^+0udpzDOgrQM7< zllV`A{eX-$oP$se*i(CK;lhOp+@ELq zF=KcRLbZLk+z*O(^p6!57AD|)1XK2K?WmTf&HlH5{-0_5 z4|U1E&Vece&e0A--TxG*s}67uS%`^P1F-#U_K*C(@2UK1iysmkT5J2kXVL!GCjYwm zCl45R`c63@yeG*02<-pS&KqTJyk0E%=e(Exo38mZANxs2pRf_d+?!e(Pww1fyEuCE zTrI!gZEe)Z8M2>jd+re2X8@d&C9z@r`0;N*|NqqYKuK!>H_-B^6VrtUEr8QwH-SD*#{yUW$ym2Ths(OUa`@70_6~d ze%uCa?d=s>PR=?9|5ocx)U^)Qt1t6H9^Thzcu$iCT8SK6Z!KO zHk+GYfW72%o`UWBt{{KTR|zwon=X=$?E;_rUI)6|W4i<3eu8*_>)Bq}$K@FYj(IR8 zV~%yA0FD`G`&kZ;fOl`WItjuO7DY72_=M+moPgYo&vJao{pURYMvaRH1P?B~ByL^* zE-_1M>=&3Yd8$~nXt5}mzo6;j!oqg9TtEB#CTV{x25&~*ov*oX@pB+tgxL4YNnMc4 z$ugj>%X7e1z@=Sy5%2}<{M+n5__uCy#lJqbx7|Mumv#9M8@Pv>z?nFf12*g*XdP6J z^Jg>yylY*e7HEw}?|De1;f-2@?%D~_FOqOxNYb&^h@+no;>@?v&wXosg}-Cpnx2f^ zRpr1j>hbL;+L`}q={b1_HU)T>n2W}srAJEr! z-5YK%pl4`M&u-_(Kfk2;h_5S~kNjF|KJpvQcl2J;>+X0I*}=)A`5!8p_7S!94;P zc{RJ<2)o#H*iMsoV{;*6wJyssUjRT|;QUB+{U4klEU_aRV{H0_s;ksjRcFa}`(d|h zP13)r@EiYq)iqI*un0H~n${e@YeVX65^i{lfD6Kl1Pa-UYY-dLV+* z^SpXI_`2x1;T4sP;+=a^9x&m3C&E?(9|L;XOcsNn`)``efjiE47zUnU_iX3Zac`Cy zKVk1diLeYy71n_RL}+mTPFKdxedwYQ>$P?x?$g?idPHlQ{v~b3G0fF05jh9%IxFR^ zef>jXkD;87Tdg5Wt%KrxjP}f47F_t@*@LNCV)Ml9e_bAPGtOYTLAxS)rPeX}y2@T* zss9PKTJD3+t+#}P=2{}61K1A%U&NKb&w#VMZuPj%DqU-91> z^nV7BmoI@(fb&2T0B;%Fu@1=o6XO~2J^XA>`93ocdXCh88~r*T=5CM{hW9Phxp;$d zHl7asoIINw7yshu@d@bP9H-seY{LI@2(#Nw!#+p0d9L>wD?O*Zr`^|i`U%&ofO`Qf zw&5q^;r(YdN2bTqU9_Ji%^Al!EKNXmEC<@UM*;Tdo(7%*o&;b+Bp!$R82W;b;GNue z$E2nlPftzK#+hI&?xm%sEp9xLXM$A>0seC0|0w*)fT|xL*TBDP+3S2Ip)S_kqfFl3 z2AVUPjeqtRxK^d}t-CKE%-&|&+Dk9!0N?v?Mk9pTft0;cQj+_mrH*+jGG)acYsxK} zHDwJz_ZBTUW%bdasnb?vj2YTmBw-CDx#E5&-dPVm1MvQZ(tQK(tn;<6`*1I$+#e?8 zt@ES1AA_&fihtQQIO~ZX?{Sn5+fNzQlYgnHsUkBi&TCHUwLU({hYGxs|El79U69);u%q^1t4MuTK$nj!an9fA$L? z>l*sc^=gi*?Cf}a;po?-ffwWZHoC0&t{>ZV-LJd${lNy_Df8O(UMEoUCC5Xzneeq4 za&M*hM>*x-tY6hn(Dhz-VgKa0IeMz~bCvyS0UpV#&Y$k`-5o;r)1@7Z1w`{K*}vD< zdL84Ox+szDpB(RC+*3oYuYvz2G6~1Nu_Y$)zC)O7|LV%F*87To*7I;+KVan5?0OU8 zoCWCio-%izcM>D{m-{}8O!#^T{Hylgu_tsq;yKS7u>VtI-n>>`UENe=!1pcxRR{l7 zxIc}&cUdprBO>pO0cr2xy2_z?xZ?jJ(C=6yaOlBuggfG^xE6$QO{17Y%DxQSH6zc)>)UkLdx4cTjxxOqfTR8y#_y=7vj2!Ubpb> zk?beY&Od7spZ(_Z8NWe(svcYf{S$D#(zphCC(on z&vQX9zeA_VWh$<3Q1@p`eO_t82W1%#RC`|XkNFbJqx)kW!K@$1avZ?tYB^S%{udMaixJjY((fukX*VT*S%`PcBn|YNJ?IZA{`-TkLx8iqjsC}>CyfDD zl+_)s_zwVm&zaCo*<&0eb))vQR61-Q-g1%7T7>%pwWq_oivNCa|EPt3j){ib;?|v} zSqw!p$8hrjGr4U;IBkO2)78UNTGVmw7hwO_xgK$^*%W~JRe#pm=N|w61@D~Kbbi`B zKWUhNcbe2Y73|wM(@R@6QPNr$y?TzS3^*sS+9W-u&-Nf0{Q=IK=}*;k760wQ+YJEU zTi0<5uGiT7L+fq#6rJRq>l;4-&b-tAG|&>LNndRtD($v-t_Uzo_jiOR0d?y^ZTZyq z9_h>E98c+BU?*Tk<938!4PcD#DgXBNurHqf!A1JigUQeX_v}G^d3AnH$;KCXj{(eV zJrVRf^>rQNm+I*`!r4Z1Uh5CQj3(~) znuc>&pqnn*dUt7Ko|!l!G`n;xz%n(!;G^JZm?A zy0j0#9F@H+$v4a79>C1T>*c_){sN%k>m&KdlJ=hC2eUa9od&wJ3y%VOke;8#FT=Rdf<2%t`}OwGn+dR)3JGuR@7&eT=zp5A9&Qu{7BC&vB}_1;K>^Yu~O z{{~nIv*r43P9Owm3g9_8C))+rHvzi=XI?z&T*-CUjgHgelxhxOW;)h9Bap|Ktnq4K5!q< zR_@Q0Yj9H6Q4W&tVz_nH8E0ONem+avvlx5_ivP%Yj#JHb&HPvnYQM?ZplvV^1p1Wy zS9;P9VYFwuju?4z=bAR)V;~>63}Aa)laA9JB6)?4li3kR9B4C=fg-@H zUTj3T>Pyxyr!)Jh30P0T8Dx;}S>Q7bpuCOc@Y?@t{&nfdIxX9X*5G%ntsK~Q_?Ud2MWtxXp;x7MnRxr6BAlSmt<~F2iUqz))6Oc2yW!&E#iFRM5bZ6C3+al1T49k@6T$h? zEfNLNEfzDi!eT2J{!PQV4LE6Gi*mizXkPG_dj-M`)GF}>9O-)FtcB0v_rlo^WdT~H zAKm6#;8yyS`)P#%S~aAkKSW8Cw~OGcp!y zMFE=3smMnw&x2Tsg;pGlqaDgbAkMPjy_P5f#`UK>Ah!0DkEXp-B&Dd872&`L{3;<0 zx>~ustx}f(cr8=@ifwK=T%HqA2;h(i$2k$WS~B?*ofE;lPsdO7BRKw|?Y$CUpKU5| zEATAvA@DuGvHl@|<2c$R_CJpSoL}J>w;1>gconz@mR7$26Lk8`jGybp zrEQ&w>%e}1TwkkKLVxFn*xyid7nFA!pdVzD3-@0D+g!@WjG>P933c{02}j zo&cy5Q9yg-+gMC+f1GMqXXM@=&-VZPon=nmRX?*4=Dh=PJp#A`_ypJwoX8l|U0pE7 z`wMw~2T&g-K@YmYHZ&E<-zwd#MOHQ)pbcmS{9^-ZDJzt%TIW#pob!~d03QLYbEi|z?&Mtw z8rlA^@4$J)7J#x{2I1LsfHr{pAmzRj!|lKCrIh<#U(}u6C^z=qSeB>Sw!0%|cj9m@ zkNwDG*n_jhWb_*|f0we=We)cr8^97#b%gc32XH6wJK#0`l>vx|1zgvQds1tcW&SA`fm)(H(_I?2%Q%@n^?K{(Tfpg@q0i65x_nU4%?~ePy zPg@&c9WqLNpD!%J5AT7Uhj+d%FrY22bzF#RqMeRGk&zc?XJ=h8F*mp4gb6tvbF#BL zW@lw}%*xE{l$nvyDP#QjPUFXo>y(~8wiC_=>4Y71IJ)OmPvM%PQy zUz~JS#+I!uGqzR%n!;Cbf$?8y&BuQ!-(BVVs}6jDYhbK$eKU&BblDr}KTk_-$9v$y5)yU+-rv0$a{UbW9QeY3FL6zLWy4mu#Mi-A>o({> zG0sr?iNLiHyCWkbcH_IH)esR8{xi-Xln4)x{M|BW_|c$2qqLwwBekH&5jG5mt1uv9 zxYjpp7{1r0W2pRg8^7PyH#9-w>gcIjK-wmh@&AM!&~@Pl=)tsRv-h`t24_B|{^0p} zk0+`ymZWSEj6^J<5i=oAybEqT_u*7s23y-7ZfD?PT%QM* zYg1geZ3&zOv;i&xFm^xC7rHW|}8${E2roxCdf9a8lQYoRx#$xwJ;b z`QaV-XaCn^UY*_`t$$d;uGVR9j}{aD?0`AKW+EH)DO-)VocT8M563Fit+yA7`8mUz ztz0niqU#q{{BRI+%rf0 zRAVADLK`sb|Bw7(yMjYM3yX@rAY@RCMe~pM>$-h$;o{u5c< zckOz$*!>$`V@gg5$jr34?ga(&u1|;`BJAIDXZ@Tg>u7V7 zc@VG)VBeyCHlgNupPwQvi->xI^PuMZ=r$s|gl*Sc;2Gc?z&yT5sFHs?<=VRc&p+BR!yY-i+~vM#wn=XR)Vpm!J3yzbPFKo5 zn(_~AaQXA>#38XU+Jbon^89F?A$=lPzI2JUXu*7((;cTV?Hc-8NBzI1dv~#L;R2D7 znb{omoo7`)2~h6#v#QOmDgXR}g6m@jN1MxEFJ+$Nn!A_nb|64K;QFB3bJr&Fr#^5z zl8C*)IAa}hC34HC51kOsc~WEB^CSG+OR7^;r)!Wu&pfJGrY8`l%bzk^v21CBpm5Pb zc|NG%v#M&?f?hrgPBt9-K88UwuaxOKKwON=hf7r6x<*%1E>uQ#K zFB4-4d9L?9xXyLEh96@9y$|4gkA2M)>^J8gVUAU>#wf?C&bq~TeE&eFq)yi%|B#a+ ze|%#?L*Gi9Gi#9GGXm=t1KjMZA`3o{Owex1OXP8a?D?@`V?#W*-b!Df0A&+o?uyW9uPqp;Q|@{MCI1BW z|4xeh>m#R=^-O)`kM9>~`S}Gm^y$^pbNTB9&2u`len%g%WDw-TJxi`+d?MjoXN;+* z{CU=)$93v|=@}{iSkLSKq)Af#H+H-Fs`|^Hdcbj9?g82ajuRdOs zIT8V!ZROs)m#zN$qW=FQe;4Bbe$xf@|Hi92cRVrqQwP#9SEKreoPWL%;GCb7FJ+JO zirkg8Sv>X!GXRwb^Q+@0Smzv+^|b|)@>T^>?Ka;~3qi0rqS z$+JFTc~bryC%WG@Se?8>Isr&pp(D@?Yq={D-3chd%cA zsQE@eF#ad?|<<5Cx_5D7sMLz%-=kCm8 zS)Z`GLbsCr#< z4cMLf?i}Y0$i9h3@{bwT=pXsds`1@I-6q)Tf5XUM*8|lLYy{ay0h@s14KV(vE?`e% zNr0SV(DSOrmGxiA|KER$`X3uxul67He+`TAgzLXi7F-u#KV5yxX*t|Iat%w=sQENKMUbDi*QpxV4J{LVJMHb3_qxV;A?IAV|p ziHV2(4|(WJl|Se0?X(%MJshv7`Tu&?|63Zo{_FCGoA7a^cm(eN_~q?CAM#rS{O+OL zb)DFS=Pm;bsk^?sc+>`QUg}HD`iI3mXD?$9%k|_wXVr!#{kpE%y|H}D|X1#59$FVKf^Incp7YtOA+V&~x- znEbxynKK8#`Z_o|QCnQNMZ0Znxy1bW@8LVFLqVs(Cg?O-==*9GCk;y>=}phU%GTDdp|o^2gN%0G+a%eJx5HQ zm@8(_TX4>tf_cN|&dq<`9X+tg|2A>WSFG#&_Q5_tKkL5&*IxrX2R#blx$j^XBEn>}Yv zsVjRx`7c|#^fviWa>WYBR+qiA%Wp#P?Ej?zzY)qI3pA+Mi++H`<>K(J@HF8Sj=zZaRkKh-OH@28#O3XiMr1D`qeA2wSH#y5)j-Sxb@ zC$*{59z)&Fb=^j}DSurLW-MMI3b7wJf8pYm^A;|O#TwsJko7+3L6uP#DF5ZlmfY5O zY~_WJ=@)>r+|B&_#_Q|Abf7DszISS37Yy>3=RxW8RdXp%HLuHaF`fln?E&N-kR*Wn zjjAP4!-H{0x7ewoamLO|dPa_Yhvj`{0^e}9hDeyU`#RmhA>RfMioL`d>Dl`~cii`| zESmX?3tP^~F9@SOz<%#93JMB72e!`wSGJii0D4~PYP@trLF91xxdShxJih0+1;1?M}7PXe_0Mm?ATKje?~ z#yWm-{wHn}OdVoCI7_#G5Oa#AAs-wcZ-~)H6H!@4%7hH-p`ZrudUzbj=Y`Y%p#2!-(>$LsQufJb<$*vz_~;9&8Dj%^G5)V5mt-r zg9t~zv5udT|7gnpzLQ}8IUiGL0MD1uaTM1&IA=qY8&GWy$6^Vo7-)^qf&jV-k#H4y zg(hp~4SgA9T+VXd0NB4TUq=ztep}UjPx^h%ayIj`KOl9~*7noxdshFAR1e<-Tfd)r z&fvkfAm$6b8^of`u3jI!`{=*l6W63v00+&$nWHL*io)5 z?}I=BaANI%{(N#pGSWH{U&p)B>FY?=sNz#t6@9vy_ef|7SW(FXxepsIQ#rYo3 z&i_(!<{Hlwpbg+@iQ3~^VulGz);w=ZSmZj?HD~#m_?6rTLhe@%o~5-(dQnqnZynHD zjQvRK8Igi#7{{L00oaz&)}}b!+{L_{otWA#R9)$@|nma)@> zHSjE9iHJ_Y*>8MTQp%5WL1q{b9Hm_uGaGV$L2D$>TswgIhW++^Oc%foP&caSfYth$ zH6rR7j4_3EaDp=l?)fQ;L@CQTC_l;;<$Dw`vjz6Bog$^GyGTAR#8^2ha4#>$Vt(kG z!(FcOaw$)voS#SBwy+tYaAB+Dys-0p!Ft&KMvc<#{XW`$$DFS_6jIJP@;xH%_2#(m zJ)pN3XWL`uoJJPjIWfZNz7^-Cpl$|OL&Ni|Az_>PgpDYt2Mp$}LiVvt9KQ|=ykReihw<@y1jH68t< z)_VB+z@h;qVw03ciJZ%jL9}2#P0mE@U61FbZ5+2nR=Uz3j;H-$CjCnPQ zaO7q7O?RWr^=ryG4N$t1EZ2khP54ycN#Hl&2rvu~12)=izvt)w^1K(-2E@YE&!qYm zZGM8t+KaVAgB{>E#MJwz9T2yve6A+9!jh6JqEi#SyT|99=Ra=Si@q5m3JdC1cIg$sby!dQ31>7O?-h}J2=;^he_LAs+Y%CtG z)?v2E$(6|>rSfoxq4#S+!59k!N5a*CF#^Kuu!e(%V2mrQ3RY_c`Xq;dotChOHP(p1 zZ7spUB4m7lg8-R_lq36n&h=N9x3l{h;VPqo>esX>IR~)LupfKKbU8b__Pm%U=bFdL zG}S&P^gZ`q1KfN?-14=Me~Cl>&;x7mcFW+QLoLY@uC*lP^aOh0{K4Lq(OEt?OJ} zuJxETEb<=9i1b#L_(WmJU8KrG)nSewxz6h>XIK70#8q{_da2g%!QSibe*Mq?SMujP zFl1FtCWqm_88)D`9RI1lf*-=}2l(DW4SMVWD$VwYvjfm|sy6o^;&DH_JqbDQFhy(B zC2mnm^e5Ir{ydYxW&yAvP2FRL2-$S4<$#O$LMyykK=jt zGYoa#Q6kl@Y_g~P+2^a@oDWl!^;&+9?=cfuv0gq7T#CBLy3ajDp8&&vYV=g|DEW6s zoP9uTa@X$_!``6pSv^f_Qm%kp1Y~_V>ikCr`PV87PvZrLMQ9-*AzDaquv-X4yc!4z zsS1sbofCwD2+N+Ux7~EPhU==XJBL4nxQ#uKKjmKkx=*38jn9^Sz?HSgiv7Z#0M`k4 z?!-g@{Q>k7oqwDwRPqmnOB^vT{*9C#RUR&9rHTYeV)qJo%n-e zVzk7OBecX3Ht@O@jK)0&M%u1NYQs~;-qQ2N7rkS0?eb?IlkK^)oXz})5iefKzK;5D zsQYa9x!xn^f1E|(mf!I{(WE+L^$qUd18^VN5&&{G%o*vKsrH*XKpWxCJ`?K2GtecR zH)uZ3jJ8!+BM1A#Uf%$Da&Ff+7p!0F^TD;b`aCgReXh77E-tQeEY641FA{waNR$>ps(;zf`g;o>FM|G6k|XKb;smqMSE&R-`W}$aS_^sT*!`l^QPO7 z2X~qcQ{hgrVKUrFz(gDP+yo%UhHSW5I8QQj#E20aPek^77H17UJ$h_Lo8&R$blJ17 z&heUAU3U(vLcAFQYq)jEU$5(M+3wfe=VMZSwFc$b$ADpwmAm%(A;d)=-9%pY^~938 z?1?UWx~}a>t;C<$&6M=Ev1L`m9e$|*%oD-Rf^CGK(VP;50{FH-`{o_ev zGrA^^9Ve2~?DA*7?{_!l{{!US5pnBe$WZrBT=sfys{V7Y=YGH_7gyKMp|1Lx%Ab1$ zRC?TF=IVLp@aggyH};w6BsYXRI(3YgkUEm`9|$>4OG_Oytw+j(n>!}IqA9!zm)NLX zA@Leq;y>Eu0K$$8NLiadAuTK*Gc`dBO&hP*eNX#+cVbS`+s(SqIX<@ea;~=_%0af{ z*(F@}<(_Y6*_in^LjD{J*390~{^z@y7Sqo*O{-?=CohEOF(>1@8Og_@;2uzO!kibb z3&-vgNt(Y%vVC(wwfpCzF1y?BD?{9{y6V2I-s|JN6YKLim!et+>ZZ)zLOg#{ znK|13d2Xh~KEim@w4CWY*?uXzqina=1I}%uY?T&GXliuDqq}bw|kH7dK^Agm~uirwvzg1@6{=%Aa$Jby0cp@2k2?8D0zQ z0$j=5IsARZBY)qKKClkud1%u{knIV8#VEaAH= zG2(LWcA*E)td#F`)Lr*!?~Uc zKCinePuhgz0OxYd?1OXIlgI<(2FTy!XOO-9eGY~-_|I;yJ({n*L!LcjX8#@Ie+%UQ zhnxEJ4A!B1UCsYBIM41RsM-M9fH>fwn=*Blu`55v2BQF`UxOMa**AQD&zPgK{j>qO zZpw=G0P}TRGpe~>Ba>EXdeWc3+Ozv-%^1l)sn<$A?9V?4xRPak!uf9Jxpl~%Z9VP& z$!YWTf@2+4`+BhF#x2`V`BPV5uWOb6g^07w%`|^Rybdx=ovt&*RXV_S`sW7JfdaWF z(8=~Y)%%mv*LN;gDMy|YQTnKxvf}%qY}=hva`;vKZ-F>(yP0Oq{U46hPVbfK2Y5sF zD;r4uyOGXSKn=cZ^5@)MbKvCk_ndQ8vN{WL!Wz6=^`Bz|juo6!a`c@;AWZ} zCuGPpYfIOW!>PSeHh_Drw>E$d$bGxUexFmlZvww;^G^wrO8%VtarbPH?-2K5DJxe5 zI{K9E&H=McxlNr

Wu<%I{={EBUjpHW~0_Jm}mv;JFUbfW6=6BzxBTQzv_l-<160 z;g$oGLtVh!UrBS*vA-^d0=b`vX?rpTd>8Rs0(vTEmaAme2C^#xoaO4S|1CTlAmwl4 z&L)4_dix$;hMkfh`)^rtUmyDOb;@1Wi#x>pdtCSZbi!2|&;{wbyQYM>N4W;6r*LMu z><6ehq2Z7p>#@5s*W+<+V3L$Qbjc=nx+iaLr>+uIGHMDLz2<@Za}c+#ly$p;J$>>_ zQeAgybI}JV$y94cCi@EO&hg~OP&S|`WcX-3v^$zGq+J$duGb(M&+{j8(z zuKOK8+4pI5Gnms4?H$)9caK)~HK9=-mr!5$AU(M8Ii z_MY|rE*FPa{C!p36H|T(D z<20N_3_HO2Vt3bqOAt3m=3}UTYDTbJ7jT^@*p& zeE~}TW8k`+2f}-~ngL6=$HQkVo;?$O_PM!|Q7B*ioo}O@&8}(tZS%A4+hu9z#_ki1 zCYLsb4R}a?leG5l66<+WSFY0KZ_p>b-ITUP57&!T_rqoTqxY@#XY^?Gchy<|$A8be zs{5$#npc{VKjQFxPVObFf1VBfq-ytZu1_i2S-0yx=X@{K<>3)YdS6bx4|c?ZJXgYI zu>YWsm+9)VtV{m9PZ*!^i0m4XRlR5Z?++NyZLY2F|1jdZ^*(2f{7y!I>W{N;9S0op zKo)n34EN3fGbLN;0LP8)t})RLaLjNGAjH52O_M#PfwcVz(*EBFnbszA{T{~#>V3{r zN@y*ask+ZOxt9Rl*4E{gp)VdT`{V34)aU200W*j(tImWPi0j`FipU>vvMc zC6L)@xZKZA*$oCFfM9_2o@2i4fG*?O-1iXgY`_yLPF`HcH-b`8{+`%j>I&9-POvYg zbbxIL&X;jp_c#^^m-6Q~&rjx0+4nTai~Tx+d$d@G{{;As2jA1-J}}PX*Cuz~;~u~n za*qe?#+mR_<$n>%^S>UHKi3440Ci5piSWU;X9kd6y3~XGX`5cfm_waGaw7TH^{hkw z?#Q<;`Tq#{cLeIn_0-&#vM=#QSuO)SvA;#I`>h*nE=K7f=MdPRtgGG8?{n^W2KE}G zFX;Z*!{dTg^5+>_4I%$KG3N8Z`D`AO(cllLGH1OD1%C6O+*$Y20X*A40 z4pj8CN4lSTNY8&j&-w1mKh=x2hLitB=uq=B!uIoQm#h-5@!Sk}Qr|c>f)gc>^aIUqdm$3+}(3TedYY|8t{WN=^Dr$8A(*~Plnw1E?-^kyQ}+rpEFa+-f3^I zF{@K@P1%i?dwXcZ-F**3w+sKqGu#()a!6G+pcT^hWE@J`{sbn7%oCW4aK(|5KhNtq z5&3g}XrPq8t9(vHxO@j!?!mL7yov!`uI{+I5x+NpI*Ph_GJfg!o{-W3uJgFNKTM|` z`@~9z$bD<m1mHPtNew>P5KIxTo_k~+r51K#2Gd<-Q=4aww zfm2b2%wrmDKFhI`^Lv!NCw+a|h6-T1$i;eFL$;~z@Xxkt$X3#x0eG?|rQ0;xfgq8^ zF~up;TX*<6RdF0PpZn}y0X&sG%kcr=^u2pQom1zDtp*(&=jpO_*JXcT2;`6c#NS8< zq`jA8yq@5HQ$5O!<+~YWcFAckH%DLKnR@cUxy=dCBmYxw!%kIQH|9gx%e}bN`_gaf zS!O>#?gQmFzcNqrI~VCVhm>|e?H7Kpp8RlrU^T`+=fh=M#uEGgah>_ADyJN2uV;bB zy@0!R(im?aWIs}5^4yh^G|u<5#O3#?sn;d6XJ6HmFODTKSIqZR{-3o6x=v@8b^(8n z0G`aB8fDMEy;A4?8gN57yma;5)!bwg4cyeDXUf^|kjbzr#QQzLRM;#tlugrU5Bfm6$eF*mvAdJp7Y8VJk<*k@fK$8CAF$bsXdOulm?=VTv)`xjv3 z(UWUFi}^OJp`6aLFqVs}YwBj6Tq}+M%_m|9SUza$N^b{H-&~wq?uw2R4VN~1KjnTg z!1kK$nm*roy_ElS6Zy;M`0Y*k{?v7F-F;8Tl|HcEL-z7}e<#Y-sd=7dFdoRpyi|7S z7l13?+zl^A8rK7y8$Y>iAM1OjT<739NYeq%Q|NNn>8&Y$DR-%(mm&TFU^`HsF}3qbn^y8ah`92aJyj8vcL z3Gi_Y(D^$Nm-|a!K)M-lS>Nyt8ss&p9_7S#TCHndfOIASTzjjF&J~EG_X$#Q{Uopl zIMMp9mkDi09Qyg*|MPPqw5Q58o(-4vgEmd)^F&?B33DN(4+G<&4_5dJ`PP){ex4=U$kwV)7{D1jL9pLxM<-5o` z8nDdta;44P3QU3gvG3hQ*^v&)UY&=K4fjL9UAgOdoeY=#yt_bmJ83f~*Ta^b>AJ$Q z&yjuO?%);nyFtpGHeefY6VMO#vYFif;w*pWoyC4#NgKptyYT^VCdi$-v=hh#ZRpdu z(AzUzw(io$IT5wy*%~~fZ(GXwp8C|MKk(d}0Bm?JYdPwpyyiXEcz35v{^N|``-AkGlc3y-~0w0jhs# zQf?W)K<p z(R|0L5^yeO%I#xd9?I)V`@4l^^_}Z1*|NT)A6S|KybYX5axVovXy;2iqkqRS#NSQo zHTh*fSK8>(wkVI80Q+(5&ruIPfy@)puAd9IE-$V_PLT5rt?Kqc1cSaPpu)k z)0UhnJ@^xJy#gcvv~z6t{$6tRlv|dM(u0doRv6F8_YD?8#^=@8H>&m?uuMAxF9K&u zpPqJ}{hA>_3y}$){y&cCJe92{@i|V%IYcNw_TdHt!=M9a$$90@?>SPUEzQN=ZLS%s zHXm~+r=`uO?r|)-3g{1DJO{a->^=F8lKB65rQ1xdee=Dzsp!}D`lKeW{H}c_`T%_I zT+K6`iatO4s~nTCu8)O&wnsn32dGKkKOv{41SX*D<@wkpoO4bG8hXsn@x*rE-vHNW z(3h8MK(s-phR1($sk;Omc7t<2SRde?*#_w!+>d(R7Iwy0Ou<>8LyGFA<)0X*uLL-! z%DJG1oAc+sj(_U<>62*va%P*HF6D-Cgk1CEoKjtDy=LRYn)^TMN6|k|osJUVctMRT z&WHRb0hnX*NDuyz|LKrhL+42wKKU@m3!Hc4Ji}*h>cKzqZ)jPZ&h)4Ua_(5ZgF78M z@C9JD4xzUN|H%Jz%Ijq1O+8TG!R5Ro*CDfb@w0npDY=i3F%S?CUDPx$;FWU z9Kg69MIHD@{%3-mPBsm4j3?J<+e7ADkNO(;NB$?f+|RW1x$c;`k895zfm?vtay`fF z{f{$^b{F*E`wsY(^IXR&tGwpFLc|W#?EXqV?4t$p7JoRZ0l&o?qzC^Br9V*jS4pq% z+hV(q)cNz${pxWc;&I=0Pe$;AU%$ryXTJ~b7t5IHpO?dLm3i9zURrr$#94gM7T-%N z_A3&?y36h_^g~VoOLTvg@IwlX5l>)lE-ds>T|JpQWvBaPor? zNk8bJs)GD#evt3*7YZMcs}+)8xM08sR#3iJ!#`)gOqKVjd$=$CMbaN=@T)v{jImwp5<#>3@EUNX(f1Aj4f0xorl%oHMAGKFx) z6L?%@T*L$_1^R6XR&->5TIY+il{=VzfSKsN~`QhmA&+%!|>+^2Cwsu>V(eC@79+tSB4r=&Mu*)44O`$ZiKKVEWP?(#dQ zjeLE@+O<(HU)bu}gV8T}eg1pjb}g^+UG05a(Y7alc;&xwokXa2hc6oY-yiGM(%a(O zuEi&xEIhR6`-s!DxoB8c3F~H~1Cik|S9KZcw$BP~i>%uP^C5j)M zd{f$I1AMlxF6+1MrR9AVEnOS`o>zFnD<8}`+T;0)toQDYpMg}DB)#2k;Ie&vCwI*2 z^2(tDv86la`i$#+|HNTe286C$^YgFeEuZ_aP2Bt0yS{C*a^&k%e0z4js{4(1P1x;o zf3wf;eDcX3p89XZ#;Ot*t z{(9=p_bxj}>|VEH<$;yYiM~zlS&`GH{g~2M?zqAGqN0?hYrJ2*>5p@Uev?s_{LE8x z4qegm0r6NX-$@4!-}k__Rkt1gs?9fD`rNs&U(2}OAK!V&y_dcFTG9UCm%jV$f>!Id z=f3;H=Dam$?}}*G`+*4`xA}VNcjeG1ueC9^^?U!UIX-h5ReksUrWX%3e&I-3+P}o; z7u&ti_=eX%Iq#lC?W**^`=9ylx1{1S}b_X zoHpw9+?QiIiOo?DwpiD4*5@mCiIRUE>%M(Nl8EoT;M>gCQkKu!7w|#e&A+s7AGvPD zjF+fA;QPZ~Xkpk{NeB{mrW(ZCAe2?)iR4w)nPe)b@#mK@;!2y4X_uXwxJ4Z%)3s zXPasB?{2=_`~IjId;4y$nETexU$>roapk-F$}MHTy!64dzg?C2RmwH*^zL(X>vcC3 zHV?fhC3wS-;^579ZHn);ePx?Q+b-A@zxvAyC;C9?&Ut5Zd|2-xThIC{{5Ai+x9+;~ z$4;M5y*($Qe3k#)-DT$vZhKyG)w7jL#Pyqh4JhdkKgUjNLm zV&}Gt^Bt9N-?TTqMm>3Wy7sjH;!8G9Y`*uV$j=*luU_K&#J$B)8#WY$A8!8VvgTz2 z%NDNqvD2)+-dz(%zMgc)<>v^W4-59cf6?{JhFVs=TyiXT_5t6jraQcMWZ#~cJ!Z(3 zV~=jSv(H_x?hd#!baU7vJ-ct2ee^-ExgEFqM?TnW<3+pX`^Vp(dBxgRuy?E9d%rmR zorgy^N-ga5M_2!{TN>y4ZH(V_?xh32{QRS%BhLHokM-AX`FD$ib}OEq(eL<{?8*qg zQU7|iFtAHy{@$LWrhX@0-2B|E0XzMDh3~}+uFH6?WgoxcuYLAl(G|s=i;ono&)qa& z`t_4%-hJoZksph^hg#nBUSzZTd`bqF{_6Kw@8}itgML}O!$07O+or59eq~8?SJC=B zpO&F_Mr<#rS}|hV_gDM8@%TqmF4-}$IB9OvdwP!C`Q73FR2F29{@p)ke8w$vI&Ag7 zE_|2Ik}F$1GwrS00)G6D|0@+kUruS$eC;Ul^EZbd+TO3~N3ZJ>21NFFKl05W?@F(Y z);$M9wsyW|Z`YiwX02Kk-#21%&v9LInm=(xbn(;`&lYsPIHKE&&ptb6ZDr2?0eL`% zztRbSL>qVp9HCW&3$cFoTa>%s0O|#{=#+%75YTpab4SSS}n- z9bil(K8@`!e;OsoL1xVY?swGW(x|CNM30G29b1dhNOVfO&$Qu|YojYj!j z5&o|}&e}KLggtJrc9X`&gcSfQKV<`E8tXY2_zG}1wL8l6sPzuKSKxl&IfQjoSf@0*mmci0J!R8_Wx;I3i5N7BBfIa1>S;Ot0SAk4i7_YomO{@pxSuVCMI$ z-K5f)kOCla38)Yu!-*n%1-s^5Yk1gE@Il~K6&~qMvnm=PTWrd(N|Boy#IZ|;OR<7r zE6NiD?*qpJ&(nxq>#(>8Eyl372%ix67_gAqS)wh(!wT$wWCl;uIsS4DOeg`6_%t?i zhA;)?lfV~&dDU*$0FuDV!0o{A5dMmgto3NLf_w;3?C87{8x~zkbYvl$34p@-fQdH9 zqyQlniL#vtOR(C)-oVsqUyC7l3gO>~aW`4K@sz53VhMmY@Uk?y5&jmtzTaH!HWko| zO=tZp;4Wi$Ta}FKj;|%9L>qP@rNmM8L|KYWep+hW#IOQjv*RrXwZ%{7U~L6w0fzz8 zs(md6@H+4%WB7&R;Ek7iI$;FBTAM$wRfK;MxR}~Wj?sk;1O5rZ-Cl+@;-KT*dc5XB zsH=xehPYUb;5=;l^LZ3EH7H5|%K)3R7sSPN;hdw_?58&Lj86KiRQmI)YPw)#R)Lp&N~KM~HxCMTKC z$j?_v0w7P~zd+vr6Qj|!2E%i(e`_UU@;cyhqg*3GSEW{N#>%)C00o`@Yrtt#-&m9d zo&|mc{GKeUaL|@hqzl3A{A*D(ov(5TC&CJ{MyW0C^HCuwp*RbnFVxirn8? z(EK(5-@xI!DBZQ}Ff?ujz?$U{cfeB?0soD)OjmQ6&j4=%*8w--@-B+0b>p7jymcOI zIRiFyQ|CDBn@eTBguyu!%Mt*2Rxg7@7UslhQRM`IHf&n7YDYSD0^iELI-oXfJ>yaU z6j-FU#diKrP+jMd4Z!b!t1=m$j<|SXIqSaa#SJ1Hh*i~(rC%fPMF8aa@Epi=!j#!8 z65)Jo{>DXA_ZjcN#t(cO=&VHn;DUI7s@Q7NYpJ(PZ z@RvW*Gj%5Ss`6QEr~E0oLLGjx#SPFn47lt!=Um^#fF;yO;%}GyS$1m z8HRDC0jyaLQ30i|^PffagxE^pC)gCz??P>=c(p>J&8FLNJnEwn4iTG&;VR$_FAB4K zNRC=~EC7UQz^N#o0d}K$&q@dI-w59m=zi@rIPktIwPXO}N&w_;>>S|#VU0}HF!*JF zhk$RO+>4M3JAP^O)lyWljzhL%9W4Bf|HoN<0jT1{V(bQd4mgGCITCFEz64wiwe!r3 z8v(HTB2Z;|)a5@#Xrnqto&<0`@P9oXZ^xXm$Kr=nh5~!hbnGh8-(q79s=*oqU+C`T zhIj-sw+0f6j0*vs*e@@6g(J-3{5C^~(W85cU<}i`aUO z)rbsz7x+9be?al7{T$W204NAVS%FodW>mNdX@x(ae66ROzqk?1yq{G2s)US%J~w8= zT%Zl*5^Qb9O7jwMSw^{kx&w7p^b@FQ0kCcvq>@N|151Jbq4J45HYr?flyCQDS=|^7 z4Sf@VTzo;D2%iA{gDOl36dpFv=4E*)R#&|!!kQHTiHjk<3Zk?5s93|vHWhBd>k3~J zho1wz)mGI){AKNONQ2Y~2MGKdHm;zeMrDQHddg>1`Cv|!mX2#u03l~={NUo6b+2%T!aTORPVU(|8Ge&<q$~Ld)fqIcUvj0BbLTSOg-5gHis8%60xO;C~VR4OpEGJO89*=GEXh zWQ=eV!e@aOD|q<*Q2tdN=K3EgF+4S)0TlT7Z;7?|A5)=2cLCorR@-PF4;frSf+trf zMez72Hk^0&3LQEPTn>B{NLOOXxh6CK0n$ob;WA)xg$~;dd=KH9j)a{*q@R|n01w5M zVf%Zm7icAjVe=UrMG6v^27kb+3xLF>;7&!N4xbRXfXXEG$R}&~I!Z_A+!Hd8ma73l zBT?>An_%|Y3LSbb@Xyq-BOWBq5B6YHodP6QU<+ZxuD}n0{VQ|9z8ckK<#OookXaFq1invYyaqjlYt-Q% z1v-LEGhS5zu+An(XmW&a0T&XyMv}os^L-ImU#la3YAIlooO~Bpj`dIQgJJ}UgYpix zHsJFp#BZwh6{#+Xi$Oue@Cj^opM@1TY&*i=(8Et@grI~#)usT6OJRBkh{H)#Cb35r z_yxk3klOA1fbFIRuyevF);rCQSA7w$IKuV_OAu;cl30COt^_eCa0~Fy*mPz=GY#eQ zG_Vr}66XbTkm}uD4?3o?lh|x6jTJcJUBJI%_^{$p1!F<0s+|cVXY`$PDd!5p9}0${@mP{R~#F1@`faL8wXe<#b^)I-ZZRO75mK**ayt0@F_ z$5!IWPe~>{EmuP}OUCo~v08gTGT=ixz?lliHeUs+E(qoT6=nS;fCnOc99v&5XsiDl z3Sa!?)jaJ1E#Is38IOVfDL^#^Kof8RhNfIwLV)NLP={Vm`8L*`lnwZhGX*}IXk+VW z0I6>)E&#-Uv4K995_~n6jlh44!`)}BfLY@&u&3INT8AR+h6|}Pt9>bIgO=|@Gzt-A z1Mqd=?g||C01?g=7bjP;-8U*K0CL%VoLu>+priaU3fCCJ&(*`L#pS+XsU73ne1zli zaBHMJH9^Z2paSCZHo}*&8GeGq16JP|A2HaK|LU#;y6-4}nv z35L@Eu1gZ(3gGsD57z=*L>;sJx)&AG090whs{UI9co+}3PT<$Gn$dBay;t$i_s<{p zN7yga0tVCaJ?Kq>>#`c*zX(2r_;8dH;!d9@ZCL~^01{sSvLM1o2|mpCLE!%clHPb9 zt?Zqt1q}e86*z$maWd6zO6@WKC*XOYF3$kp!Dbo@iaOv^$t(-}csPRB06IV;%mgkX z*qr_!0{;_tcv}T#jbFo`?e^05t`-nrF%h<_Y612drsXOiiz?iVeFf<~v9Abc;NXM--5~u)(Mxncl7HqK3^q`KT@PsN?p`-%$%c>N$x9%QAIGLri zR;48CIAGzAa>M?i{1xje+#TTIb_b5@Od;hM1Ot1_5|@!5#f~KBQyvf-fbTR#csFC9 z<%atLbcGw%?;F@by4bgHH=!2ljZ-83^JX8!=I;D;UP8rj(;KrFO5Me5| zjQ6yFj-tTtjK>}AX{c6pl|atQO7&XnYK_22WT{V`QSGMGF1=}pMc9bd0^SVpP{P&gbdAs>mi*5Yao z+w4A3o-_s~R8mjdy$vo8VmoyTB?DxT++QVwkj`C)!dJTB?`+^-@wWo*d~77=)2XF+ z@t;@wV$~)yuYp7x8I+$OEFrjbcY6aL#qhJl#Ws0KDflh`5*K0>SL^ft(SS}G;5mh# zk-?jA6@2WNok6(<;aU_Wh2jFy+yo(o&E6LWR-xPn%!T+WyNlFPK&b}~Lpa^X)Bq(Y*nbVc?lFqZC=*l= zNfP+6#CUfiI;O;b+4r`zvs+d0UICY048H-60~&m6Vm?{OPf|-E)B=WP?)81%dcSvs zlYx&1bf`m&vX3L&Go!>6nm}gGs%!-u8`S=RhY@~Dn#$D=8gCf#t|$-V|C)3Ia1w^b zFj>gR7@*E&4e%pueu^NNEyAe^F{eahfUg~N?Wb&EKe403jscx)C-76&uo8imuLg9K zaZW)x?+<}H@ISiX5FGZbL4SpsV)iwVwnFk=;QpYFBXAV3wJY%ak;VVc*C~J-1Cyo+ z;RJ$<_kRMolUYN1{H5>db2!XDn)xwGa_1YN-*QfD@q?otFt<-9cTOhv`@;Q7{{O}7 zuVN@5c)%ZlPvLJm>si3bz+n}v7NC% z)V23<@EIZcqA#A~lRW+U0zlKPii4|GO={Q^mOeuLMj#xq9h#k(nz9%dR{2dSR z0}kBGco{MTxxk$>fNQZySN&$K!a0s`Pu3I{5Lfo_oL9ML{^Q9}F}fAVVHg#%o_$#S z>-=fpm+8!Aw(gKoi2s7T-tuSQg)!|U-|4-Ap~Y%@b-;-nLTf-CB@+tI1J7_j@K`{H zXcag*V~7^p?Zzws()S$NKR0$H>UH!)=}GO4s;!;oe?0z6z@70JbaeTDuCsecEVFVNPXMjH%!`sHdqR`+}8rt{o9l*Q3?b9egGZE($wwqn2KlMoeDafer z@y*=pVD0nZDfen{nS^)1RurP+v!icZv;Y{QH1dek1t+qgU{ADavSWnx`LQb^ETaUhbec1-3KR&-uLj2&%{GFP@k!M;w{N4iGLm zArK0J0a#)DSH`+DJ38Aq4to}}0zcv=1uB1>ey5=rgexGR-nrB_>Nvd1sy1J)cY`Vx^P^o4dNk>mZv&fc*%@ z`kzp^uP%$hlQ~Ai;SC zZm+Q2XsdxEcB`D4Z(@rd^fpuZ3wPi!4cK?IeT|V9)$qK*233TVfekEnfzyG50y@e( z;CRwF`tv99pXDsk$(nw z$Z=UKHRokNzUZswBkYKs1k?q1xFtkcfbLGQO{h&Z|%t9`g zk?jJLc1qClJ@TpFRuPEI^YD7G#4JJKpV&>Gc^>{K$?s~AZtJzvTAb$1W`j^D{{v94WAx*gE2o0 zx!|xy0vb^SotX&|+By=2_eXR|a z73-G~M1IBT!0srRVUo*@y?;4?!z^IC02-cBcsSzVO{i?Y6()5CHYc;q;(L4r4?P<= z0YiMKCv1Q*IWGhzr>wXAXcgkSb5?%u`*imbNhOEhpkxx4k@qd%9+(qA!&d^&)Lx2> z@k8o#?A=W;7h9OM(w3B?5Vjuf%K>(QZmb}X^gV}8D&wGf5Vbj8W`MEEd(kmAXMgYEJTrx09_)<|pz9E}U9vxnZGz%G!#(=G+t zz@!iY4rJ`vKMSl2;0W^_VeW7%0b>&Y)^rmEb`7Ax3OuJu81+9!Qs-d1(k8aU&i#X2 z_8SftI0=u|5;Qpv`*bzrem~)bfHRf+G~jLEod6CoRbl&Kk6*@)r@`OkHwIF(#Z ziis!$Jeyr@4R#6KZ>BNKbiH%|;D9>RQQ{3Pl5U09RBd_Xkm5<533MaCsZ?j#Z+L{= za5xMZeo1fy6dNs~wx%qz+!59F$B$%a; ziH{33unjigCy3N+|O2l48tM7J~$&U2@Yg{O(2OC1{2S1IA5?%c#r<2 zP`_}1c`+EY5Kz*E%tUha|Ey7FdH|QqC~8_xer!`{U`f%C{E+^9k3ARLcJY%Bu4 zKnUc6h$hs^K+6?JToX zHkSQ{Lx7`jSco(FlHgDj7zPd209_9gDA%A}!d*o$0-yy$!@!l8k_3Q~O9E;&0RP=f zg%38kF!!qRcQqL(=tLg_PN{Z#ieN`zF;noPbX;Bt1XYHh{j`?5qY4lQPNbXWvD$eG41*c0k3gTp_=L~`?EHU?-#b;9 zu1b@ZqX8I&R0P4UHT$iodnl_z17LBa&H|nUY@Gkcs@ zA>szq3O3)Jfdr;HLgT=wz>=o`WN{T{1aR)%3L660@5DraeOU;sAedV7ke`+M%XE}e zF~rM>QWy|Gq)dR70Z$>3BBQ~01I8F4bzjLB&9Ms>K|F9>LKp&E45_7n;2@lh&B+)9 z9&jJu&w9+Wby6bghu4_0-K!1ygr>I%$^qXG&1FC6M%y(tHMSW*Kc4vqvP z0D1_fOwxoRbqsd&x7C==r@v&I-@F0*8*qC7`(6kfLkg$d95@3sfhg6Dek>0m-|ai` zKPu4mlxYJ$EX@XBtC_eOi~#7>Pymch3!pUQmi@LbcXz{(0j@=O1mza|pPEI1F0tyq2j?3wQQEO<&8aJ~(@7{5wObx)X{>qL7kOmy+6^GvOdFv`e>NN7>+abWo z1oxmn2;7JQ!jr%=0UTpbgoAS0Oj!)@7R;BhA9qs$Rr03wE&>n$Luu}%JwOhK)0el+ zZ<0Vd%mX+A5g^TUlobS1j0Ipl@B`djRGPy^l;7k31KETXVhuhk?RhW3zB~fs2JMrD z-S|HRfFZm@OI`&~?JMo%HyI2X3V@+WolU-|)^P~O1aue$ehu7-2l1biA5-ta+64UO z2!g3AkdigsW5IyKI&aw%`>H!0e1k@L_OaTya!L?I>U^IYG01Qda z<<|wy!aC9fK?b;nG|!^B(Laxn0&c@j5Bx-cV~MjUfVGT#9m2jEgtd;>3*z*(J&3+A z=qi_XVQiBE(*Qh0y-);fMuETot^`}z_W|HW;+XhN{U64EPX4|>0sJL^2`fo#9tm9L%XH{}TcW5Ad|yu$!oSFEo=$RL7F@x30n5*Z;KRUPY5 zZpVLPU;}VGS!VcUvKvrvBwu>0=ASIn-#z<^rUp&P!9b2+2u?cH{7tGP=`+aRp@XsN ze-PKl8vYD-Vg{)Gc?7#gBium{o`LrK_5ny8>HEGt>{P&|#tV?fr&6e82XU_l_1m#z z1rAC*i5f*rI0fh@0*+xi*57|_Ku391lq(RrV#7Rg@f-Tyz6ty(fHt%Op8z5OoMrxr zYNjB6KrNEV*c9PL0~-tn`CXP~da+FkYO$_foWR^#YnJoRJu81PV~W$NL?R%npy%P} z7tCEt=CbLSk#cJH>x(1Z79Hw|$|Q;Y>e|R5uYdWyJ2+#(dB9IcYHk*|1vnG`1Hz8R zCNz1?uN}q~KbY_A2J2jt4;nJ*dk!5~rMUVSD*)7{cMHPKHYn9tNgYn@>_031&jSJK zMXFN6u2xux^}TNejDW_-y1$h@cb-abbH4LRK_@Tl(D~2%KO5ZPH`_*)G;Z%ZPV-J3 z)Ln4if~B|Cky&}}c}ugi-+P>IJ}_)@+9z|bqkTUAt$}0NmDf_IL;P3%>@+6?6zgVQ zk2Rw9_}q41h{nM+AWnbcQ(qBM1ILJx1b}B1h^#B5#D4{)9ur8KvGKw*tYggl{09by zcVy;}<9fN5-|kbJ1WrQraL^+KuAkMAe00G%~RKPHSo#v1|;sYHg&~11qERY z+za6#B4bY$G86-{2<5|uYtG;-YU^%b6P)-h01Vc}cr!}V0IaXFafO}$uHIC{9|3Uo zNr!XepW)<#Xln0acGe?C{{*?PyAAbzxbKJhZn*D9`(5APx87NaF~-c9-7-5~*AS`B zV=0IbQ=DCUvylr0-k8DB-3#EA-J1*IM6eE z5}U%T@Wv1K7Y08d#r%J?zr(!;P{(n!v$Llq8mph`RMineP<3{4#9Z2wj=cAeN4@gg zQ|~nobw|=zW8hL49AjQ4N1*J8@N_^YnLnR8AeFx7Py^J)R6sy8AaSPSzW~S=SJ{lx zR{;bM6G+iT8g;9l&O*fT zRQBjfxd;C7#aS;IbvCmc$A8}EvG)YRUjV;X?zciXmJ@h7mGRFQH~@ovCLDqp%*KRg zAQi)@hvoo=0T0+T@Waxg0TqnhQ4qQNTu+%FDdWt~J?U`L8AxWB(VOO!tYIAu>ccx(b zxwyS)K4J`?QVk?|X@Jzs)YOf-x?f{Fz0a$O8FZxv$fdlOy|n|p6~OU#MmPc>b#7qi z*h~MaKutIYLDJj0=kvx+gQ z9?9NLdQ#=dEWi9S(s4d$j`PmUx;KaopSiOaxD_}Z|J2qzhX8v4_ovRbLdP!(gg_Si zoYYYZ8L92Po6gv;Wjk;c!nYk|wXp&^i4~}uD0daWXkTftwODT|zXd?6Dzn5^NG+QA zwkA$AYxtNdON|DWCqGcs7)%gR7Gt0{rEeuV^p$xtgyt!OrzQnUf=>X?0w49c33GuZ z2oDoXdMvO4po4z*imJ}RavH!akug2LD-B#O!u6tbt38{ya_83oY>*)go~1bgN#7Mp z5Y$qjuvIBPIP~ztImpV(omIKeXlcK%1#+p@YQ_TKI+|{bvszVpn;YQ^-yTsdUW?TN z%1rP*2mzL$EDYit3sn6iRuEJ*XF%eTzNEWbFhu_TQFsCPtP|mCap-Qj+78y(QhTd& z+kEILnSsG}C20W7SHpU1pz9R760peU>rf}KFcN{cPKT{WSOQwJ3_K+=+kL=2_Km}) zWR0Az%E656L#+`<+oKWI)1N`sy3N~nc{lm|`#yzQbK12Q{-*zXq42wbZu+_C9tM9e z0#1Wur$t;MDXEQxfLMez)28tF*0V`(7-2G2uq1dV!eziVJ~w42U@^k$eoq4m$lC(k z+~4ZS;a;GDMJVwie_<5vSNPYc!{eTZX~`AV^$ZBCbsavymX2SU60!q#T(S|**r&W( zB#`n&5nxd|MYL(!&}v`eQozO06kA8&)c3r|x{M*M%DFmr8#*_nlkN zL6w{VbGQ!4c!UQc4iEq0A+pDgR(Hrs#W%4l0)7jC2=ED%8b}xq4uv4g&jSeO`AR1syR(!Qax|L)3 zZ4qqaxHK`q*C25z@FO707Gya^;9P~h-cB{$?iq<|K@iPQh>(mr+@10G{*t|TdtFCg z$L>F`{!VRGsKW2HUppA&)uWq@{`q|k+(!D|0~=#gbm<3=&7Pg=IL*b>zri&A$ee&K zY0)Gj4)?}fu4#<(-oZPthbxYf`Y|wL@$r!!*Cp&zum~xm)6E2-(B$d z#@1*uEi!TlZ+=*GM5%K;BBN&$X%$!?@Y>3gK!xe593^l8a2PgbfUF9C>2BtkuI9On zGI4f<58@GSp4z~Zj-Y=HN_Q!ev~~4Zh!tjy`Rf#O3~|R42!Mj<{t+(PP+u7pZ-{N| zR7XHW4N8ZB_Nc?^hB$XeTz(Ue@e-=pjh*n@yNb*NZq>~-c-(=#M}GUUAAzs~@LcLN zh~GT&#;GOP$)F(uY)OVAfnyO`P%cJzCBJRKG$2jEYC|Qb0f|enW=LxQA4v^-PT?!K z+~O#i8CMR!VapHf;EC=0FQ6ob+HO<-LXE#nGKRz@YR*O&fF^A z6?F@fOyr)|LMvJR|4nhjUJVJhj&?93k|yp9yWTYo*ve#y*UjPxlna2PC{Qg8url4i zL+!0>%0``$dcQz##NkfhreFMlj!&HiuRmYC(LZ$tkj5p(dBDE;&u2)ApL zFp2;;;h4i&-vRY87G^yzOJ-$pGNaoYCB9K(Y{(Wr-HY@n&v#B`QM`+NrfguJ#st&d z46Y2)2%^9V65()Q2{uE{W^BsF`QxT}yx2Q^=tNfqxDGG64nLXE$ot111J~bNz0Tiv z#g#pQ^Tb|5Sel7s7^ceSZEwBH_^GjOp$uINDz>VTjketq9A3{YhY(xx||?2ND&Sd6uNPak4GA4m8ZW=O{$ z#omDk&|4`jz_Z27Vy;d7KG0B~1a1btQg3)Y>%y$7ircSRQP~CDB~f~YTJ#@L07PA7 zehaZTR?Bf2k8@O+8m&GM-{jFaosC{9=XW@SZ>AkSVz+b19lCS;a0t>L&iH-&K2j(&IbG;AB zE(nhgc?SJjKt*`|qc#(eD$NW|`@RXd0{D(7Ym;%9^MA$f`&FA@FAaPEaLD%tZ!@9* zXlek*VQa_H<4jg&mV2^!SF4TL7!P#J;+gJdUTB!kZVemRvA%z#0H~yZ^Hh)S`kC}pz>Ts;JJcuZ?`%rH5Vt9koKL$&m7N9(a z@D%=s2~WXZw>z-~Mfb&FN$xn?LeXpIa}Yj8FHfY-MB~4(9~Mjlx+zE-7W8%7BDd%# z!UF76CC`Vz<(_h#BXrL!M&%#CP#u0CBMN}-B&0IztjZqv{J>__A(4&oNM|e0bLERAtrQG6OqD z4r0A;9k#0PDw3lc$^ygbDqJN(F;0SYoOR#hNazed#$6iMZ ziWMTmX~6l#mEhw8GC+n_l-+@w5H53id5j1ebmxa4QV*AjL0F%Sv!N@-%e~Whvc8j@ z8rpd^IhB>EQG0XN5&q;lTy@b=B<_C!zWbBvj{cdYHjj#Di)rjz_6`Tr3tWrv5)!DV zTybQ9IK3Ed!-fe@uX2lqLa@<`vl-ygnzIGu7v>@a=oHkq{%;MJzcb2pF07mJ)3SD3 z5;Z3PAa8vUI=m>)c1`D%-X_w$;5x5`tB~|cV8;ba^`qb)2f#hSmcp0U;c?`zBawtXsR4q0|01t;Q&ndPM4MzC{kk{FCn3oyhyHd6paXSaq z!w)+`zrJC|k8B<7+NrRF*T8T=Wa#gj+$?*>Hqq*)aAnYQxEA<6)?!@!(Lav^WLS&K zEm&h<&E(xHU<$B=G`Hanxn^RpMob6rf-nZQT+#P-Q?b8U-Hn!@V<|hkIuZdm6IYo6X&T8zjr#b(=V{VJ-W_ zHxQT2miBMPM&Z>?=f`^3<+Omiu|~VC%i3X32!{}55yGoOe4C#FWT_GDDzOYOxW-{0 zgii_lZsQ}|RZb$^5d}c4B&et|QsigD;uX8O4&HUUM)`BkOy2Vvh&hJ6V;jj83jHf^ zHIyD8QxU9Q^cpVrQL6#~79o5D!>g%tHmiaR_HIOUtAE*b8!eMG* z_byQN^F9GUb+QHJqG4U5><|0^>j$wDwoq4>0@*V3lUkgcg$%$hlfp``o=%MdJb>X> z2&Ojc+~$Om?K)3jje)hw{^Vj8QiHuk`xBs7n8b>l$}h}P-=r5UH_3s)Hi*mvLM>PSV9k0ltYH{=bv6@C8K zwSlL&I2?@f1K_I+4zNmMi+wQTn`1v#r~!-{1Xb8z;=hYH+?UiyZL0nSC>2UEpJ;=`#o!3DUHBaE6Kwp$P|jmLP=3TmO)mq6^dl&p8eR8P zX6El7@0^}YPMJb&Yu20b3h*GcWehY}zmdm)-vQ}i%zXLkL4n2wBvt@I6vH9F=YgZK z?#RQ@t2Px|S&S?I!meLaB)s^_$1|-Tnq&&C55l8(bUyc)%V=(Cp{uhq-qbX8PF;ON zT|qSxyN)6K>zO}qY3@yZ>cUkQES29OoJ{E{ul>YebN)RK+=KPIe+B45&=EAMW^7!& z@2T(;%gHD1n4L?0vz+1tWlt{rx-5nj0PkK1TRpvyQ)j8BfJ&YZO*nM$9MHQHL(;VDR}3`oRv-);TXufG{FJeqZR1{)4t zY1)C8u=Vop0iMBO1Bwn<`Wp(xs@uNWFbbCTVkn0Ke~-0A)D^jlUXg$VKw<@`5^q27 z$4C5f!&XawyMF$ZOl^7%*EIQPl3WMDsFrI{s<;@|_Lq@qJMq>3`bs33>}g%IcHKd( zv*+&ZdFJGFCbMHYlaV3LsLz|pah%o8npMAWZ_?LN=g1w{l3$g0n9|tNSPx(wlAZ!q zA!NCsIG^lXTtMC*AYZhhY{~oXg%EWhV_1OAb-4^{j4Xv-4t-5;B z2W31xTC?8EMN{eV1atg-P4lsgd~#Ad_E zlxZ-{yL^|;h818uq8Y=H*irv5#ug*edL0=*n9PTFJp~?ehL7C%@g=^E_L{QD6g|0y<7$HSIgZ!(4Qu3 z%q};Hwp>jKWh-%54qOOjRRQk82cZ;Mw;Zw_@rcWTzzUQT@W1Hiq(On!`g)GtdJ%`t zpHJNFPcPS8S4VSQ9VyS_H?O@xN4jJU&ITC;AOJ4^&(G15-Ib=g_v_Yg=$u+Nt#QA! zr)PU6bAa)@t&D0}NnzfbwgX1oUPrxr0g-ZY1}b)5{{qTgNY0pN*aW#WU;dX7vl*4g zFa=21b^SV5_!#iF*kHACuBQTBIGA!LBoPr1hh2cLW4)pVQ0X!i;~NLqvALN&T3d-Z z&Y)}87>#nk+_^lnW-TwQPmF0Q;I{zy_ka6m4AH1bzdpa)xJO4K(Ic~2Zx_%VjAqL% zSlH)Lo{MvQ5Nm}$WDNW20A9ly^X>rtg0KNbwBY-J!A>tqx(DC(1x zH|pn6g|2Q7tuOOghzQ^~yoB=quBU%b;%zG4T%zGT0#3Ne?N2r2ip>^14K*wmmNho$PuZM={ERF{LE_c3u zWg9jEUFkGt%9t`t^b={h8dfbMnMm`8IdPs7VFmCh{E<|X4pk*<%;?+b*r#u*L&}z- z_}pjzhWA&kC1V=u-*`W{aM7Y|4o;=Lk0QF*Gde@dRP~2zGQeFsEob>-pCM{S&}#7#_yqeT3dB20wWeArTW716KhK+hA>J=hC0-(=QCr)j9>TWtssa0CRJ- z#S(423;ZYWFuA#k`k&c#LX$Rzx7*uE^d{M&aZ2A3U>>8&s_t&y?dZfar3nF5qCII^ z73RFR9u7OKZ%MuAEJc5L=6QD7aoZV2IVx-1<2}#pZq&?DH9_6y{`#sSd9&3k2=}wO z0PwJ$dCy@Tbne0M8V&T)4)I?H)VktHVf%}dzUNRg&>OJNkZx$;FD$`o(+3cYA>9C7 zCR@Iawprs^u7*S#y`FNLBRu0kTgtdA2qum7ghYYYHf-eaRjW99;Z`)pVto@w1=jcW z^1yrV^Ik`1$u}=!n4d{;F|fX1m(Xtw)*=4tz|VVoQ;Vif(}O)@W~q*zXRRCt3P3VI z13hH99pM!0y!v@;Vv~D;7qH>O8ow#XmW_!x))ugt^)|5#TXZbK4!~u=Qv9!yT!;sB zse(JLyd4daPWeov>zDK4^eKGx@s+J^R-J#KLIDxu9RW6_Qrz*@+a$ADc5iK^xxNmg z%DSE&9$&SZKYy^2-fZcPWva{uPGPX%FE&Gw0wh!Eh%p)&>oj5v^tB`Y>%KB#525@A z@OrMQ@H#3quP@^qdJE5G-7>%dPib@`oCtgdoA@>8%0g+N7lG#gDQ`!^swXqAfyGB2 zmUdiuH>0Eo1whd#@P20}zkU4;{`~$2%&4owQ)NRkNusxROr1Z6;Dbt8Z6BmuCtnSG zx4JDUjsinqpC7=wW#AbkD(s-bXMr;acGNE<4gO?;81Z595L}ROC7^T+(4J1yo=)R* zbmYwU)_PZM&&mpp{CURpBUF$HD1z&<=JWSw>-S??G{Q;1X9fQ&XN^J%@uvpF$fL=) zzHQZ~aPAL7%!eljSL&9ka#p=dQ&tUAUmP@8Q?UkQ}-YRc15IIMi&61)!z;Y z8J%%01ln(Y80kquJXWu%%xS1z2JA-l66)9~fDb)0Ob8NE5yq?bvu+ufuB7V-dyq_j z7Hfp9wyV6=0DK?}_L-Dawlj*1PczbnHZaNz5zfLo_3TV-q|r;F{-lEsHGq(i0VGxc z5K-7utV5g)kjweamz9X$AG&eK25$rCClmr9V`bco{*N93yX^+aBr`=g2RrI-NB;R2 zL81}VWU9TE+KHAQ2?)hi1`0cWNV(L!5JeZxzYnV}+tn z1DK?k60;GF#7LHYV~iMMM2+$Fm}6n)Rj~FVI*j4lktnwT=L(#O%}i7a9)87;p~3%JpwYR57J zUj;z1QZEz&6AV=i{AG;6cm`uUHO9l3+R?aMt^#_9|LAoyNyGT!Bz$G zg%LG?np(dJ@rh8L4@K*>5NV`|H5U!$w+udhh+V7P$fo|^MUVRV*+Z8ZtPN^FNCWA zAps*W4m5yVVUGrs3xI!NxXM^njs(Oy0r`>(0E!R*H6F|rGA8n-z~G-`0hMZZnGtyW zaM)${z8nCb$9f13ZTxctiAAa%5!i*H%z|M3jGPZ3j0Oyuz_%g7VQL|(#nklMAXpnS!O12_? z069VpAY@DwJUBHq1;`}opsOc?sq@LJI@AC{0z`72fTGoYj82ukvSyqYHqlYdodnI1aH`Y~+NL+CM0bbU$^p4MsqR`JF0wUbgDtu@ywC(f<>d z01lGQutP4t|Cs_)$GpRV#U3k<2XwWs_D`OUybS1VcG}~H#>PhG&6`g&8ZEe2T5#hw z`*h$(=;r^){Z9vNH^kNjn+>(S{ZH02tY5c|O`A4Rou_Hs-O`dsTnd^3^=J~0PXM0= z_65qDIh(TX)lb$G8s<=<+;}3fch19kFwvvc%tmZUVAIB*LC3p9M~$`nCL?0R9HyMU>;Qfkyi? zlFz}=c;q7iLjf>4wVIROahx&rJXd&A;WtLvz~(dSq5cm0nK-h*^SlEc$Js_z0}Xho z)E!7%2F)8`y~})ovr#StcJQ?cu4A=;(xmoZfG=Q$066>-!(+gCz=hasM8%Q?dT{(Z zt746Swb_#<5duVA-m8oAvyI)nEhFETk?xoDboVqxqmezPPn&*x*2{hj*v3Dlva%%F zAmTzg!?X=9OB`F+<3MV|!v8ezcSd6tSfe)8)F#QB643O5;-{*iyxq> zTM$gg@qG&L<^?dj9#UDRWIYbbb^MPLl)5ic>gfLj!soN^@JM74v|QQ$Ma$KYxReYj z9wNf?#&DttmkI2H4M-l2B(^lTZ%o*H0F_92HI`Rl`^I)&_HQ`_YOlZkr>tMML8ncd zw(*4*Uif`yN5{Vy~X z;31=YuH`Bo(FL1#{yZ%|fR-OZdk-CJI=KPmeBc|v`y=ePS0L%<6&+Cn@T>)V+-U%* zREk7mJ<({if9$cd-~N*+I4jxwKSO_B$bg;5fX`%@ZS!xl*(~Ywm;||RBk7%Y-o>4F z-UX1}ZMWUtP9zfV)z#HKluoC2ZE9*d%@OBN$91!0y)f+j8A?*8_N`op$nv z@4oxqnwc|OpPxE)>i$hlO`nLz>kc)>%odSGs-Q8h`XnT~5f@q(P2nJH8t=u}j$avs zV$}Z(@OxGMxnT-#yuT8*{CRP^Z@JF?ObPm(gxsp z9-db_8EE|?Z}pRaB=gNT|CZUUE#8w)KD~O^U3U57F1zgfY_vJDdv7wecYS^RsaRv- zlv3rWjKL8oaWP;8&b(Nh#aI>p0H7t9vmfOQ9I-0#(DVW~DEwz#1MhwCCTxF8=|^d~ z!v0;ef{j_YHm*D*upBrG8^4eQQWXJi36b`j0)*5Y3c*U`HR}=p{Po2bGk<;Y#rJ^s zjz0RR`{vJ||ES}*Cr6{vBSf67Rkdh8f@0-WVi}+a5t=aU1{?<*4eSIo1bEt`oPdtx z1hh%vf7S5aNQA_iRb%V?h0MMR5^WfSmju3Olsi@VoFjCKkoHpt43`1N7gd>+&7Z%Z zd;Pj~_bL2!i@9_D=s2-M(&_Ym(P;Dl$8m=7BTz(e9FeT!h*6axr$+0SLpBR;geeHy z00*Ib95@J=MJ+sgf}QgXo&vlJeBCJ5IS#!ut}K1m!;!ZgJbgU9J8i=qo!vYm!Xh!1 zp8|x`0=fCWA{ui&(i$yuhsE=wAN`0aQyQ|}-94)=xp?{QZ@&5F{n1EdkNNZGf3m(V zzB6`?TG&y=3IK;`O${%!&YZp}o9z!_PqcySLMB5UurM0sVBkoscifiL#v1;>(;3KL zfG+`exI$($W8YZW=hnWrYjQ7NnUFSsiHa*4X>n7L`%<$xd-_}as)EPv?zSs~S6q3G zcl?rLI$wJ6ua9lHV2igJ>g#5R9oh>tMHN*+Tt}zRn$^Db5y!3m=S5ras|zKzZaK{g z+j<`RI}Qh9ja>7oxlW%$1c|ve6Oa`GY2Z$Tf2Wb>=tWz8Q0+#Rae5@Ze)lZe43ohoJJ>e zp~6xif$~1eo0{fjh1b`&@s_}c2wlb@`P8FinwsDv4+hhw4Q&w3Kq^keD0MDOLs_r^ z7SYJo*p9xvShaqJ)aocd68#>4uK-_Do(E@5f35tJm+uYJmi>3FuWwsglO7U1!B1D~eIY zNWX8BV-#0}2oMn=juHpz5Smb06}Cu6*+L9+9ov?zfSK5s`xxV4gdd$=;0{&(n2H31td)G_ND~3{6lq@dJ!rrOLI@ zI$53URAyga?I!ulhyq}09V9cnEby41ixjEN0Q(7!0*$W6mho=lQnG_nB=^d@m2Oe( z^BD(ZfIs6p--<4r^+4~RS9doq--l@@Jyq>?`Ob&}pgs#c(&(o>L z9ggcDn|f$WWocC1%(x>ZydQYHA-8F2YI1kjVTZ<8Eanpp)32~4nF`b5D&%!FFSN6-|YW` zZ$o~YMmNixXfKhV0suk`@VdekYPf0UHmpf5+#R=dnu|@@)eGoE?EEmnRr#@^D}X3& zcbdI2wt&P5SnGD>+rs#b${Yu*27U=#n-pG*fSG+2r0+Qt>`IH0i@uwv0w8n+9s;qc zo4gGxc*+<)E5a?nGOW95pgHtHDnci45AZ{Tdj)#uT{UPMC8zpNWI_#K6xJ*U6(lOm zLOBI12zJFTkA;jclEBjnR|0?BlqNAX3bU@UU*<-Bu>B&2T|%9(^Z)#bh7>`f4Y1d1 zE8q-lDd}ApIfq+FZIHqS@B9q-9VtE}1})cYzEObysKW+0b>}|_1waU33rvdO7?16N z(?mEE>v%IU*NMhAY2X>)7Ye^qe-O zW^tz1v6UknhfQ6zH^t?75AhELHUN(Szd*Q~M%IujE=saM{m+m7p#TUep4Fd(WEaxd z%oYeo2%HQYimg8%UgzL2Sns{NfIlESMicAFLd$oG-$}vfKOO57l!8zIgp^34&0bW6 zCRO$n;Y8pVU|Yf^M88n%Qr`2x?MAsngqKxGIx>1H?tv7H{t>MDpJoC({}d7mfB;#$ z9Mr*em4#w`2o_`0Ud<<5Js1l~;0@qGRqg>E?#-|^;-GVXH1?eq2!MS0?Fqf~S4b!T zDnOzQ!~x^c1neNfp}=B<{m^le8K-(=)T;Q83fv1kqK3CyW|DgUec1Ab@^(I;^XEtZ zNzwTs6aW<`(FPcV2-6gH!0-`)!+_nf#V#iMG(oW?u-{d9N|gtJN3&Vp?R4mA6xib0 zGLKL|P5?MSGj`dp9YO&RQUPw;8J>O#E?G{KBWw-qi>++CJGN|eGrm=VuUQm3>aGJ` z!&cON0(d5?yzdI>nE|EW8Zi1##V#L)8bC(}B%x_Gb*{rKU>jgBwH0G`6BZ(ET!%H_y{hn{z>C;uyiG>Q zI+Sj`_lbNu^9djLGu+9Cj1zM42rkfw(26pT{$!k6VTD2~Hsy9+FhuDe;rzzK&YLsX zj=m9_d~`MN0q`Ee+eUd`ln)g)rVPD~pnlHd$3nsApAYJqbfZ6n0$|*e6ABIxQ)m=x zH<*DH0&}s3#o5@;n-!*u^-^raCJ~M2UM^N6bg*7<2HUZdxmOQDC(w@4j_v5{a<5ei zt5w-3VqaN9Qk4v#qq*Q#ngQ$nQ?W+JNhtvSKM}@_1E200ZvX%Q07*qoM6N<$f>_+q AVgLXD literal 0 HcmV?d00001 diff --git a/rehlds/HLTV/Console/msvc/resource.h b/rehlds/HLTV/Console/msvc/resource.h new file mode 100644 index 0000000..26bff13 --- /dev/null +++ b/rehlds/HLTV/Console/msvc/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resource.rc +// +#define IDI_ICON1 107 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 108 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/rehlds/HLTV/Console/src/System.cpp b/rehlds/HLTV/Console/src/System.cpp new file mode 100644 index 0000000..e263c13 --- /dev/null +++ b/rehlds/HLTV/Console/src/System.cpp @@ -0,0 +1,1147 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +System gSystem; + +#ifdef _WIN32 +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) +#else +int main(int argc, char *argv[]) +#endif // _WIN32 +{ +#ifdef _WIN32 + gSystem.BuildCommandLine(lpCmdLine); +#else + gSystem.BuildCommandLine(argc, argv); + _snprintf(g_szEXEName, sizeof(g_szEXEName), "%s", argv[0]); +#endif // _WIN32 + + if (!gSystem.Init(&gSystem, 0, "Console")) + { + gSystem.Sleep(2000); + return 0; + } + + gSystem.RunFrame(0); + gSystem.ShutDown(); + return 0; +} + +char *System::GetBaseDir() +{ + return COM_GetBaseDir(); +} + +void Sys_Printf(char *fmt, ...) +{ + // Dump text to debugging console. + va_list argptr; + static char string[8192]; + + va_start(argptr, fmt); + _vsnprintf(string, sizeof(string), fmt, argptr); + va_end(argptr); + + // Get Current text and append it. + gSystem.Printf("%s", string); +} + +double System::GetTime() +{ + return m_SystemTime; +} + +void System::SetFPS(float fps) +{ + m_MaxFPS = fps > 0 ? (1 / fps) : 0; +} + +void System::RedirectOutput(char *buffer, int maxSize) +{ + m_RedirectBuffer = buffer; + m_RedirectSize = maxSize; + + if (m_RedirectBuffer) { + memset(m_RedirectBuffer, 0, m_RedirectSize); + } +} + +void System::Printf(char *fmt, ...) +{ + va_list argptr; + static char string[8192]; + + va_start(argptr, fmt); + _vsnprintf(string, sizeof(string), fmt, argptr); + va_end(argptr); + + Log(string); + + if (m_RedirectBuffer && strlen(string) + strlen(m_RedirectBuffer) + 1 < m_RedirectSize) { + strcat(m_RedirectBuffer, string); + } + + m_Console.Print(string); +} + +void System::DPrintf(char *fmt, ...) +{ + va_list argptr; + static char string[8192]; + va_start(argptr, fmt); + if (m_Developer) + { + _vsnprintf(string, sizeof(string), fmt, argptr); + Log(string); + + if (m_RedirectBuffer && strlen(string) + strlen(m_RedirectBuffer) + 1 < m_RedirectSize) { + strcat(m_RedirectBuffer, string); + } + + m_Console.Print(string); + } + + va_end(argptr); +} + +void System::FreeFile(unsigned char *fileHandle) +{ + if (!fileHandle) + return; + + free(fileHandle); +} + +bool System::RegisterCommand(char *name, ISystemModule *module, int commandID) +{ + command_t *cmd = (command_t *)m_Commands.GetFirst(); + while (cmd) + { + if (_stricmp(cmd->name, name) == 0) { + Printf("WARNING! System::RegisterCommand: command \"%s\" already exists.\n", name); + return false; + } + + cmd = (command_t *)m_Commands.GetNext(); + } + + cmd = (command_t *)malloc(sizeof(command_t)); + + strcopy(cmd->name, name); + cmd->module = module; + cmd->commandID = commandID; + + m_Commands.Add(cmd); + return true; +} + +void System::ExecuteString(char *commands) +{ + if (!commands || !commands[0]) + return; + + int size = 0; + char singleCmd[256] = ""; + bool quotes = false; + char *p = singleCmd; + char *c = commands; + + COM_RemoveEvilChars(c); + while (true) + { + *p = *c; + + if (++size >= sizeof(singleCmd)) + { + DPrintf("WARNING! System::ExecuteString: Command token too long.\n"); + break; + } + + if (*c == '"') + quotes = !quotes; + + if ((*c != ';' || quotes) && *c) + { + ++p; + } + else + { + *p = '\0'; + + char *cmd = singleCmd; + while (*cmd == ' ') { cmd++; } + + DispatchCommand(cmd); + p = singleCmd; + size = 0; + } + + if (!*c++) + break; + } +} + +void System::Errorf(char *fmt, ...) +{ + va_list argptr; + static char string[1024]; + va_start(argptr, fmt); + _vsnprintf(string, sizeof(string), fmt, argptr); + va_end(argptr); + + Printf("***** FATAL ERROR *****\n"); + Printf("%s", string); + Printf("*** STOPPING SYSTEM ***\n"); + + Stop(); +} + +char *System::CheckParam(char *param) +{ + return m_Parameters.CheckToken(param); +} + +ISystemModule *System::FindModule(char *type, char *name) +{ + if (!type || !type[0]) + return nullptr; + + ISystemModule *module = (ISystemModule *)m_Modules.GetFirst(); + while (module) + { + if (_stricmp(type, module->GetType()) == 0 + && (!name || _stricmp(name, module->GetType()) == 0)) { + return module; + } + + module = (ISystemModule *)m_Modules.GetNext(); + } + + return nullptr; +} + +bool System::AddModule(ISystemModule *module, char *name) +{ + if (!module) + return false; + + if (!module->Init(this, m_SerialCounter, name)) + { + Printf("ERROR! System::AddModule: couldn't initialize module %s.\n", name); + return false; + } + + m_Modules.AddHead(module); + m_SerialCounter++; + + return true; +} + +ISystemModule *System::GetModule(char *interfacename, char *library, char *instancename) +{ + ISystemModule *module = FindModule(interfacename, instancename); + if (module) { + return module; + } + + library_t *lib = GetLibrary(library); + if (!lib) { + return nullptr; + } + + module = (ISystemModule *)lib->createInterfaceFn(interfacename, nullptr); + if (!module) { + DPrintf("ERROR! System::GetModule: interface \"%s\" not found in library %s.\n", interfacename, lib->name); + return nullptr; + } + + AddModule(module, instancename); + return module; +} + +void System::Stop() +{ + m_State = MODULE_DISCONNECTED; +} + +bool System::RemoveModule(ISystemModule *module) +{ + if (!module) { + return true; + } + + module->ShutDown(); + + command_t *cmd = (command_t *)m_Commands.GetFirst(); + while (cmd) + { + if (cmd->module->GetSerial() == module->GetSerial()) { + m_Commands.Remove(cmd); + free(cmd); + } + + cmd = (command_t *)m_Commands.GetNext(); + } + + ISystemModule *mod = (ISystemModule *)m_Modules.GetFirst(); + while (mod) + { + if (mod->GetSerial() == module->GetSerial()) { + m_Modules.Remove(mod); + return true; + } + + mod = (ISystemModule *)m_Modules.GetNext(); + } + + return false; +} + +void System::GetCommandMatches(char *string, ObjectList *pMatchList) +{ + int len = strlen(string); + command_t *cmd = (command_t *)m_Commands.GetFirst(); + while (cmd) + { + if (!strncmp(cmd->name, string, len)) { + pMatchList->AddTail(cmd); + } + + cmd = (command_t *)m_Commands.GetNext(); + } +} + +System::LocalCommandID_s System::m_LocalCmdReg[] = { + { "developer", CMD_ID_DEVELOPER, &System::CMD_Developer }, + { "exec", CMD_ID_EXEC, &System::CMD_Exec }, + { "modules", CMD_ID_MODULES, &System::CMD_Modules }, + { "cmdlist", CMD_ID_CMDLIST, &System::CMD_CmdList }, + { "help", CMD_ID_CMDLIST, &System::CMD_CmdList }, + { "logfile", CMD_ID_LOGFILE, &System::CMD_Logfile }, + { "quit", CMD_ID_QUIT, &System::CMD_Quit }, + { "exit", CMD_ID_QUIT, &System::CMD_Quit }, + { "loadmodule", CMD_ID_LOADMODULE, &System::CMD_LoadModule }, + { "unloadmodule", CMD_ID_UNLOADMODULE, &System::CMD_UnloadModule }, + { "title", CMD_ID_TITLE, &System::CMD_Title }, + { "showcon", CMD_ID_SHOWCON, &System::CMD_ShowCon }, + { "echo", CMD_ID_ECHO, &System::CMD_Echo }, +}; + +bool System::Init(IBaseSystem *system, int serial, char *name) +{ + if (!BaseSystemModule::Init(system, serial, name)) + return false; + + m_State = serial; + m_SerialCounter = serial + 1; + + if (!name) { + SetName("system"); + } + + strcopy(m_BaseDir, GetBaseDir()); + + m_Developer = CheckParam("-dev") ? true : false; + if (!m_Console.Init(this)) + { + Error(); + return false; + } + + m_SystemTime = 0; + m_LastTime = 0; + + if (!InitTimer() || !InitFileSystem()) + return false; + + m_Commands.Init(); + m_Modules.Init(); + m_Libraries.Init(); + + m_LogFile = nullptr; + memset(m_LogFileName, 0, sizeof(m_LogFileName)); + memset(m_Factorylist, 0, sizeof(m_Factorylist)); + + m_RedirectBuffer = nullptr; + m_RedirectSize = 0; + m_Tick = 0; + m_SleepMSecs = 1; + m_VGUIModule = nullptr; + m_VGUIStarted = false; + SeedRandomNumberGenerator(); + + if (CheckParam("-highpriority")) + { + m_SleepMSecs = 0; +#ifdef _WIN32 + SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); +#endif // _WIN32 + } + + auto pszValue = CheckParam("-maxfps"); + SetFPS(pszValue ? (float)atof(pszValue) : 100); + + for (auto& cmd : m_LocalCmdReg) { + RegisterCommand(cmd.name, this, cmd.id); + } + + SetTitle("Console"); + GetModule(PROXY_INTERFACE_VERSION, "proxy"); + SetTitle("HLTV"); + m_State = MODULE_RUNNING; + + DPrintf("System initialized.\n"); + ExecuteCommandLine(); + Printf("Type 'help' for a list of commands.\n"); + + return true; +} + +bool System::StartVGUI() +{ +#ifndef _WIN32 + return false; +#else + /*if (!m_FileSystemModule) { + Printf("System::StartVGUI: filesystem not loaded.\n"); + return false; + } + + if (CheckParam("-novgui")) { + return false; + } + + m_VGUIModule = Sys_LoadModule(VGUI2_LIB); + + m_Factorylist[0] = Sys_GetFactoryThis(); + m_Factorylist[1] = Sys_GetFactory(m_VGUIModule); + m_Factorylist[2] = Sys_GetFactory(m_FileSystemModule); + + if (vgui2::VGuiControls_Init("HLTV", m_Factorylist, ARRAYSIZE(m_Factorylist))) + { + vgui2::filesystem()->AddSearchPath("platform", "PLATFORM"); + vgui2::localize()->AddFile(vgui2::filesystem(), "Resource/platform_%language%.txt"); + vgui2::localize()->AddFile(vgui2::filesystem(), "Resource/vgui_%language%.txt"); + + m_MainPanel = new Panel(nullptr, "MainPanel"); + vgui2::surface()->SetEmbeddedPanel(m_MainPanel->GetVPanel()); + + if (!vgui2::scheme()->LoadSchemeFromFile("platform/Resource/TrackerScheme.res", "DEFAULT")) { + Printf("System::StartVGUI: Could not load TrackerScheme.res\n"); + return false; + } + + // Start vgui + vgui2::ivgui()->Start(); + m_VGUIStarted = true; + Printf("VGUI initialized.\n"); + return true; + } + else + { + Printf("System::StartVGUI: Could not initialize vgui.\n"); + return false; + }*/ + + return false; +#endif // _WIN32 +} + +void System::StopVGUI() +{ + if (!m_VGUIStarted) + return; + + /*vgui2::surface()->Shutdown(); + if (m_MainPanel) { + delete m_MainPanel; + m_MainPanel = nullptr; + } + + Sys_UnloadModule(m_VGUIModule);*/ + Printf("VGUI shutdown.\n"); +} + +void System::SetName(char *newName) +{ + strcopy(m_Name, newName); +} + +void System::RunFrame(double time) +{ + float fps = 0.0f; + float nextConsoleUpdate = 0.0f; + + BaseSystemModule::RunFrame(time); + while ((m_State == MODULE_RUNNING || m_State == MODULE_CONNECTING)) + { + UpdateTime(); + double timeDiff = m_SystemTime - m_LastTime; + if (m_LastTime > 0 && timeDiff <= 0) { + Printf("WARNING! System::RunFrame: system time difference <= 0.\n"); + timeDiff = 0.001; + } + + if (m_MaxFPS > timeDiff) { + Sleep(m_SleepMSecs); + continue; + } + + m_Tick++; + m_LastTime = m_SystemTime; + fps = (float)(0.1 / timeDiff) + fps * 0.9f; + + if (m_SystemTime > nextConsoleUpdate) + { + ExecuteString(GetInput()); + m_Console.SetStatusLine(m_StatusLine); + nextConsoleUpdate = (float)(m_SystemTime * 0.1); + } + + /*if (m_MainPanel) { + vgui2::ivgui()->RunFrame(); + }*/ + + if (m_State == MODULE_CONNECTING) { + Sleep(1); + continue; + } + + ISystemModule *module = (ISystemModule *)m_Modules.GetFirst(); + while (module) + { + if (m_State == MODULE_DISCONNECTED) + break; + + module->RunFrame(m_SystemTime); + module = (ISystemModule *)m_Modules.GetNext(); + } + } +} + +char *System::GetStatusLine() +{ + static char string[80]; + sprintf(string, " Libraries %i, Modules %i, Commands %i.\n", m_Libraries.CountElements(), m_Modules.CountElements(), m_Commands.CountElements()); + return string; +} + +char *System::GetType() +{ + return BASESYSTEM_INTERFACE_VERSION; +} + +IFileSystem *System::GetFileSystem() +{ + return m_FileSystem; +} + +void System::ShutDown() +{ + m_Commands.Clear(true); + + ISystemModule *module = (ISystemModule *)m_Modules.GetFirst(); + while (module) + { + module->ShutDown(); + module = (ISystemModule *)m_Modules.GetNext(); + } + + library_t *lib = (library_t *)m_Libraries.RemoveTail(); + while (lib) + { + if (lib->handle) { + Sys_UnloadModule(lib->handle); + } + free(lib); + lib = (library_t *)m_Libraries.RemoveTail(); + } + + CloseLogFile(); + if (m_FileSystem) { + m_FileSystem->Unmount(); + } + + Sys_UnloadModule(m_FileSystemModule); + StopVGUI(); + + if (m_Developer) { + Sleep(3000); + } + + m_Console.ShutDown(); + m_State = MODULE_DISCONNECTED; +} + +#ifdef _WIN32 + +void System::BuildCommandLine(char *argv) +{ + m_Parameters.SetLine(argv); +} + +#else // _WIN32 + +#define MAX_LINUX_CMDLINE 2048 + +void System::BuildCommandLine(int argc, char **argv) +{ + int len = 0; + char string[MAX_LINUX_CMDLINE]; + + for (int i = 1; i < argc && len < MAX_LINUX_CMDLINE; i++) + { + len += strlen(argv[i]) + 1; + + if (i > 1) { + strcat(string, " "); + } + + strcat(string, argv[i]); + } + + m_Parameters.SetLine(string); +} + +#endif // _WIN32 + +void System::Sleep(int msec) +{ +#ifdef _WIN32 + ::Sleep(msec); +#else + usleep(1000 * msec); +#endif // _WIN32 +} + +bool System::InitFileSystem() +{ + char *filesystemmodule = STDIO_FILESYSTEM_LIB; +#ifdef _WIN32 + if (CheckParam("-steam")) { + filesystemmodule = STEAM_FILESYSTEM_LIB; + } +#endif // _WIN32 + + m_FileSystemModule = Sys_LoadModule(filesystemmodule); + if (!m_FileSystemModule) + { + Errorf("Couldn't load %s.\n", filesystemmodule); + return false; + } + + CreateInterfaceFn filesystemFactory = Sys_GetFactory(m_FileSystemModule); + if (!filesystemFactory) + return false; + + m_FileSystem = (IFileSystem *)filesystemFactory(FILESYSTEM_INTERFACE_VERSION, nullptr); + if (!m_FileSystem) + { + Errorf("Couldn't get IFileSystem from %s.\n", filesystemmodule); + return false; + } + + m_FileSystem->Mount(); + m_FileSystem->AddSearchPath(m_BaseDir, "ROOT"); + + Printf("FileSystem initialized"); + DPrintf(" (%s, %s)", filesystemmodule, m_BaseDir); + Printf(".\n"); + + return true; +} + +bool System::InitTimer() +{ + if (!m_Counter.Init()) { + Errorf("Couldn't get system timer.\n"); + return false; + } + + m_SystemTime = 0; + m_LastTime = 0; + return true; +} + +void System::Error() +{ + Errorf("%s\n", strerror(errno)); +} + +void System::CMD_CmdList(char *cmdLine) +{ + Printf("Registerd console commands:"); + + command_t *cmd = (command_t *)m_Commands.GetFirst(); + while (cmd) + { + Printf("\n %s", cmd->name); + DPrintf(" (%s)", cmd->module->GetName()); + + cmd = (command_t *)m_Commands.GetNext(); + } + + Printf("\n"); +} + +void System::CMD_Title(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) { + Printf("Syntax: title \n"); + return; + } + + m_Console.SetTitle(params.GetToken(1)); +} + +void System::CMD_Echo(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 2) { + Printf("Syntax: title \n"); + return; + } + + Printf("%s\n", params.GetRestOfLine(1)); +} + +void System::CMD_Logfile(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + Printf("Syntax: logfile <0|1|filename>\n"); + if (m_LogFile) { + Printf("Console is logged to \"%s\".\n", m_LogFileName); + } + else { + Printf("Logging is off.\n"); + } + + return; + } + + char *param = params.GetToken(1); + switch (param[0]) { + // log enabled + case '1': + { + if (m_LogFile) { + Printf("Console is logged to \"%s\".\n", m_LogFileName); + return; + } + + char filename[MAX_PATH]; + sprintf(filename, "logfile%s.txt", COM_TimeString()); + OpenLogFile(filename); + break; + } + // log disabled + case '0': + CloseLogFile(); + break; + // log enabled with the provided file name. + default: + OpenLogFile(param); + break; + } +} + +void System::CMD_ShowCon(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) { + Printf("Syntax: showcon <0|1>\n"); + return; + } + + char *param = params.GetToken(1); + ShowConsole((param[0] != '0') ? true : false); +} + +void System::CMD_Modules(char *cmdLine) +{ + ISystemModule *module = (ISystemModule *)m_Modules.GetFirst(); + while (module) + { + Printf("Module %s, Interface %s, Version %i\n", + module->GetName(), + module->GetType(), + module->GetVersion()); + + module = (ISystemModule *)m_Modules.GetNext(); + } + + Printf("--- %i modules in total ---\n", m_Modules.CountElements()); +} + +void System::CMD_Exec(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) { + Printf("Syntax: exec \n"); + return; + } + + ExecuteFile(params.GetToken(1)); +} + +void System::CMD_Developer(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) { + Printf("Syntax: developer <0|1>\n"); + Printf("Developer mode is %s.\n", m_Developer ? "on" : "off"); + return; + } + + m_Developer = atoi(params.GetToken(1)) ? true : false; +} + +void System::CMD_Quit(char *cmdLine) +{ + Stop(); +} + +void System::OpenLogFile(char *filename) +{ + CloseLogFile(); + strcopy(m_LogFileName, filename); + + m_LogFile = m_FileSystem->Open(m_LogFileName, "wt"); + if (!m_LogFile) + { + memset(m_LogFileName, 0, sizeof(m_LogFileName)); + Printf("System::OpenLogFile: error while opening logfile.\n"); + } +} + +void System::CloseLogFile() +{ + if (!m_LogFile || !m_FileSystem) + return; + + m_FileSystem->Flush(m_LogFile); + m_FileSystem->Close(m_LogFile); + m_LogFile = nullptr; + + Printf("Console log file closed.\n"); + memset(m_LogFileName, 0, sizeof(m_LogFileName)); +} + +void System::Log(char *string) +{ + if (!m_LogFile) + return; + + m_FileSystem->Write(string, strlen(string), m_LogFile); +} + +void System::ExecuteFile(char *filename) +{ + char line[256]; + FileHandle_t cfgfile; + + cfgfile = m_FileSystem->Open(filename, "rt"); + if (!cfgfile) { + Printf("Couldn't open config file %s.\n", filename); + return; + } + + Printf("Executing file %s.\n", filename); + while ((m_FileSystem->ReadLine(line, sizeof(line) - 1, cfgfile))) + { + char *remark = strstr(line, "//"); + if (remark) { + *remark = '\0'; + } + + ExecuteString(line); + } + + m_FileSystem->Close(cfgfile); +} + +bool System::DispatchCommand(char *command) +{ + if (!command || !command[0]) + return true; + + TokenLine params(command); + command_t *cmd = (command_t *)m_Commands.GetFirst(); + while (cmd) + { + if (_stricmp(cmd->name, params.GetToken(0)) == 0) { + cmd->module->ExecuteCommand(cmd->commandID, command); + return true; + } + + cmd = (command_t *)m_Commands.GetNext(); + } + + Printf("WARNING! System::DispatchCommand: command \"%s\" not registered.\n", command); + return false; +} + +void System::ExecuteCommandLine() +{ + int i = 0; + char string[256]; + char *token = m_Parameters.GetToken(i); + while (token) + { + if (token[0] != '+') { + token = m_Parameters.GetToken(++i); + continue; + } + + memset(string, 0, sizeof(string)); + strcopy(string, token + 1); + + // next iteration + token = m_Parameters.GetToken(++i); + while (token && !(token[0] == '+' || token[0] == '-')) + { + strncat(string, " ", (sizeof(string) - 1) - strlen(string)); + strncat(string, token, (sizeof(string) - 1) - strlen(string)); + + token = m_Parameters.GetToken(++i); + } + + ExecuteString(string); + } +} + +void System::UpdateTime() +{ + m_SystemTime = m_Counter.GetCurTime(); +} + +char *System::GetInput() +{ + return m_Console.GetLine(); +} + +void System::CMD_LoadModule(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 2) { + Printf("Syntax: loadmodule [] []\n"); + return; + } + + switch (params.CountToken()) { + case 2: + GetModule(params.GetToken(1), params.GetToken(1)); + break; + case 3: + GetModule(params.GetToken(1), params.GetToken(2)); + break; + default: + GetModule(params.GetToken(1), params.GetToken(2), params.GetToken(3)); + break; + } +} + +void System::CMD_UnloadModule(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 2) { + Printf("Syntax: unloadmodule []\n"); + return; + } + + ISystemModule *module = nullptr; + switch (params.CountToken()) { + case 2: + module = FindModule(params.GetToken(1)); + break; + case 3: + module = FindModule(params.GetToken(1), params.GetToken(2)); + break; + } + + if (!module) { + Printf("Module not found.\n"); + return; + } + + RemoveModule(module); +} + +System::library_t *System::GetLibrary(char *name) +{ + char fixedname[MAX_PATH]; + strcopy(fixedname, name); + COM_FixSlashes(fixedname); + + library_t *lib = (library_t *)m_Libraries.GetFirst(); + while (lib) + { + if (_stricmp(lib->name, name) == 0) { + return lib; + } + + lib = (library_t *)m_Libraries.GetNext(); + } + + lib = (library_t *)malloc(sizeof(library_t)); + if (!lib) { + DPrintf("ERROR! System::GetLibrary: out of memory (%s).\n", name); + return nullptr; + } + + _snprintf(lib->name, sizeof(lib->name), "%s." LIBRARY_PREFIX, fixedname); + lib->handle = (CSysModule *)Sys_LoadModule(lib->name); + if (!lib->handle) { + DPrintf("ERROR! System::GetLibrary: coulnd't load library (%s).\n", lib->name); + free(lib); + return nullptr; + } + + lib->createInterfaceFn = (CreateInterfaceFn)Sys_GetFactory(lib->handle); + if (!lib->createInterfaceFn) { + DPrintf("ERROR! System::GetLibrary: coulnd't get object factory(%s).\n", lib->name); + free(lib); + return nullptr; + } + + m_Libraries.Add(lib); + DPrintf("Loaded library %s.\n", lib->name); + + return lib; +} + +unsigned int System::GetTick() +{ + return m_Tick; +} + +void System::ExecuteCommand(int commandID, char *commandLine) +{ + for (auto& cmd : m_LocalCmdReg) + { + if (cmd.pfnCmd && cmd.id == commandID) { + (this->*cmd.pfnCmd)(commandLine); + return; + } + } + + Printf("ERROR! System::ExecuteCommand: unknown command ID %i.\n", commandID); +} + +void System::SetTitle(char *text) +{ + m_Console.SetTitle(text); +} + +bool System::InitVGUI(IVGuiModule *module) +{ + if (!m_VGUIStarted && !StartVGUI()) { + return false; + } + +#ifdef _WIN32 + module->Initialize(m_Factorylist, ARRAYSIZE(m_Factorylist)); + module->PostInitialize(); + //module->SetParent(m_MainPanel->GetVPanel()); +#endif // _WIN32 + + return true; +} + +Panel *System::GetPanel() +{ +#ifdef _WIN32 + if (m_VGUIStarted || StartVGUI()) { + return m_MainPanel; + } +#endif // _WIN32 + + return nullptr; +} + +void System::SetStatusLine(char *text) +{ + strcopy(m_StatusLine, text); +} + +void System::ShowConsole(bool visible) +{ + m_Console.SetVisible(visible); +} + +void System::LogConsole(char *filename) +{ + if (filename) { + OpenLogFile(filename); + return; + } + + CloseLogFile(); +} + +unsigned char *System::LoadFile(const char *name, int *length) +{ + if (!m_FileSystem) { + return nullptr; + } + + if (length) { + *length = 0; + } + + FileHandle_t hFile = m_FileSystem->Open(name, "rb", 0); + if (!hFile) { + return nullptr; + } + + m_FileSystem->Seek(hFile, 0, FILESYSTEM_SEEK_TAIL); + + int len = m_FileSystem->Tell(hFile); + unsigned char *buf = (unsigned char *)malloc(len + 1); + if (!buf) + { + Printf("WARNING! System::LoadFile: not enough space for %s.\n", name); + return nullptr; + } + + buf[len] = '\0'; + m_FileSystem->Seek(hFile, 0, FILESYSTEM_SEEK_HEAD); + m_FileSystem->Read(buf, len, hFile); + m_FileSystem->Close(hFile); + + if (length) { + *length = len; + } + + return buf; +} diff --git a/rehlds/HLTV/Console/src/System.h b/rehlds/HLTV/Console/src/System.h new file mode 100644 index 0000000..75a589c --- /dev/null +++ b/rehlds/HLTV/Console/src/System.h @@ -0,0 +1,188 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "TokenLine.h" +#include "interface.h" +#include "textconsole.h" +#include "BaseSystemModule.h" +#include "ObjectList.h" + +class Panel; +class System: public IBaseSystem, public BaseSystemModule { +public: + System() {} + ~System() {} + + double GetTime(); + unsigned int GetTick(); + void SetFPS(float fps); + void Printf(char *fmt, ...); + void DPrintf(char *fmt, ...); + void RedirectOutput(char *buffer, int maxSize); + IFileSystem *GetFileSystem(); + unsigned char *LoadFile(const char *name, int *length); + void FreeFile(unsigned char *fileHandle); + void SetTitle(char *pszTitle); + void SetStatusLine(char *pszStatus); + void ShowConsole(bool visible); + void LogConsole(char *filename); + bool InitVGUI(IVGuiModule *module); + Panel *GetPanel(); + bool RegisterCommand(char *name, ISystemModule *module, int commandID); + void GetCommandMatches(char *string, ObjectList *pMatchList); + void ExecuteString(char *commands); + void ExecuteFile(char *filename); + void Errorf(char *fmt, ...); + char *CheckParam(char *param); + bool AddModule(ISystemModule *module, char *name); + ISystemModule *GetModule(char *interfacename, char *library, char *instancename = nullptr); + bool RemoveModule(ISystemModule *module); + void Stop(); + bool Init(IBaseSystem *system, int serial, char *name); + void RunFrame(double time); + void ExecuteCommand(int commandID, char *commandLine); + char *GetType(); + char *GetStatusLine(); + void ShutDown(); + char *GetBaseDir(); + +#ifdef _WIN32 + void BuildCommandLine(char *argv); +#else + void BuildCommandLine(int argc, char **argv); +#endif // _WIN32 + void Sleep(int msec); + +protected: + struct command_t { + char name[32]; + int commandID; + ISystemModule *module; + }; + + struct library_t { + char name[MAX_PATH]; + CSysModule *handle; + CreateInterfaceFn createInterfaceFn; + }; + + library_t *GetLibrary(char *name); + ISystemModule *FindModule(char *type, char *name = nullptr); + bool InitTimer(); + bool InitFileSystem(); + void Error(); + void OpenLogFile(char *filename); + void CloseLogFile(); + void Log(char *string); + bool DispatchCommand(char *command); + void ExecuteCommandLine(); + void UpdateTime(); + char *GetInput(); + bool StartVGUI(); + void StopVGUI(); + void SetName(char *newName); + +protected: + enum LocalCommandIDs { + CMD_ID_DEVELOPER = 1, + CMD_ID_EXEC, + CMD_ID_MODULES, + CMD_ID_CMDLIST, + CMD_ID_LOGFILE, + CMD_ID_QUIT, + CMD_ID_LOADMODULE, + CMD_ID_UNLOADMODULE, + CMD_ID_TITLE, + CMD_ID_SHOWCON, + CMD_ID_ECHO + }; + + void CMD_Developer(char *cmdLine); + void CMD_Exec(char *cmdLine); + void CMD_Title(char *cmdLine); + void CMD_Modules(char *cmdLine); + void CMD_CmdList(char *cmdLine); + void CMD_ShowCon(char *cmdLine); + void CMD_Logfile(char *cmdLine); + void CMD_Quit(char *cmdLine); + void CMD_UnloadModule(char *cmdLine); + void CMD_LoadModule(char *cmdLine); + void CMD_Echo(char *cmdLine); + + struct LocalCommandID_s { + char *name; + LocalCommandIDs id; + void (System::*pfnCmd)(char *cmdLine); + }; + static LocalCommandID_s m_LocalCmdReg[]; + +private: + double m_LastTime; + +#ifdef _WIN32 + CTextConsoleWin32 m_Console; +#else + CTextConsoleUnix m_Console; +#endif // _WIN32 + + CCounter m_Counter; + CSysModule *m_FileSystemModule; + IFileSystem *m_FileSystem; + CSysModule *m_VGUIModule; + TokenLine m_Parameters; + + char m_BaseDir[MAX_PATH]; + char m_StatusLine[80]; + + FileHandle_t m_LogFile; + char m_LogFileName[MAX_PATH]; + + ObjectList m_Modules; + ObjectList m_Libraries; + ObjectList m_Commands; + + float m_MaxFPS; + char *m_RedirectBuffer; + unsigned int m_RedirectSize; + bool m_Developer; + + unsigned int m_SerialCounter; + unsigned int m_Tick; + unsigned int m_SleepMSecs; + + CreateInterfaceFn m_Factorylist[3]; + + bool m_VGUIStarted; + Panel *m_MainPanel; +}; + +extern System gSystem; + +void Sys_Printf(char *fmt, ...); diff --git a/rehlds/HLTV/Console/src/precompiled.cpp b/rehlds/HLTV/Console/src/precompiled.cpp new file mode 100644 index 0000000..5f656a4 --- /dev/null +++ b/rehlds/HLTV/Console/src/precompiled.cpp @@ -0,0 +1 @@ +#include "precompiled.h" diff --git a/rehlds/HLTV/Console/src/precompiled.h b/rehlds/HLTV/Console/src/precompiled.h new file mode 100644 index 0000000..19ee736 --- /dev/null +++ b/rehlds/HLTV/Console/src/precompiled.h @@ -0,0 +1,19 @@ +#pragma once + +#include "osconfig.h" +#include "archtypes.h" +#include "mathlib.h" +#include "FileSystem.h" + +#include +#include + +#include "interface.h" + +#include "mem.h" +#include "common.h" +#include "common/common_hltv.h" + +// Console stuff +#include "System.h" +#include "common/random.h" diff --git a/rehlds/HLTV/Console/src/public_amalgamation.cpp b/rehlds/HLTV/Console/src/public_amalgamation.cpp new file mode 100644 index 0000000..1fc308c --- /dev/null +++ b/rehlds/HLTV/Console/src/public_amalgamation.cpp @@ -0,0 +1,3 @@ +#include "precompiled.h" + +#include "interface.cpp" diff --git a/rehlds/HLTV/Core/build.gradle b/rehlds/HLTV/Core/build.gradle new file mode 100644 index 0000000..3b137cc --- /dev/null +++ b/rehlds/HLTV/Core/build.gradle @@ -0,0 +1,154 @@ +import org.doomedsociety.gradlecpp.cfg.ToolchainConfigUtils +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.toolchain.icc.Icc +import org.doomedsociety.gradlecpp.toolchain.icc.IccCompilerPlugin +import org.doomedsociety.gradlecpp.gcc.GccToolchainConfig +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeLibrarySpec +import org.gradle.nativeplatform.toolchain.VisualCpp + +apply plugin: 'cpp' +apply plugin: IccCompilerPlugin +apply plugin: GccCompilerPlugin + +project.ext.dep_bzip2 = project(':dep/bzip2') + +void setupToolchain(NativeBinarySpec b) { + def cfg = rootProject.createToolchainConfig(b); + cfg.projectInclude(project, '/..', '/../..', '/src', '/../../common', '/../../engine', '/../../public', '/../../public/rehlds', '/../../pm_shared'); + cfg.projectInclude(dep_bzip2, '/include') + + cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'CORE_MODULE' + + if (cfg instanceof MsvcToolchainConfig) { + cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig( + enabled: true, + pchHeader: 'precompiled.h', + pchSourceSet: 'core_pch' + ); + + cfg.singleDefines('_CRT_SECURE_NO_WARNINGS') + cfg.compilerOptions.args '/Ob2', '/Oi', '/GF' + cfg.extraLibs "ws2_32.lib", "psapi.lib" + } + else if (cfg instanceof GccToolchainConfig) { + cfg.compilerOptions.pchConfig = new GccToolchainConfig.PrecompilerHeaderOptions( + enabled: true, + pchSourceSet: 'core_pch' + ); + + cfg.compilerOptions.languageStandard = 'c++0x' + cfg.defines([ + '_strdup': 'strdup', + '_stricmp': 'strcasecmp', + '_strnicmp': 'strncasecmp', + '_vsnprintf': 'vsnprintf', + '_snprintf': 'snprintf', + ]); + + cfg.compilerOptions.args '-Qoption,cpp,--treat_func_as_string_literal_cpp', '-fno-exceptions' + } + + ToolchainConfigUtils.apply(project, cfg, b); +} + +model { + buildTypes { + release + } + + platforms { + x86 { + architecture "x86" + } + } + + toolChains { + visualCpp(VisualCpp) { + } + icc(Icc) { + } + } + + components { + core(NativeLibrarySpec) { + targetPlatform 'x86' + baseName 'core' + + sources { + core_main(CppSourceSet) { + source { + srcDir "src" + include "**/*.cpp" + exclude "precompiled.cpp" + } + + lib project: ':dep/bzip2', library: 'bzip2', linkage: 'static' + } + + core_common(CppSourceSet) { + source { + srcDirs "../../common", "../common" + + // common + include "BaseSystemModule.cpp" + include "ObjectDictionary.cpp" + include "ObjectList.cpp" + include "TokenLine.cpp" + + // HLTV common + include "BitBuffer.cpp" + include "byteorder.cpp" + include "common.cpp" + include "DemoFile.cpp" + include "DirectorCmd.cpp" + include "InfoString.cpp" + include "mathlib.cpp" + include "md5.cpp" + include "munge.cpp" + include "NetAddress.cpp" + include "NetChannel.cpp" + include "random.cpp" + } + } + + core_engine(CppSourceSet) { + source { + srcDir "../../engine" + include "mem.cpp" + } + } + + core_pch(CppSourceSet) { + source { + srcDir "src" + include "precompiled.cpp" + + lib project: ':dep/bzip2', library: 'bzip2', linkage: 'static' + } + } + } + + binaries.all { + NativeBinarySpec b -> project.setupToolchain(b) + } + } + } +} + +task buildFixes { + dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} + +task buildRelease { + dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} + +// prevent static lib building +binaries.withType(StaticLibraryBinarySpec) { binary -> + buildable = false +} diff --git a/rehlds/HLTV/Core/msvc/Core.sln b/rehlds/HLTV/Core/msvc/Core.sln new file mode 100644 index 0000000..bd7239b --- /dev/null +++ b/rehlds/HLTV/Core/msvc/Core.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Core", "Core.vcxproj", "{52F752EA-73D1-422D-B805-17EF1FB20E09}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzip2", "..\..\..\..\dep\bzip2\msvc\bzip2.vcxproj", "{792DF067-9904-4579-99B9-46C17277ADE3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {52F752EA-73D1-422D-B805-17EF1FB20E09}.Debug|Win32.ActiveCfg = Debug|Win32 + {52F752EA-73D1-422D-B805-17EF1FB20E09}.Debug|Win32.Build.0 = Debug|Win32 + {52F752EA-73D1-422D-B805-17EF1FB20E09}.Release|Win32.ActiveCfg = Release|Win32 + {52F752EA-73D1-422D-B805-17EF1FB20E09}.Release|Win32.Build.0 = Release|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug|Win32.ActiveCfg = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug|Win32.Build.0 = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Release|Win32.ActiveCfg = Release|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/rehlds/HLTV/Core/msvc/Core.vcxproj b/rehlds/HLTV/Core/msvc/Core.vcxproj new file mode 100644 index 0000000..644508e --- /dev/null +++ b/rehlds/HLTV/Core/msvc/Core.vcxproj @@ -0,0 +1,251 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {52F752EA-73D1-422D-B805-17EF1FB20E09} + Win32Proj + Core + 8.1 + + + + DynamicLibrary + true + v120_xp + v140_xp + MultiByte + + + DynamicLibrary + false + v120_xp + v140_xp + true + MultiByte + + + + + + + + + + + + + + + true + core + + + false + + + + Use + Level3 + Disabled + HLTV;WIN32;_DEBUG;_WINDOWS;_USRDLL;CORE_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + $(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;$(ProjectDir)\..\..\..\..\dep\bzip2\include;%(AdditionalIncludeDirectories) + precompiled.h + MultiThreadedDebug + true + EnableFastChecks + false + + + Windows + true + psapi.lib;ws2_32.lib;%(AdditionalDependencies) + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + echo Empty Action + + + Force build to run Pre-Build event + + + git.always.run + + + git.always.run + + + + + Level3 + Use + MaxSpeed + true + true + HLTV;WIN32;NDEBUG;_WINDOWS;_USRDLL;CORE_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + $(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;$(ProjectDir)\..\..\..\..\dep\bzip2\include;%(AdditionalIncludeDirectories) + precompiled.h + MultiThreaded + true + + + Windows + true + true + true + psapi.lib;ws2_32.lib;%(AdditionalDependencies) + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + echo Empty Action + + + Force build to run Pre-Build event + + + git.always.run + + + git.always.run + + + + + + + + + + true + true + + + true + true + + + true + true + + + + + + + + + + + + + + + Use + precompiled.h + Use + precompiled.h + + + Use + precompiled.h + Use + precompiled.h + + + Use + precompiled.h + Use + precompiled.h + + + Use + precompiled.h + Use + precompiled.h + + + Create + precompiled.h + Create + precompiled.h + + + + Use + precompiled.h + Use + precompiled.h + + + Use + precompiled.h + Use + precompiled.h + + + + + + + + + + true + true + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + {792df067-9904-4579-99b9-46c17277ade3} + + + + + + \ No newline at end of file diff --git a/rehlds/HLTV/Core/msvc/Core.vcxproj.filters b/rehlds/HLTV/Core/msvc/Core.vcxproj.filters new file mode 100644 index 0000000..1a7689c --- /dev/null +++ b/rehlds/HLTV/Core/msvc/Core.vcxproj.filters @@ -0,0 +1,192 @@ + + + + + {a2b59fb8-08c7-4528-89af-ade37c2610c8} + + + {2c80c58c-56fb-4bd9-b106-8ed08029173e} + + + {664fe3c6-46ae-4fa5-bf0c-f70873228f5e} + + + {fb482bcd-a131-4e66-be87-c7b0ffe6a4cf} + + + {0997bc0d-a67f-47eb-abc1-3c7ebb128beb} + + + {3a1d44ef-34e6-4921-a2b7-ff9808b3cfad} + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + src + + + src\hookers + + + src\hookers + + + common + + + common + + + common + + + common + + + HLTV\common + + + src\hookers + + + engine + + + + + src + + + src + + + src + + + src + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + src + + + src + + + src + + + src\hookers + + + common + + + common + + + common + + + common + + + HLTV\common + + + src\hookers + + + engine + + + \ No newline at end of file diff --git a/rehlds/HLTV/Core/msvc/PostBuild.bat b/rehlds/HLTV/Core/msvc/PostBuild.bat new file mode 100644 index 0000000..8583878 --- /dev/null +++ b/rehlds/HLTV/Core/msvc/PostBuild.bat @@ -0,0 +1,39 @@ +@echo OFF +:: +:: Post-build auto-deploy script +:: Create and fill PublishPath.txt file with path to deployment folder +:: I.e. PublishPath.txt should contain one line with a folder path +:: Call it so: +:: IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") +:: + +SET targetDir=%~1 +SET targetName=%~2 +SET targetExt=%~3 +SET projectDir=%~4 +SET destination= + +IF NOT EXIST "%projectDir%\PublishPath.txt" ( + ECHO No deployment path specified. Create PublishPath.txt near PostBuild.bat with paths on separate lines for auto deployment. + exit /B 0 +) + +FOR /f "tokens=* delims= usebackq" %%a IN ("%projectDir%\PublishPath.txt") DO ( + ECHO Deploying to: %%a + IF NOT "%%a" == "" ( + copy /Y "%targetDir%%targetName%%targetExt%" "%%a" + IF NOT ERRORLEVEL 1 ( + IF EXIST "%targetDir%%targetName%.pdb" ( + copy /Y "%targetDir%%targetName%.pdb" "%%a" + ) + ) ELSE ( + ECHO PostBuild.bat ^(27^) : warning : Can't copy '%targetName%%targetExt%' to deploy path '%%a' + ) + ) +) + +IF "%%a" == "" ( + ECHO No deployment path specified. +) + +exit /B 0 \ No newline at end of file diff --git a/rehlds/HLTV/Core/src/BSPModel.cpp b/rehlds/HLTV/Core/src/BSPModel.cpp new file mode 100644 index 0000000..8b27804 --- /dev/null +++ b/rehlds/HLTV/Core/src/BSPModel.cpp @@ -0,0 +1,1163 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +void BSPModel::Init(IBaseSystem *system) +{ + m_System = system; + m_visframecount = 0; + m_currentLeaf = nullptr; + m_base = nullptr; + m_wadpath = nullptr; + + memset(&m_model, 0, sizeof(m_model)); + memset(m_novis, 0xFF, sizeof(m_novis)); +} + +bool BSPModel::Load(const char *name, bool minimal) +{ + int length; + unsigned int *buffer = (unsigned int *)m_System->LoadFile(name, &length); + if (!buffer) { + return false; + } + + return LoadFromBuffer(buffer, length, COM_SkipPath((char *)name)); +} + +void BSPModel::LoadLeafs(lump_t *l) +{ + dleaf_t *in; + mleaf_t *out; + int i, j, count, p; + + in = (dleaf_t *)(m_base + l->fileofs); + if (l->filelen % sizeof(*in)) { + m_System->Errorf("BSPModel::LoadLeafs: funny lump size in %s\n", m_model.name); + } + + count = l->filelen / sizeof(*in); + out = (mleaf_t *)Mem_ZeroMalloc(count * sizeof(*out)); + + if (!out) { + m_System->Errorf("BSPModel::LoadLeafs: not enough memory to load leafs from %s\n", m_model.name); + } + + m_model.leafs = out; + m_model.numleafs = count; + + for (i = 0; i < count; i++, in++, out++) + { + for (j = 0; j < 3; j++) + { + out->minmaxs[j] = _LittleShort(in->mins[j]); + out->minmaxs[3 + j] = _LittleShort(in->maxs[j]); + } + + out->contents = _LittleLong(in->contents); + out->firstmarksurface = m_model.marksurfaces + _LittleShort(in->firstmarksurface); + out->nummarksurfaces = _LittleShort(in->nummarksurfaces); + + p = _LittleLong(in->visofs); + if (p == -1) + out->compressed_vis = nullptr; + else + out->compressed_vis = m_model.visdata + p; + + out->efrags = nullptr; + + for (j = 0; j < 4; j++) { + out->ambient_sound_level[j] = in->ambient_level[j]; + } + } +} + +void BSPModel::LoadNodes(lump_t *l) +{ + int i, j, count, p; + dnode_t *in; + mnode_t *out; + + in = (dnode_t *)(m_base + l->fileofs); + if (l->filelen % sizeof(*in)) { + m_System->Errorf("BSPModel::LoadNodes: funny lump size in %s\n", m_model.name); + } + + count = l->filelen / sizeof(*in); + out = (mnode_t *)Mem_ZeroMalloc(count * sizeof(*out)); + if (!out) { + m_System->Errorf("BSPModel::LoadNodes: not enough memory to load nodes from %s\n", m_model.name); + return; + } + + m_model.nodes = out; + m_model.numnodes = count; + + for (i = 0; i < count; i++, in++, out++) + { + for (j = 0; j < 3; j++) + { + out->minmaxs[j] = _LittleShort(in->mins[j]); + out->minmaxs[3 + j] = _LittleShort(in->maxs[j]); + } + + out->plane = m_model.planes + _LittleLong(in->planenum); + out->firstsurface = _LittleShort(in->firstface); + out->numsurfaces = _LittleShort(in->numfaces); + + for (j = 0; j < 2; j++) + { + p = _LittleShort(in->children[j]); + if (p >= 0) + out->children[j] = m_model.nodes + p; + else + out->children[j] = (mnode_t *)(m_model.leafs + (-1 - p)); + } + } + + if (count) { + // sets nodes and leafs + SetParent(m_model.nodes, nullptr); + } +} + +void BSPModel::SetParent(mnode_t *node, mnode_t *parent) +{ + node->parent = parent; + if (node->contents < 0) + return; + + SetParent(node->children[0], node); + SetParent(node->children[1], node); +} + +byte *BSPModel::LeafPVS(mleaf_t *leaf) +{ + if (leaf == m_model.leafs) { + return m_novis; + } + + return DecompressVis(leaf->compressed_vis); +} + +byte *BSPModel::DecompressVis(unsigned char *in) +{ + static unsigned char decompressed[MODEL_MAX_PVS]; + if (in == nullptr) { + return m_novis; + } + + int row = (m_model.numleafs + 7) / 8; + if (row < 0 || row > MODEL_MAX_PVS) { + m_System->Errorf("BSPModel::DecompressVis: oversized m_model.numleafs: %i\n", m_model.numleafs); + } + + DecompressPVS(in, decompressed, row); + return decompressed; +} + +void BSPModel::DecompressPVS(unsigned char *in, unsigned char *decompressed, int byteCount) +{ + int c; + unsigned char *out; + + if (in == nullptr) + { + // Make all visible + memcpy(decompressed, m_novis, byteCount); + return; + } + + out = decompressed; + while (out < decompressed + byteCount) + { + // Non zero is not copmpressed + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; // TODO: Check that input buffer is correct (last byte on the buffer could be zero and we will go out of the buffer - check the model) + in += 2; + + // Prevent buffer overrun + if (c > decompressed + byteCount - out) + { + c = decompressed + byteCount - out; + } + + // Unpack zeros + memset(out, 0, c); + out += c; + } +} + +mleaf_t *BSPModel::PointInLeaf(vec_t *point) +{ + mnode_t *node; + float d; + mplane_t *plane; + + if (!m_model.nodes) { + m_System->Errorf("BSPModel::PointInLeaf: bad model, no leafs.\n"); + return nullptr; + } + + node = m_model.nodes; + while (node->contents >= 0) + { + plane = node->plane; + if (plane->type >= 3u) + d = DotProduct(plane->normal, point) - plane->dist; + else + d = point[plane->type] - plane->dist; + + node = node->children[(d <= 0) ? 1 : 0]; + } + + return (mleaf_t *)node; +} + +void BSPModel::PVSMark(unsigned char *ppvs) +{ + m_visframecount++; + + for (int i = 0; i < m_model.numleafs - 1; i++) + { + if ((1 << (i & 7)) & ppvs[i >> 3]) + { + mnode_t *node = (mnode_t *)&m_model.leafs[i + 1]; + do + { + if (node->visframe == m_visframecount) + break; + + node->visframe = m_visframecount; + node = node->parent; + } + while (node); + } + } +} + +mnode_t *BSPModel::PVSNode(mnode_t *node, vec_t *emins, vec_t *emaxs) +{ + mplane_t *splitplane; + int sides; + mnode_t *splitNode; + + if (node->visframe != m_visframecount) { + return nullptr; + } + + if (node->contents < 0) { + return node->contents != CONTENTS_SOLID ? node : nullptr; + } + + splitplane = node->plane; + if (splitplane->type >= 3) + { + sides = BoxOnPlaneSide(emins, emaxs, splitplane); + } + else + { + if (splitplane->dist > emins[splitplane->type]) + { + if (splitplane->dist < emaxs[splitplane->type]) + sides = 3; + else + sides = 2; + } + else + { + sides = 1; + } + } + + if (sides & 1) + { + splitNode = PVSNode(node->children[0], emins, emaxs); + if (splitNode) + return splitNode; + } + + if (sides & 2) { + return PVSNode(node->children[1], emins, emaxs); + } + + return nullptr; +} + +void BSPModel::LoadPlanes(lump_t *l) +{ + int i, j; + mplane_t *out; + dplane_t *in; + int count; + int bits; + + in = (dplane_t *)(m_base + l->fileofs); + if (l->filelen % sizeof(*in)) { + m_System->Errorf("BSPModel::LoadPlanes: funny lump size in %s\n", m_model.name); + return; + } + + count = l->filelen / sizeof(*in); + out = (mplane_t *)Mem_ZeroMalloc(count * 2 * sizeof(*out)); + if (!out) { + m_System->Errorf("BSPModel::LoadPlanes: not enough memory to load planes from %s\n", m_model.name); + return; + } + + m_model.planes = out; + m_model.numplanes = count; + + for (i = 0; i < count; i++, in++, out++) + { + bits = 0; + for (j = 0; j < 3; j++) + { + out->normal[j] = _LittleFloat(in->normal[j]); + if (out->normal[j] < 0) { + bits |= (1 << j); + } + } + + out->dist = _LittleFloat(in->dist); + out->type = _LittleLong(in->type); + out->signbits = bits; + } +} + +void BSPModel::LoadVisibility(lump_t *l) +{ + if (!l->filelen) + { + m_model.visdata = nullptr; + return; + } + + m_model.visdata = (byte *)Mem_ZeroMalloc(l->filelen); + if (!m_model.visdata) { + m_System->Errorf("BSPModel::LoadPlanes: not enough memory to load planes from %s\n", m_model.name); + return; + } + + memcpy(m_model.visdata, m_base + l->fileofs, l->filelen); +} + +bool BSPModel::IsValid() +{ + return m_model.name[0] != '\0'; +} + +void BSPModel::SetPVS(vec_t *point) +{ + unsigned char *ppvs; + mleaf_t *pleaf = PointInLeaf(point); + + if (m_currentLeaf != pleaf) + { + ppvs = LeafPVS(pleaf); + + PVSMark(ppvs); + m_currentLeaf = pleaf; + } +} + +bool BSPModel::InPVS(vec_t *point) +{ + vec3_t mins, maxs; + for (int i = 0; i < 3; i++) + { + mins[i] = point[i] - 32; + maxs[i] = point[i] + 32; + } + + if (PVSNode(m_model.nodes, mins, maxs)) { + return true; + } + + return false; +} + +void BSPModel::Clear() +{ + #define FREE_FIELD(field) if (field) { free(field); } + + FREE_FIELD(m_model.leafs); + FREE_FIELD(m_model.nodes); + FREE_FIELD(m_model.planes); + FREE_FIELD(m_model.visdata); + FREE_FIELD(m_model.vertexes); + FREE_FIELD(m_model.entities); + FREE_FIELD(m_model.edges); + FREE_FIELD(m_model.lightdata); + FREE_FIELD(m_model.surfedges); + FREE_FIELD(m_model.surfaces); + FREE_FIELD(m_model.marksurfaces); + FREE_FIELD(m_model.clipnodes); + FREE_FIELD(m_model.hulls[0].clipnodes); + FREE_FIELD(m_model.texinfo); + + if (m_model.textures) + { + for (int i = 0; i < m_model.numtextures; ++i) { + FREE_FIELD(m_model.textures[i]); + } + + FREE_FIELD(m_model.textures); + } + + FREE_FIELD(m_wadpath); + + memset(&m_model, 0, sizeof(m_model)); + + m_visframecount = 0; + m_wadpath = nullptr; + m_currentLeaf = nullptr; +} + +void BSPModel::GetDimension(vec_t *min, vec_t *max) +{ + min[0] = MAX_WORLD_SIZE; + min[1] = MAX_WORLD_SIZE; + min[2] = MAX_WORLD_SIZE; + + max[0] = -MAX_WORLD_SIZE; + max[1] = -MAX_WORLD_SIZE; + max[2] = -MAX_WORLD_SIZE; + + for (int i = 0; i < m_model.numvertexes; i++) + { + vec3_t v; + VectorCopy(m_model.vertexes[i].position, v); + + if (v[0] > max[0]) max[0] = v[0]; + if (v[1] > max[1]) max[1] = v[1]; + if (v[2] > max[2]) max[2] = v[2]; + if (v[0] < min[0]) min[0] = v[0]; + if (v[1] < min[1]) min[1] = v[1]; + if (v[2] < min[2]) min[2] = v[2]; + } +} + +void BSPModel::LoadVertexes(lump_t *l) +{ + dvertex_t *in; + mvertex_t *out; + int i, count; + + in = (dvertex_t *)(m_base + l->fileofs); + if (l->filelen % sizeof(*in)) { + m_System->Errorf("BSPModel::LoadVertexes: funny lump size in %s\n", m_model.name); + } + + count = l->filelen / sizeof(*in); + out = (mvertex_t *)Mem_ZeroMalloc(count * sizeof(*out)); + + m_model.vertexes = out; + m_model.numvertexes = count; + + for (i = 0; i < count; i++, in++, out++) + { + out->position[0] = _LittleFloat(in->point[0]); + out->position[1] = _LittleFloat(in->point[1]); + out->position[2] = _LittleFloat(in->point[2]); + } +} + +void BSPModel::MakeHull0() +{ + mnode_t *in, *child; + dclipnode_t *out; + int i, j, count; + hull_t *hull; + + hull = &m_model.hulls[0]; + + in = m_model.nodes; + count = m_model.numnodes; + out = (dclipnode_t *)Mem_ZeroMalloc(count * sizeof(*out)); + + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count - 1; + hull->planes = m_model.planes; + + for (i = 0; i < count; i++, out++, in++) + { + out->planenum = in->plane - m_model.planes; + for (j = 0; j < 2; j++) + { + child = in->children[j]; + if (child->contents < 0) + out->children[j] = child->contents; + else + out->children[j] = child - m_model.nodes; + } + } +} + +bool BSPModel::TraceLine(vec_t *start, vec_t *end, vec_t *impact) +{ + trace_t trace; + memset(&trace, 0, sizeof(trace)); + auto res = RecursiveHullCheck(m_model.hulls, 0, 0, 1, start, end, &trace); + VectorCopy(trace.endpos, impact); + return res; +} + +bool BSPModel::RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, vec_t *p1, vec_t *p2, trace_t *trace) +{ + int i; + dclipnode_t *node; + mplane_t *plane; + float t2; + vec3_t mid; + float frac; + float t1; + int side; + float midf; + float pdif = p2f - p1f; + + float DIST_EPSILON = 0.03125f; + + if (num >= 0) + { + if (num < hull->firstclipnode || num > hull->lastclipnode || !hull->planes) { + m_System->Errorf("BSPModel::RecursiveHullCheck: bad node number\n"); + } + + node = &hull->clipnodes[num]; + plane = &hull->planes[hull->clipnodes[num].planenum]; + if (plane->type >= 3) + { + t1 = DotProduct(p1, plane->normal) - plane->dist; + t2 = DotProduct(p2, plane->normal) - plane->dist; + } + else + { + t1 = p1[plane->type] - plane->dist; + t2 = p2[plane->type] - plane->dist; + } + + if (t1 >= 0.0f && t2 >= 0.0f) { + return RecursiveHullCheck(hull, node->children[0], p1f, p2f, p1, p2, trace); + } + + if (t1 >= 0.0f) + { + midf = t1 - DIST_EPSILON; + } + else + { + if (t2 < 0.0f) { + return RecursiveHullCheck(hull, node->children[1], p1f, p2f, p1, p2, trace); + } + + midf = t1 + DIST_EPSILON; + } + + midf = midf / (t1 - t2); + midf = clamp(midf, 0.0f, 1.0f); + + // not a number + if (!IS_NAN(midf)) + { + frac = pdif * midf + p1f; + for (i = 0; i < 3; i++) { + mid[i] = (p2[i] - p1[i]) * midf + p1[i]; + } + side = (t1 < 0.0f) ? 1 : 0; + + if (RecursiveHullCheck(hull, node->children[side], p1f, frac, p1, mid, trace)) + { + if (HullPointContents(hull, node->children[side ^ 1], mid) != CONTENTS_SOLID) { + return RecursiveHullCheck(hull, node->children[side ^ 1], frac, p2f, mid, p2, trace); + } + + if (!trace->allsolid) + { + if (side) + { + VectorSubtract(vec3_origin, plane->normal, trace->plane.normal); + trace->plane.dist = -plane->dist; + } + else + { + VectorCopy(plane->normal, trace->plane.normal); + trace->plane.dist = plane->dist; + } + + while (HullPointContents(hull, hull->firstclipnode, mid) == CONTENTS_SOLID) + { + midf -= 0.1f; + if (midf < 0.0f) + { + trace->fraction = frac; + VectorCopy(mid, trace->endpos); + m_System->Printf("BSPModel::RecursiveHullCheck: backup past 0\n"); + return false; + } + + frac = pdif * midf + p1f; + for (i = 0; i < 3; i++) { + mid[i] = (p2[i] - p1[i]) * midf + p1[i]; + } + } + + trace->fraction = frac; + VectorCopy(mid, trace->endpos); + m_System->Printf("BSPModel::RecursiveHullCheck: backup past 0\n"); + return false; + } + } + } + + return false; + } + + if (num == CONTENTS_SOLID) + { + trace->startsolid = TRUE; + } + else + { + trace->allsolid = FALSE; + if (num == CONTENTS_EMPTY) + { + trace->inopen = TRUE; + } + + else if (num != CONTENTS_TRANSLUCENT) + { + trace->inwater = TRUE; + } + } + + return true; +} + +int BSPModel::HullPointContents(hull_t *hull, int num, const vec_t *point) +{ + float d; + dclipnode_t *node; + mplane_t *plane; + + while (num >= 0) + { + if (num < hull->firstclipnode || num > hull->lastclipnode) { + m_System->Errorf("BSPModel::HullPointContents: bad node number\n"); + } + + node = &hull->clipnodes[num]; + plane = &hull->planes[node->planenum]; + + if (plane->type >= 3) + d = DotProduct(point, plane->normal) - plane->dist; + else + d = point[plane->type] - plane->dist; + + num = node->children[(d < 0) ? 1 : 0]; + } + + return num; +} + +bool BSPModel::LoadFromBuffer(unsigned int *buffer, int length, const char *name) +{ + dheader_t *header; + int i; + + Clear(); + strcopy(m_model.name, name); + + m_System->DPrintf("Loading model: %s (%i kB)\n", name, length / 1024); + m_model.needload = NL_PRESENT; + + // call the apropriate loader + switch (_LittleLong(*(uint32 *)buffer)) + { + case IDPOLYHEADER: // old-format of the model from the quake1 + case IDSPRITEHEADER: + case IDSTUDIOHEADER: + m_System->Printf("ERROR! BSPModel::Load: only .BSP models supported.\n"); + if (buffer) { + m_System->FreeFile((unsigned char *)buffer); + } + return false; + default: + break; + } + + m_model.type = mod_brush; + header = (dheader_t *)buffer; + + i = _LittleLong(header->version); + if (i != HLBSP_VERSION) { + m_System->Errorf("BSPModel::LoadFromBuffer: %s has wrong version number (%i should be %i)\n", m_model.name, i, HLBSP_VERSION); + } + + // swap all the lumps + m_base = (byte *)header; + + for (i = 0; i < sizeof(dheader_t) / 4; i++) { + ((int *)header)[i] = _LittleLong(((int *)header)[i]); + } + + // load into heap + if (!m_IsMinimal) + { + LoadVertexes(&header->lumps[LUMP_VERTEXES]); + LoadEdges(&header->lumps[LUMP_EDGES]); + LoadSurfedges(&header->lumps[LUMP_SURFEDGES]); + LoadEntities(&header->lumps[LUMP_ENTITIES]); + LoadTextures(&header->lumps[LUMP_TEXTURES]); + LoadLighting(&header->lumps[LUMP_LIGHTING]); + } + + LoadPlanes(&header->lumps[LUMP_PLANES]); + if (!m_IsMinimal) + { + LoadTexinfo(&header->lumps[LUMP_TEXINFO]); + LoadFaces(&header->lumps[LUMP_FACES]); + LoadMarksurfaces(&header->lumps[LUMP_MARKSURFACES]); + } + + LoadVisibility(&header->lumps[LUMP_VISIBILITY]); + LoadLeafs(&header->lumps[LUMP_LEAFS]); + LoadNodes(&header->lumps[LUMP_NODES]); + + if (!m_IsMinimal) + { + LoadClipnodes(&header->lumps[LUMP_CLIPNODES]); + } + + MakeHull0(); + + // regular and alternate animation + m_model.numframes = 2; + m_model.flags = 0; + + m_System->FreeFile((unsigned char *)buffer); + return true; +} + +bool BSPModel::IsMinimal() +{ + return m_IsMinimal; +} + +void BSPModel::LoadEdges(lump_t *l) +{ + dedge_t *in; + medge_t *out; + int i, count; + + in = (dedge_t *)(m_base + l->fileofs); + if (l->filelen % sizeof(*in)) { + m_System->Errorf("BSPModel::LoadEdges funny lump size in %s\n", m_model.name); + } + + count = l->filelen / sizeof(*in); + out = (medge_t *)Mem_ZeroMalloc((count + 1) * sizeof(*out)); + + m_model.edges = out; + m_model.numedges = count; + + for (i = 0; i < count; i++, in++, out++) + { + out->v[0] = (unsigned short)_LittleShort(in->v[0]); + out->v[1] = (unsigned short)_LittleShort(in->v[1]); + } +} + +void BSPModel::LoadSurfedges(lump_t *l) +{ + int i, count; + int *in, *out; + + in = (int *)(m_base + l->fileofs); + if (l->filelen % sizeof(*in)) { + m_System->Errorf("BSPModel::LoadSurfedges; funny lump size in %s\n", m_model.name); + } + + count = l->filelen / sizeof(*in); + out = (int *)Mem_ZeroMalloc(count * sizeof(*out)); + + m_model.surfedges = out; + m_model.numsurfedges = count; + + for (i = 0; i < count; i++) { + out[i] = _LittleLong(in[i]); + } +} + +void BSPModel::LoadEntities(lump_t *l) +{ + if (!l->filelen) { + m_model.entities = nullptr; + return; + } + + m_model.entities = (char *)Mem_ZeroMalloc(l->filelen); + memcpy(m_model.entities, (const void *)(m_base + l->fileofs), l->filelen); + + if (m_model.entities) + { + char *pszInputStream = COM_Parse(m_model.entities); + if (*pszInputStream) + { + while (com_token[0] != '}') + { + if (!strcmp(com_token, "wad")) + { + COM_Parse(pszInputStream); + if (m_wadpath) { + free(m_wadpath); + } + + m_wadpath = _strdup(com_token); + return; + } + + pszInputStream = COM_Parse(pszInputStream); + if (!*pszInputStream) + return; + } + } + } +} + +void BSPModel::LoadLighting(lump_t *l) +{ + if (l->filelen) + { + m_model.lightdata = (color24 *)Mem_ZeroMalloc(l->filelen); + memcpy(m_model.lightdata, (const void *)(m_base + l->fileofs), l->filelen); + } + else + { + m_model.lightdata = nullptr; + } +} + +void BSPModel::LoadFaces(lump_t *l) +{ + dface_t *in; + msurface_t *out; + int i, count, surfnum; + int planenum, side; + + in = (dface_t *)(m_base + l->fileofs); + if (l->filelen % sizeof(*in)) { + m_System->Errorf("BSPModel::LoadFaces: funny lump size in %s\n", m_model.name); + } + + count = l->filelen / sizeof(*in); + out = (msurface_t *)Mem_ZeroMalloc(count * sizeof(*out)); + + m_model.surfaces = out; + m_model.numsurfaces = count; + + for (surfnum = 0; surfnum < count; surfnum++, in++, out++) + { + out->firstedge = _LittleLong(in->firstedge); + out->numedges = _LittleShort(in->numedges); + out->flags = 0; + out->pdecals = nullptr; + + planenum = _LittleShort(in->planenum); + side = _LittleShort(in->side); + if (side) { + out->flags |= SURF_PLANEBACK; + } + + out->plane = m_model.planes + planenum; + out->texinfo = m_model.texinfo + _LittleShort(in->texinfo); + + // lighting info + for (i = 0; i < MAXLIGHTMAPS; i++) { + out->styles[i] = in->styles[i]; + } + + i = _LittleLong(in->lightofs); + if (i == -1) + out->samples = nullptr; + else + out->samples = m_model.lightdata + i; + + if (out->texinfo->texture) + { + // set the drawing flags flag + const char *texName = out->texinfo->texture->name; + if (!strncmp(texName, "sky", 3)) { + out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); + continue; + } + + if (!strncmp(texName, "aaatrigger", 10)) { + out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); + continue; + } + } + } +} + +void BSPModel::LoadMarksurfaces(lump_t *l) +{ + int i, j, count; + short *in; + msurface_t **out; + + in = (short *)(m_base + l->fileofs); + if (l->filelen % sizeof(*in)) { + m_System->Errorf("BSPModel::LoadMarksurfaces: funny lump size in %s\n", m_model.name); + } + + count = l->filelen / sizeof(*in); + out = (msurface_t **)Mem_ZeroMalloc(count * sizeof(*out)); + + m_model.marksurfaces = out; + m_model.nummarksurfaces = count; + + for (i = 0; i < count; i++) + { + j = _LittleShort(in[i]); + if (j >= m_model.numsurfaces) { + m_System->Errorf("BSPModel::LoadMarksurfaces: bad surface number\n"); + } + + out[i] = m_model.surfaces + j; + } +} + +void BSPModel::LoadClipnodes(lump_t *l) +{ + dclipnode_t *in, *out; + int i, count; + hull_t *hull; + + in = (dclipnode_t *)(m_base + l->fileofs); + if (l->filelen % sizeof(*in)) { + m_System->Errorf("BSPModel::LoadClipnodes: funny lump size in %s\n", m_model.name); + } + + count = l->filelen / sizeof(*in); + out = (dclipnode_t *)Mem_ZeroMalloc(count * sizeof(*out)); + + m_model.clipnodes = out; + m_model.numclipnodes = count; + + hull = &m_model.hulls[1]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count - 1; + hull->planes = m_model.planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -36; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 36; + + hull = &m_model.hulls[2]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count - 1; + hull->planes = m_model.planes; + hull->clip_mins[0] = -32; + hull->clip_mins[1] = -32; + hull->clip_mins[2] = -32; + hull->clip_maxs[0] = 32; + hull->clip_maxs[1] = 32; + hull->clip_maxs[2] = 32; + + hull = &m_model.hulls[3]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count - 1; + hull->planes = m_model.planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -18; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 18; + + for (i = 0; i < count; i++, out++, in++) + { + out->planenum = _LittleLong(in->planenum); + out->children[0] = _LittleShort(in->children[0]); + out->children[1] = _LittleShort(in->children[1]); + } +} + +int BSPModel::TruePointContents(vec_t *point) +{ + hull_t *hull = &m_model.hulls[0]; + if (hull->firstclipnode >= hull->lastclipnode) { + return CONTENTS_EMPTY; + } + + return HullPointContents(hull, hull->firstclipnode, point); +} + +void BSPModel::LoadTexinfo(lump_t *l) +{ + texinfo_t *in; + mtexinfo_t *out; + int i, j, count; + int miptex; + float len1, len2; + + in = (texinfo_t *)(m_base + l->fileofs); + if (l->filelen % sizeof(*in)) { + m_System->Errorf("BSPModel::LoadTexinfo: funny lump size in %s\n", m_model.name); + } + + count = l->filelen / sizeof(*in); + out = (mtexinfo_t *)Mem_ZeroMalloc(count * sizeof(*out)); + + if (!out) { + m_System->Errorf("BSPModel::LoadTexinfo: not enough memory to load planes from %s\n", m_model.name); + return; + } + + m_model.texinfo = out; + m_model.numtexinfo = count; + + for (i = 0; i < count; i++, in++, out++) + { + for (j = 0; j < 4; j++) + { + out->vecs[0][j] = _LittleFloat(in->vecs[0][j]); + out->vecs[1][j] = _LittleFloat(in->vecs[1][j]); + } + + len1 = Length(out->vecs[0]); + len2 = Length(out->vecs[1]); + len1 = (len1 + len2) / 2; + + if (len1 < 0.32) + out->mipadjust = 4; + else if (len1 < 0.49) + out->mipadjust = 3; + else if (len1 < 0.99) + out->mipadjust = 2; + else + out->mipadjust = 1; + + miptex = _LittleLong(in->_miptex); + out->flags = _LittleLong(in->flags); + + if (!m_model.textures) + { + out->texture = nullptr; + out->flags = 0; + } + else + { + if (miptex >= m_model.numtextures) { + m_System->Errorf("BSPModel::LoadTexinfo: miptex >= m_model.numtextures\n"); + return; + } + + out->texture = m_model.textures[miptex]; + if (!out->texture) + { + out->texture = nullptr; // texture not found + out->flags = 0; + } + } + } +} + +void BSPModel::LoadTextures(lump_t *l) +{ + int i, j; + int pixels; + + miptex_t *mt; + texture_t *tx; + dmiptexlump_t *m; + + if (!l->filelen) { + m_model.textures = nullptr; + return; + } + + m = (dmiptexlump_t *)(m_base + l->fileofs); + m->_nummiptex = _LittleLong(m->_nummiptex); + + m_model.numtextures = m->_nummiptex; + m_model.textures = (texture_t **)Mem_ZeroMalloc(4 * m->_nummiptex); + + if (!m_model.textures) { + m_System->Errorf("BSPModel::LoadTextures: not enough memory to load planes from %s\n", m_model.name); + return; + } + + for (i = 0; i < m->_nummiptex; i++) + { + m->dataofs[i] = _LittleLong(m->dataofs[i]); + if (m->dataofs[i] == -1) { + continue; + } + + mt = (miptex_t *)((char *)m + m->dataofs[i]); + for (j = 0; j < MIPLEVELS; j++) { + mt->offsets[j] = _LittleLong(mt->offsets[j]); + } + + mt->width = _LittleLong(mt->width); + mt->height = _LittleLong(mt->height); + if ((mt->width & 0xF) || (mt->height & 0xF)) { + m_System->Errorf("BSPModel::LoadTextures: Texture %s is not 16 aligned\n", mt->name); + return; + } + + pixels = (mt->width * mt->height) / 64; + tx = (texture_t *)Mem_ZeroMalloc(85 * pixels + 66); + + m_model.textures[i] = tx; + memcpy(tx->name, mt->name, sizeof(tx->name)); + + if (strchr(tx->name, '~')) { + tx->name[2] = ' '; + } + + tx->width = mt->width; + tx->height = mt->height; + + m_System->Printf("Texture: %s %i,%i\n", tx->name, tx->width, tx->height); + } +} diff --git a/rehlds/HLTV/Core/src/BSPModel.h b/rehlds/HLTV/Core/src/BSPModel.h new file mode 100644 index 0000000..45ea405 --- /dev/null +++ b/rehlds/HLTV/Core/src/BSPModel.h @@ -0,0 +1,99 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include + +#include "l_studio.h" +#include "edict.h" + +// values for model_t's needload +#define NL_PRESENT 0 +#define NL_NEEDS_LOADED 1 +#define NL_UNREFERENCED 2 + +const int MAX_WORLD_SIZE = 32000; + +class IBaseSystem; +class BSPModel: public IBSPModel { +public: + BSPModel() {} + virtual ~BSPModel() {} + + void Init(IBaseSystem *system); + void Clear(); + bool Load(const char *name, bool minimal); + bool IsValid(); + bool IsMinimal(); + void SetPVS(vec_t *point); + bool InPVS(vec_t *point); + bool TraceLine(vec_t *start, vec_t *end, vec_t *impact); + int TruePointContents(vec_t *point); + +private: + void LoadTextures(lump_t *l); + void LoadEdges(lump_t *l); + bool LoadFromBuffer(unsigned int *buffer, int length, const char *name); + void LoadLeafs(lump_t *l); + void LoadNodes(lump_t *l); + void LoadVisibility(lump_t *l); + void LoadPlanes(lump_t *l); + void LoadVertexes(lump_t *l); + void LoadTexinfo(lump_t *l); + void LoadClipnodes(lump_t *l); + void LoadMarksurfaces(lump_t *l); + void LoadFaces(lump_t *l); + void LoadLighting(lump_t *l); + void LoadEntities(lump_t *l); + void LoadSurfedges(lump_t *l); + int HullPointContents(hull_t *hull, int num, const vec_t *point); + bool RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, vec_t *p1, vec_t *p2, trace_t *trace); + void MakeHull0(); + mleaf_t *PointInLeaf(vec_t *point); + void GetDimension(vec_t *min, vec_t *max); + mnode_t *PVSNode(mnode_t *node, vec_t *emins, vec_t *emaxs); + void PVSMark(unsigned char *ppvs); + unsigned char *LeafPVS(mleaf_t *leaf); + void DecompressPVS(unsigned char *in, unsigned char *decompressed, int byteCount); + unsigned char *DecompressVis(unsigned char *in); + void SetParent(mnode_t *node, mnode_t *parent); + +protected: + model_t m_model; + + enum { MODEL_MAX_PVS = 1024 }; + byte m_novis[MODEL_MAX_PVS]; + byte *m_base; + + int m_visframecount; + mleaf_t *m_currentLeaf; + bool m_IsMinimal; + char *m_wadpath; + IBaseSystem *m_System; +}; diff --git a/rehlds/HLTV/Core/src/Delta.cpp b/rehlds/HLTV/Core/src/Delta.cpp new file mode 100644 index 0000000..0c566d0 --- /dev/null +++ b/rehlds/HLTV/Core/src/Delta.cpp @@ -0,0 +1,1514 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#ifndef HOOK_HLTV + +delta_t *Delta::m_EntityDelta = nullptr; +delta_t *Delta::m_PlayerDelta = nullptr; +delta_t *Delta::m_ClientDelta = nullptr; +delta_t *Delta::m_WeaponDelta = nullptr; +delta_t *Delta::m_EventDelta = nullptr; +delta_t *Delta::m_CustomentityDelta = nullptr; + +#define DELTA_D_DEF(member) #member, offsetof(delta_description_s, member) +#define DELTA_DEF(structname, member) { #member, offsetof(structname, member) } + +delta_description_t Delta::m_MetaDescription[] = +{ + { DT_INTEGER, DELTA_D_DEF(fieldType), 1, 32, 1.0, 1.0, 0, 0, 0 }, + { DT_STRING, DELTA_D_DEF(fieldName), 1, 1, 1.0, 1.0, 0, 0, 0 }, + { DT_INTEGER, DELTA_D_DEF(fieldOffset), 1, 16, 1.0, 1.0, 0, 0, 0 }, + { DT_INTEGER, DELTA_D_DEF(fieldSize), 1, 8, 1.0, 1.0, 0, 0, 0 }, + { DT_INTEGER, DELTA_D_DEF(significant_bits), 1, 8, 1.0, 1.0, 0, 0, 0 }, + { DT_FLOAT, DELTA_D_DEF(premultiply), 1, 32, 4000.0, 1.0, 0, 0, 0 }, + { DT_FLOAT, DELTA_D_DEF(postmultiply), 1, 32, 4000.0, 1.0, 0, 0, 0 }, +}; + +delta_t Delta::m_MetaDelta[] = +{ + { 0, ARRAYSIZE(Delta::m_MetaDescription), "", nullptr, Delta::m_MetaDescription }, +}; + +Delta::delta_definition_t Delta::m_DeltaDataDefinition[] = +{ + DELTA_DEF(delta_description_s, fieldType), + DELTA_DEF(delta_description_s, fieldName), + DELTA_DEF(delta_description_s, fieldOffset), + DELTA_DEF(delta_description_s, fieldSize), + DELTA_DEF(delta_description_s, significant_bits), + DELTA_DEF(delta_description_s, premultiply), + DELTA_DEF(delta_description_s, postmultiply), + DELTA_DEF(delta_description_s, flags), +}; + +Delta::delta_definition_t Delta::m_EventDataDefinition[] = +{ + DELTA_DEF(event_args_s, entindex), + DELTA_DEF(event_args_s, origin[0]), + DELTA_DEF(event_args_s, origin[1]), + DELTA_DEF(event_args_s, origin[2]), + DELTA_DEF(event_args_s, angles[0]), + DELTA_DEF(event_args_s, angles[1]), + DELTA_DEF(event_args_s, angles[2]), + DELTA_DEF(event_args_s, fparam1), + DELTA_DEF(event_args_s, fparam2), + DELTA_DEF(event_args_s, iparam1), + DELTA_DEF(event_args_s, iparam2), + DELTA_DEF(event_args_s, bparam1), + DELTA_DEF(event_args_s, bparam2), + DELTA_DEF(event_args_s, ducking), +}; + +Delta::delta_definition_t Delta::m_EntityDataDefinition[] = +{ + DELTA_DEF(entity_state_s, startpos[0]), + DELTA_DEF(entity_state_s, startpos[1]), + DELTA_DEF(entity_state_s, startpos[2]), + DELTA_DEF(entity_state_s, endpos[0]), + DELTA_DEF(entity_state_s, endpos[1]), + DELTA_DEF(entity_state_s, endpos[2]), + DELTA_DEF(entity_state_s, impacttime), + DELTA_DEF(entity_state_s, starttime), + DELTA_DEF(entity_state_s, origin[0]), + DELTA_DEF(entity_state_s, origin[1]), + DELTA_DEF(entity_state_s, origin[2]), + DELTA_DEF(entity_state_s, angles[0]), + DELTA_DEF(entity_state_s, angles[1]), + DELTA_DEF(entity_state_s, angles[2]), + DELTA_DEF(entity_state_s, modelindex), + DELTA_DEF(entity_state_s, frame), + DELTA_DEF(entity_state_s, movetype), + DELTA_DEF(entity_state_s, colormap), + DELTA_DEF(entity_state_s, skin), + DELTA_DEF(entity_state_s, solid), + DELTA_DEF(entity_state_s, scale), + DELTA_DEF(entity_state_s, effects), + DELTA_DEF(entity_state_s, sequence), + DELTA_DEF(entity_state_s, animtime), + DELTA_DEF(entity_state_s, framerate), + DELTA_DEF(entity_state_s, controller[0]), + DELTA_DEF(entity_state_s, controller[1]), + DELTA_DEF(entity_state_s, controller[2]), + DELTA_DEF(entity_state_s, controller[3]), + DELTA_DEF(entity_state_s, blending[0]), + DELTA_DEF(entity_state_s, blending[1]), + DELTA_DEF(entity_state_s, body), + DELTA_DEF(entity_state_s, owner), + DELTA_DEF(entity_state_s, rendermode), + DELTA_DEF(entity_state_s, renderamt), + DELTA_DEF(entity_state_s, renderfx), + DELTA_DEF(entity_state_s, rendercolor.r), + DELTA_DEF(entity_state_s, rendercolor.g), + DELTA_DEF(entity_state_s, rendercolor.b), + DELTA_DEF(entity_state_s, weaponmodel), + DELTA_DEF(entity_state_s, gaitsequence), + DELTA_DEF(entity_state_s, mins[0]), + DELTA_DEF(entity_state_s, mins[1]), + DELTA_DEF(entity_state_s, mins[2]), + DELTA_DEF(entity_state_s, maxs[0]), + DELTA_DEF(entity_state_s, maxs[1]), + DELTA_DEF(entity_state_s, maxs[2]), + DELTA_DEF(entity_state_s, aiment), + DELTA_DEF(entity_state_s, basevelocity[0]), + DELTA_DEF(entity_state_s, basevelocity[1]), + DELTA_DEF(entity_state_s, basevelocity[2]), + DELTA_DEF(entity_state_s, friction), + DELTA_DEF(entity_state_s, gravity), + DELTA_DEF(entity_state_s, spectator), + DELTA_DEF(entity_state_s, velocity[0]), + DELTA_DEF(entity_state_s, velocity[1]), + DELTA_DEF(entity_state_s, velocity[2]), + DELTA_DEF(entity_state_s, team), + DELTA_DEF(entity_state_s, playerclass), + DELTA_DEF(entity_state_s, health), + DELTA_DEF(entity_state_s, usehull), + DELTA_DEF(entity_state_s, oldbuttons), + DELTA_DEF(entity_state_s, onground), + DELTA_DEF(entity_state_s, iStepLeft), + DELTA_DEF(entity_state_s, flFallVelocity), + DELTA_DEF(entity_state_s, weaponanim), + DELTA_DEF(entity_state_s, eflags), + DELTA_DEF(entity_state_s, iuser1), + DELTA_DEF(entity_state_s, iuser2), + DELTA_DEF(entity_state_s, iuser3), + DELTA_DEF(entity_state_s, iuser4), + DELTA_DEF(entity_state_s, fuser1), + DELTA_DEF(entity_state_s, fuser2), + DELTA_DEF(entity_state_s, fuser3), + DELTA_DEF(entity_state_s, fuser4), + DELTA_DEF(entity_state_s, vuser1[0]), + DELTA_DEF(entity_state_s, vuser1[1]), + DELTA_DEF(entity_state_s, vuser1[2]), + DELTA_DEF(entity_state_s, vuser2[0]), + DELTA_DEF(entity_state_s, vuser2[1]), + DELTA_DEF(entity_state_s, vuser2[2]), + DELTA_DEF(entity_state_s, vuser3[0]), + DELTA_DEF(entity_state_s, vuser3[1]), + DELTA_DEF(entity_state_s, vuser3[2]), + DELTA_DEF(entity_state_s, vuser4[0]), + DELTA_DEF(entity_state_s, vuser4[1]), + DELTA_DEF(entity_state_s, vuser4[2]), +}; + +Delta::delta_definition_t Delta::m_UsercmdDataDefinition[] = +{ + DELTA_DEF(usercmd_s, lerp_msec), + DELTA_DEF(usercmd_s, msec), + DELTA_DEF(usercmd_s, lightlevel), + DELTA_DEF(usercmd_s, viewangles[0]), + DELTA_DEF(usercmd_s, viewangles[1]), + DELTA_DEF(usercmd_s, viewangles[2]), + DELTA_DEF(usercmd_s, buttons), + DELTA_DEF(usercmd_s, forwardmove), + DELTA_DEF(usercmd_s, sidemove), + DELTA_DEF(usercmd_s, upmove), + DELTA_DEF(usercmd_s, impulse), + DELTA_DEF(usercmd_s, weaponselect), + DELTA_DEF(usercmd_s, impact_index), + DELTA_DEF(usercmd_s, impact_position[0]), + DELTA_DEF(usercmd_s, impact_position[1]), + DELTA_DEF(usercmd_s, impact_position[2]), +}; + +Delta::delta_definition_t Delta::m_WeaponDataDefinition[] = +{ + DELTA_DEF(weapon_data_s, m_iId), + DELTA_DEF(weapon_data_s, m_iClip), + DELTA_DEF(weapon_data_s, m_flNextPrimaryAttack), + DELTA_DEF(weapon_data_s, m_flNextSecondaryAttack), + DELTA_DEF(weapon_data_s, m_flTimeWeaponIdle), + DELTA_DEF(weapon_data_s, m_fInReload), + DELTA_DEF(weapon_data_s, m_fInSpecialReload), + DELTA_DEF(weapon_data_s, m_flNextReload), + DELTA_DEF(weapon_data_s, m_flPumpTime), + DELTA_DEF(weapon_data_s, m_fReloadTime), + DELTA_DEF(weapon_data_s, m_fAimedDamage), + DELTA_DEF(weapon_data_s, m_fNextAimBonus), + DELTA_DEF(weapon_data_s, m_fInZoom), + DELTA_DEF(weapon_data_s, m_iWeaponState), + DELTA_DEF(weapon_data_s, iuser1), + DELTA_DEF(weapon_data_s, iuser2), + DELTA_DEF(weapon_data_s, iuser3), + DELTA_DEF(weapon_data_s, iuser4), + DELTA_DEF(weapon_data_s, fuser1), + DELTA_DEF(weapon_data_s, fuser2), + DELTA_DEF(weapon_data_s, fuser3), + DELTA_DEF(weapon_data_s, fuser4), +}; + +Delta::delta_definition_t Delta::m_ClientDataDefinition[] = +{ + DELTA_DEF(clientdata_s, origin[0]), + DELTA_DEF(clientdata_s, origin[1]), + DELTA_DEF(clientdata_s, origin[2]), + DELTA_DEF(clientdata_s, velocity[0]), + DELTA_DEF(clientdata_s, velocity[1]), + DELTA_DEF(clientdata_s, velocity[2]), + DELTA_DEF(clientdata_s, viewmodel), + DELTA_DEF(clientdata_s, punchangle[0]), + DELTA_DEF(clientdata_s, punchangle[1]), + DELTA_DEF(clientdata_s, punchangle[2]), + DELTA_DEF(clientdata_s, flags), + DELTA_DEF(clientdata_s, waterlevel), + DELTA_DEF(clientdata_s, watertype), + DELTA_DEF(clientdata_s, view_ofs[0]), + DELTA_DEF(clientdata_s, view_ofs[1]), + DELTA_DEF(clientdata_s, view_ofs[2]), + DELTA_DEF(clientdata_s, health), + DELTA_DEF(clientdata_s, bInDuck), + DELTA_DEF(clientdata_s, weapons), + DELTA_DEF(clientdata_s, flTimeStepSound), + DELTA_DEF(clientdata_s, flDuckTime), + DELTA_DEF(clientdata_s, flSwimTime), + DELTA_DEF(clientdata_s, waterjumptime), + DELTA_DEF(clientdata_s, maxspeed), + DELTA_DEF(clientdata_s, m_iId), + DELTA_DEF(clientdata_s, ammo_nails), + DELTA_DEF(clientdata_s, ammo_shells), + DELTA_DEF(clientdata_s, ammo_cells), + DELTA_DEF(clientdata_s, ammo_rockets), + DELTA_DEF(clientdata_s, m_flNextAttack), + DELTA_DEF(clientdata_s, physinfo), + DELTA_DEF(clientdata_s, fov), + DELTA_DEF(clientdata_s, weaponanim), + DELTA_DEF(clientdata_s, tfstate), + DELTA_DEF(clientdata_s, pushmsec), + DELTA_DEF(clientdata_s, deadflag), + DELTA_DEF(clientdata_s, iuser1), + DELTA_DEF(clientdata_s, iuser2), + DELTA_DEF(clientdata_s, iuser3), + DELTA_DEF(clientdata_s, iuser4), + DELTA_DEF(clientdata_s, fuser1), + DELTA_DEF(clientdata_s, fuser2), + DELTA_DEF(clientdata_s, fuser3), + DELTA_DEF(clientdata_s, fuser4), + DELTA_DEF(clientdata_s, vuser1[0]), + DELTA_DEF(clientdata_s, vuser1[1]), + DELTA_DEF(clientdata_s, vuser1[2]), + DELTA_DEF(clientdata_s, vuser2[0]), + DELTA_DEF(clientdata_s, vuser2[1]), + DELTA_DEF(clientdata_s, vuser2[2]), + DELTA_DEF(clientdata_s, vuser3[0]), + DELTA_DEF(clientdata_s, vuser3[1]), + DELTA_DEF(clientdata_s, vuser3[2]), + DELTA_DEF(clientdata_s, vuser4[0]), + DELTA_DEF(clientdata_s, vuser4[1]), + DELTA_DEF(clientdata_s, vuser4[2]), +}; + +void Delta::Init(IBaseSystem *system) +{ + m_Defs = nullptr; + m_Encoders = nullptr; + m_DeltaRegistry = nullptr; + + m_System = system; + + AddDefinition("clientdata_t", m_ClientDataDefinition, ARRAYSIZE(m_ClientDataDefinition)); + AddDefinition("weapon_data_t", m_WeaponDataDefinition, ARRAYSIZE(m_WeaponDataDefinition)); + AddDefinition("usercmd_t", m_UsercmdDataDefinition, ARRAYSIZE(m_UsercmdDataDefinition)); + AddDefinition("entity_state_t", m_EntityDataDefinition, ARRAYSIZE(m_EntityDataDefinition)); + AddDefinition("entity_state_player_t", m_EntityDataDefinition, ARRAYSIZE(m_EntityDataDefinition)); + AddDefinition("custom_entity_state_t", m_EntityDataDefinition, ARRAYSIZE(m_EntityDataDefinition)); + AddDefinition("event_t", m_EventDataDefinition, ARRAYSIZE(m_EventDataDefinition)); + + RegisterDescription("clientdata_t"); + RegisterDescription("entity_state_t"); + RegisterDescription("entity_state_player_t"); + RegisterDescription("custom_entity_state_t"); + RegisterDescription("usercmd_t"); + RegisterDescription("weapon_data_t"); + RegisterDescription("event_t"); + + m_LargeTime_Buffers = false; +} + +void Delta::Shutdown() +{ + ClearEncoders(); + ClearDefinitions(); + ClearRegistrations(); +} + +void Delta::UpdateDescriptions() +{ + m_PlayerDelta = *LookupRegistration("entity_state_player_t"); + m_EntityDelta = *LookupRegistration("entity_state_t"); + m_CustomentityDelta = *LookupRegistration("custom_entity_state_t"); + m_ClientDelta = *LookupRegistration("clientdata_t"); + m_WeaponDelta = *LookupRegistration("weapon_data_t"); + m_EventDelta = *LookupRegistration("event_t"); +} + +delta_description_t *Delta::FindField(delta_t *pFields, const char *pszField) +{ + for (int i = 0; i < pFields->fieldCount; i++) + { + if (_stricmp(pFields->pdd[i].fieldName, pszField) == 0) { + return &pFields->pdd[i]; + } + } + + m_System->Printf("Delta::FindField: Warning, couldn't find %s\n", pszField); + return nullptr; +} + +delta_t **Delta::LookupRegistration(char *name) +{ + delta_registry_t *delta = m_DeltaRegistry; + while (delta) + { + if (_stricmp(delta->name, name) == 0) { + return &delta->pdesc; + } + + delta = delta->next; + } + + return nullptr; +} + +int Delta::FindFieldIndex(delta_t *pFields, const char *fieldname) +{ + for (int i = 0; i < pFields->fieldCount; i++) + { + if (_stricmp(pFields->pdd[i].fieldName, fieldname) == 0) { + return i; + } + } + + m_System->Printf("Delta::FindFieldIndex: Warning, couldn't find %s\n", fieldname); + return -1; +} + +void Delta::SetField(delta_t *pFields, const char *fieldname) +{ + delta_description_t *pTest = FindField(pFields, fieldname); + if (pTest) { + pTest->flags |= FDT_MARK; + } +} + +void Delta::UnsetField(delta_t *pFields, const char *fieldname) +{ + delta_description_t *pTest = FindField(pFields, fieldname); + if (pTest) { + pTest->flags &= ~FDT_MARK; + } +} + +void Delta::SetFieldByIndex(delta_t *pFields, int fieldNumber) +{ + pFields->pdd[fieldNumber].flags |= FDT_MARK; +} + +void Delta::UnsetFieldByIndex(delta_t *pFields, int fieldNumber) +{ + pFields->pdd[fieldNumber].flags &= ~FDT_MARK; +} + +void Delta::ClearFlags(delta_t *pFields) +{ + for (int i = 0; i < pFields->fieldCount; i++) { + pFields->pdd[i].flags = 0; + } +} + +int Delta::CountSendFields(delta_t *pFields) +{ + int i, c; + for (i = 0, c = 0; i < pFields->fieldCount; i++) + { + auto pitem = &pFields->pdd[i]; + if (pitem->flags & FDT_MARK) { + pitem->stats.sendcount++; + c++; + } + } + + return c; +} + +void Delta::MarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields) +{ + int i; + char *st1, *st2; + delta_description_t *pTest; + int fieldType; + int fieldCount = pFields->fieldCount; + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + fieldType = pTest->fieldType & ~DT_SIGNED; + switch (fieldType) + { + case DT_BYTE: + if (from[pTest->fieldOffset] != to[pTest->fieldOffset]) + pTest->flags |= FDT_MARK; + break; + case DT_SHORT: + if (*(uint16 *)&from[pTest->fieldOffset] != *(uint16 *)&to[pTest->fieldOffset]) + pTest->flags |= FDT_MARK; + break; + case DT_FLOAT: + case DT_INTEGER: + case DT_ANGLE: + if (*(uint32 *)&from[pTest->fieldOffset] != *(uint32 *)&to[pTest->fieldOffset]) + pTest->flags |= FDT_MARK; + break; + case DT_TIMEWINDOW_8: + case DT_TIMEWINDOW_BIG: + if (*(uint32 *)&from[pTest->fieldOffset] != *(uint32 *)&to[pTest->fieldOffset]) + pTest->flags |= FDT_MARK; + break; + case DT_STRING: + st1 = (char *)&from[pTest->fieldOffset]; + st2 = (char *)&to[pTest->fieldOffset]; + + // Not sure why it is case insensitive, but it looks so + if (!(!*st1 && !*st2 || *st1 && *st2 && !_stricmp(st1, st2))) { + pTest->flags |= FDT_MARK; + } + break; + default: + m_System->Printf("Delta::MarkSendFields: Bad field type %i\n", fieldType); + break; + } + } + + if (pFields->conditionalencode) { + pFields->conditionalencode(pFields, from, to); + } +} + +void Delta::SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount) +{ + int i; + int lastbit = -1; + int fieldCount = pFields->fieldCount; + + memset(bits, 0, 8); + + for (i = fieldCount - 1; i >= 0; i--) + { + if (pFields->pdd[i].flags & FDT_MARK) + { + if (lastbit == -1) { + lastbit = i; + } + + bits[i > 31 ? 1 : 0] |= 1 << (i & 0x1f); + } + } + + // fix for bad bytecount when no fields are marked + if (lastbit == -1) { + *bytecount = 0; + return; + } + + *bytecount = (lastbit >> 3) + 1; +} + +void Delta::WriteMarkedFields(BitBuffer *stream, unsigned char *from, unsigned char *to, delta_t *pFields) +{ + int i; + delta_description_t *pTest; + int fieldSign; + int fieldType; + + float f2; + int fieldCount = pFields->fieldCount; + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + if (!(pTest->flags & FDT_MARK)) + continue; + + fieldSign = pTest->fieldType & DT_SIGNED; + fieldType = pTest->fieldType & ~DT_SIGNED; + switch (fieldType) + { + case DT_BYTE: + if (fieldSign) + { + int8 si8 = *(int8 *)&to[pTest->fieldOffset]; + si8 = (int8)((double)si8 * pTest->premultiply); + stream->WriteSBits(si8, pTest->significant_bits); + } + else + { + uint8 i8 = *(uint8 *)&to[pTest->fieldOffset]; + i8 = (uint8)((double)i8 * pTest->premultiply); + stream->WriteBits(i8, pTest->significant_bits); + } + break; + case DT_SHORT: + if (fieldSign) + { + int16 si16 = *(int16 *)&to[pTest->fieldOffset]; + si16 = (int16)((double)si16 * pTest->premultiply); + stream->WriteSBits(si16, pTest->significant_bits); + } + else + { + uint16 i16 = *(uint16 *)&to[pTest->fieldOffset]; + i16 = (uint16)((double)i16 * pTest->premultiply); + stream->WriteBits(i16, pTest->significant_bits); + } + break; + case DT_FLOAT: + { + double val = (double)(*(float *)&to[pTest->fieldOffset]) * pTest->premultiply; + if (fieldSign) + { + stream->WriteSBits((int32)val, pTest->significant_bits); + } + else + { + stream->WriteBits((uint32)val, pTest->significant_bits); + } + break; + } + case DT_INTEGER: + { + if (fieldSign) + { + int32 signedInt = *(int32 *)&to[pTest->fieldOffset]; + if (pTest->premultiply < 0.9999 || pTest->premultiply > 1.0001) { + signedInt = (int32)((double)signedInt * pTest->premultiply); + } + + stream->WriteSBits(signedInt, pTest->significant_bits); + } + else + { + uint32 unsignedInt = *(uint32 *)&to[pTest->fieldOffset]; + if (pTest->premultiply < 0.9999 || pTest->premultiply > 1.0001) { + unsignedInt = (uint32)((double)unsignedInt * pTest->premultiply); + } + + stream->WriteBits(unsignedInt, pTest->significant_bits); + } + break; + } + case DT_ANGLE: + f2 = *(float *)&to[pTest->fieldOffset]; + stream->WriteBitAngle(f2, pTest->significant_bits); + break; + case DT_TIMEWINDOW_8: + { + f2 = *(float *)&to[pTest->fieldOffset]; + if (m_LargeTime_Buffers) { + stream->WriteFloat(f2); + } else { + int32 twVal = (int)(m_Time * 100.0) - (int)(f2 * 100.0); + stream->WriteSBits(twVal, 8); + } + break; + } + case DT_TIMEWINDOW_BIG: + { + f2 = *(float *)&to[pTest->fieldOffset]; + if (m_LargeTime_Buffers) { + stream->WriteFloat(f2); + } else { + int32 twVal = (int)(m_Time * pTest->premultiply) - (int)(f2 * pTest->premultiply); + stream->WriteSBits((int32)twVal, pTest->significant_bits); + } + break; + } + case DT_STRING: + stream->WriteBitString((const char *)&to[pTest->fieldOffset]); + break; + default: + m_System->Printf("Delta::WriteMarkedFields: unknown send field type\n"); + break; + } + } +} + +bool Delta::CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields) +{ + ClearFlags(pFields); + MarkSendFields(from, to, pFields); + + return CountSendFields(pFields) ? true : false; +} + +void Delta::WriteHeader(BitBuffer *stream, deltacallback_t *header) +{ + int delta = header->num - header->numbase; + if (header->full) + { + if (delta == 1) + { + stream->WriteBit(1); + } + else + { + stream->WriteBit(0); + if (delta <= 0 || delta >= 64) + { + stream->WriteBit(1); + stream->WriteBits(header->num, 11); + } + else + { + stream->WriteBit(0); + stream->WriteBits(delta, 6); + } + } + } + else + { + stream->WriteBit(header->remove != 0); + if (delta <= 0 || delta >= 64) + { + stream->WriteBit(1); + stream->WriteBits(header->num, 11); + } + else + { + stream->WriteBit(0); + stream->WriteBits(delta, 6); + } + } + + header->numbase = header->num; + if (!header->remove) + { + stream->WriteBit(header->custom != 0); + if (header->instanced_baseline) + { + if (header->newbl) + { + stream->WriteBit(1); + stream->WriteBits(header->newblindex, 6); + } + else + { + stream->WriteBit(0); + } + } + if (header->full && !header->newbl) + { + if (header->offset) + { + stream->WriteBit(1); + stream->WriteBits(header->offset, 6); + } + else + { + stream->WriteBit(0); + } + } + } +} + +bool Delta::WriteDelta(BitBuffer *stream, unsigned char *from, unsigned char *to, bool force, delta_t *pFields, deltacallback_t *header) +{ + int i; + int bytecount; + int bits[2]; + + if (!CheckDelta(from, to, pFields) && !force) { + return false; + } + + SetSendFlagBits(pFields, bits, &bytecount); + + if (header) { + WriteHeader(stream, header); + } + + stream->WriteBits(bytecount, 3); + for (i = 0; i < bytecount; i++) { + stream->WriteBits(((byte *)bits)[i], 8); + } + + WriteMarkedFields(stream, from, to, pFields); + return true; +} + +int Delta::ParseDelta(BitBuffer *stream, unsigned char *from, unsigned char *to, delta_t *pFields) +{ + delta_description_t *pTest; + int i; + int bits[2]; // this is a limit with 64 fields max in delta + int nbytes; + int bitfieldnumber; + int fieldCount = pFields->fieldCount; + int fieldType; + int fieldSign; + + double d2; + float t; + int addt; + char *st2; + char c; + int startbit; + + startbit = stream->CurrentBit(); + memset(bits, 0, sizeof(bits)); + + nbytes = stream->ReadBits(3); + for (i = 0; i < nbytes; i++) { + ((byte *)bits)[i] = stream->ReadBits(8); + } + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + fieldType = pTest->fieldType & ~DT_SIGNED; + + bitfieldnumber = (1 << (i & 0x1F)); + if (!(bitfieldnumber & bits[i > 31])) + { + // Field was not sent to us, just transfer info from the "from" + switch (fieldType) + { + case DT_BYTE: + to[pTest->fieldOffset] = from[pTest->fieldOffset]; + break; + case DT_SHORT: + *(uint16 *)&to[pTest->fieldOffset] = *(uint16 *)&from[pTest->fieldOffset]; + break; + case DT_FLOAT: + case DT_INTEGER: + case DT_ANGLE: + case DT_TIMEWINDOW_8: + case DT_TIMEWINDOW_BIG: + *(uint32 *)&to[pTest->fieldOffset] = *(uint32 *)&from[pTest->fieldOffset]; + break; + case DT_STRING: + strcpy((char *)&to[pTest->fieldOffset], (char *)&from[pTest->fieldOffset]); + break; + default: + m_System->Printf("Delta::ParseDelta: unparseable field type %i\n", fieldType); + break; + } + continue; + } + + pTest->stats.receivedcount++; + fieldSign = pTest->fieldType & DT_SIGNED; + + switch (fieldType) + { + case DT_BYTE: + if (fieldSign) + { + d2 = (double)stream->ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#ifndef HLTV + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(int8 *)&to[pTest->fieldOffset] = (int8)d2; + } + else + { + d2 = (double)stream->ReadBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#ifndef HLTV + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(uint8 *)&to[pTest->fieldOffset] = (uint8)d2; + } + break; + case DT_SHORT: + if (fieldSign) + { + d2 = (double)stream->ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#ifndef HLTV + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(int16 *)&to[pTest->fieldOffset] = (int16)d2; + } + else + { + d2 = (double)stream->ReadBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#ifndef HLTV + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(uint16 *)&to[pTest->fieldOffset] = (uint16)d2; + } + break; + case DT_FLOAT: + if (fieldSign) + { + d2 = (double)stream->ReadSBits(pTest->significant_bits); + } + else + { + d2 = (double)stream->ReadBits(pTest->significant_bits); + } + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#ifndef HLTV + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(float *)&to[pTest->fieldOffset] = (float)d2; + break; + case DT_INTEGER: + if (fieldSign) + { + d2 = (double)stream->ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#ifndef HLTV + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(int32 *)&to[pTest->fieldOffset] = (int32)d2; + } + else + { + d2 = (double)stream->ReadBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#ifndef HLTV + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(uint32 *)&to[pTest->fieldOffset] = (uint32)d2; + } + break; + case DT_ANGLE: + *(float *)&to[pTest->fieldOffset] = stream->ReadBitAngle(pTest->significant_bits); + break; + case DT_TIMEWINDOW_8: + if (m_LargeTime_Buffers) { + t = stream->ReadFloat(); + } + else { + addt = stream->ReadSBits(8); + t = (float)((m_Time * 100.0 - addt) / 100.0); + } + *(float *)&to[pTest->fieldOffset] = t; + break; + case DT_TIMEWINDOW_BIG: + if (m_LargeTime_Buffers) { + t = stream->ReadFloat(); + } + else { + addt = stream->ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + t = (float)((m_Time * pTest->premultiply - addt) / pTest->premultiply); + } + else { + t = (float)(m_Time - addt); + } + } + + *(float *)&to[pTest->fieldOffset] = t; + break; + case DT_STRING: + st2 = (char *)&to[pTest->fieldOffset]; + do + { + c = stream->ReadBits(8); + *st2++ = c; + } while (c); + break; + default: + m_System->Printf("Delta::TestDelta: unparseable field type %i\n", fieldType); + break; + } + } + + return stream->CurrentBit() - startbit; +} + +int Delta::TestDelta(unsigned char *from, unsigned char *to, delta_t *pFields) +{ + int i; + char *st1, *st2; + delta_description_t *pTest; + int fieldType; + int fieldCount = pFields->fieldCount; + int length = 0; + bool different; + int neededBits = 0; + int highestBit = -1; + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + different = false; + fieldType = pTest->fieldType & ~DT_SIGNED; + + switch (fieldType) + { + case DT_BYTE: + different = from[pTest->fieldOffset] != to[pTest->fieldOffset]; + break; + case DT_SHORT: + different = *(uint16 *)&from[pTest->fieldOffset] != *(uint16 *)&to[pTest->fieldOffset]; + break; + case DT_FLOAT: + case DT_INTEGER: + case DT_ANGLE: + different = *(uint32 *)&from[pTest->fieldOffset] != *(uint32 *)&to[pTest->fieldOffset]; + break; + // don't use multiplier when checking, to increase performance + // check values binary like it does in jit + case DT_TIMEWINDOW_8: + case DT_TIMEWINDOW_BIG: + different = (*(int32 *)&from[pTest->fieldOffset]) != (*(int32 *)&to[pTest->fieldOffset]); + break; + case DT_STRING: + st1 = (char *)&from[pTest->fieldOffset]; + st2 = (char *)&to[pTest->fieldOffset]; + + // Not sure why it is case insensitive, but it looks so + if (!(!*st1 && !*st2 || *st1 && *st2 && !_stricmp(st1, st2))) + { + different = true; + length = strlen(st2) * 8; + pTest->flags |= FDT_MARK; + } + break; + default: + m_System->Printf("Delta::TestDelta: Bad field type %i\n", fieldType); + break; + } + + if (different) + { + highestBit = i; + neededBits += (fieldType == DT_STRING) ? length + 8 : pTest->significant_bits; + } + } + + if (highestBit != -1) { + neededBits += highestBit / 8 * 8 + 8; + } + + return neededBits; +} + +void Delta::AddEncoder(char *name, encoder_t conditionalencode) +{ + delta_encoder_t *delta = (delta_encoder_t *)Mem_ZeroMalloc(sizeof(delta_encoder_t)); + delta->name = _strdup(name); + delta->conditionalencode = conditionalencode; + delta->next = m_Encoders; + m_Encoders = delta; +} + +void Delta::ClearEncoders() +{ + delta_encoder_t *n, *p = m_Encoders; + while (p) + { + n = p->next; + free(p->name); + free(p); + p = n; + } + + m_Encoders = nullptr; +} + +encoder_t Delta::LookupEncoder(char *name) +{ + delta_encoder_t *p = m_Encoders; + while (p) + { + if (_stricmp(name, p->name) == 0) { + return p->conditionalencode; + } + + p = p->next; + } + + return nullptr; +} + +int Delta::CountLinks(delta_link_t *plinks) +{ + delta_link_t *p = plinks; + + int c; + for (c = 0; p; c++) { + p = p->next; + } + + return c; +} + +void Delta::ReverseLinks(delta_link_t **plinks) +{ + delta_link_t *n, *p = *plinks; + delta_link_t *newlist = nullptr; + + while (p) + { + n = p->next; + p->next = newlist; + newlist = p; + p = n; + } + + *plinks = newlist; +} + +void Delta::ClearLinks(delta_link_t **plinks) +{ + delta_link_t *n, *p = *plinks; + while (p) + { + n = p->next; + free(p); + p = n; + } + *plinks = 0; +} + +delta_t *Delta::BuildFromLinks(delta_link_t **pplinks) +{ + delta_description_t *pdesc, *pcur; + delta_t *pdelta; + delta_link_t *p; + int count; + + pdelta = (delta_t *)Mem_ZeroMalloc(sizeof(delta_t)); + ReverseLinks(pplinks); + count = CountLinks(*pplinks); + + if (count > DELTA_MAX_FIELDS) { + m_System->Errorf("Delta::BuildFromLinks: Too many fields in delta description %i (MAX %i)\n", count, DELTA_MAX_FIELDS); + return nullptr; + } + + pdesc = (delta_description_t *)Mem_ZeroMalloc(sizeof(delta_description_t) * count); + + for (p = *pplinks, pcur = pdesc; p; p = p->next, pcur++) + { + memcpy(pcur, p->delta, sizeof(delta_description_t)); + free(p->delta); + p->delta = 0; + } + + ClearLinks(pplinks); + + pdelta->dynamic = 1; + pdelta->fieldCount = count; + pdelta->pdd = pdesc; + + return pdelta; +} + +int Delta::FindOffset(int count, delta_definition_t *pdef, char *fieldname) +{ + for (int i = 0; i < count; i++) + { + if (_stricmp(fieldname, pdef[i].fieldName) == 0) { + return pdef[i].fieldOffset; + } + } + + m_System->Errorf("Delta::FindOffset: Couldn't find offset for %s!!!\n", fieldname); + return 0; +} + +bool Delta::ParseType(delta_description_t *pdelta, char **pstream) +{ + // Read the stream till we hit the end + while (*pstream = COM_Parse(*pstream), com_token[0] != 0) + { + if (!_stricmp(com_token, ",")) + return true; // end of type description + + if (!_stricmp(com_token, "|")) + continue; // skip | token + + // Determine field type + if (!_stricmp(com_token, "DT_SIGNED")) + pdelta->fieldType |= DT_SIGNED; + else if (!_stricmp(com_token, "DT_BYTE")) + pdelta->fieldType |= DT_BYTE; + else if (!_stricmp(com_token, "DT_SHORT")) + pdelta->fieldType |= DT_SHORT; + else if (!_stricmp(com_token, "DT_FLOAT")) + pdelta->fieldType |= DT_FLOAT; + else if (!_stricmp(com_token, "DT_INTEGER")) + pdelta->fieldType |= DT_INTEGER; + else if (!_stricmp(com_token, "DT_ANGLE")) + pdelta->fieldType |= DT_ANGLE; + else if (!_stricmp(com_token, "DT_TIMEWINDOW_8")) + pdelta->fieldType |= DT_TIMEWINDOW_8; + else if (!_stricmp(com_token, "DT_TIMEWINDOW_BIG")) + pdelta->fieldType |= DT_TIMEWINDOW_BIG; + else if (!_stricmp(com_token, "DT_STRING")) + pdelta->fieldType |= DT_STRING; + else + { + m_System->Errorf("Delta::ParseType: Unknown type or type flag %s\n", com_token); + return false; + } + } + + // We are hit the end of the stream + m_System->Printf("Delta::ParseType: Expecting fieldtype info\n"); + return false; +} + +bool Delta::ParseField(int count, delta_definition_t *pdefinition, delta_link_t *pField, char **pstream) +{ + bool readpost = false; + if (_stricmp(com_token, "DEFINE_DELTA")) + { + if (_stricmp(com_token, "DEFINE_DELTA_POST") != 0) { + m_System->Errorf("Delta::ParseField: Expecting DEFINE_*, got %s\n", com_token); + return false; + } + + readpost = true; + } + + *pstream = COM_Parse(*pstream); + if (_stricmp(com_token, "(")) + { + m_System->Errorf("Delta::ParseField: Expecting (, got %s\n", com_token); + return false; + } + + *pstream = COM_Parse(*pstream); + if (com_token[0] == '\0') + { + m_System->Errorf("Delta::ParseField: Expecting fieldname\n"); + return false; + } + + strcopy(pField->delta->fieldName, com_token); + pField->delta->fieldOffset = FindOffset(count, pdefinition, com_token); + + *pstream = COM_Parse(*pstream); + if (!ParseType(pField->delta, pstream)) { + return false; + } + + *pstream = COM_Parse(*pstream); + pField->delta->fieldSize = 1; + pField->delta->significant_bits = atoi(com_token); + *pstream = COM_Parse(*pstream); + *pstream = COM_Parse(*pstream); + pField->delta->premultiply = (float)atof(com_token); + + if (readpost) + { + *pstream = COM_Parse(*pstream); + *pstream = COM_Parse(*pstream); + pField->delta->postmultiply = (float)atof(com_token); + } + else + { + pField->delta->postmultiply = 1.0; + } + + *pstream = COM_Parse(*pstream); + if (_stricmp(com_token, ")")) + { + m_System->Printf("Delta::ParseField: Expecting ), got %s\n", com_token); + return false; + } + + *pstream = COM_Parse(*pstream); + if (_stricmp(com_token, ",")) { + COM_UngetToken(); + } + + return true; +} + +void Delta::FreeDescription(delta_t **ppdesc) +{ + if (ppdesc && *ppdesc) + { + if ((*ppdesc)->dynamic) { + free((*ppdesc)->pdd); + } + + free(*ppdesc); + *ppdesc = nullptr; + } +} + +void Delta::AddDefinition(char *name, delta_definition_t *pdef, int numelements) +{ + delta_definition_list_t *p = m_Defs; + while (p) + { + if (_stricmp(name, p->ptypename) == 0) { + break; + } + + p = p->next; + } + + if (!p) + { + p = (delta_definition_list_t *)Mem_ZeroMalloc(sizeof(delta_definition_list_t)); + p->ptypename = _strdup(name); + p->next = m_Defs; + m_Defs = p; + } + + p->pdefinition = pdef; + p->numelements = numelements; +} + +void Delta::ClearDefinitions() +{ + delta_definition_list_t *n, *p = m_Defs; + while (p) + { + n = p->next; + free(p->ptypename); + free(p); + p = n; + } + + m_Defs = nullptr; +} + +Delta::delta_definition_t *Delta::FindDefinition(char *name, int *count) +{ + *count = 0; + + delta_definition_list_t *p = m_Defs; + while (p) + { + if (!_stricmp(name, p->ptypename)) + { + *count = p->numelements; + return p->pdefinition; + } + + p = p->next; + } + + return nullptr; +} + +void Delta::SkipDescription(char **pstream) +{ + *pstream = COM_Parse(*pstream); + do + { + *pstream = COM_Parse(*pstream); + if (com_token[0] == '\0') { + m_System->Errorf("Delta::SkipDescription: Error during description skip\n"); + return; + } + } + while (_stricmp(com_token, "}")); +} + +bool Delta::ParseOneField(char **ppstream, delta_link_t **pplist, int count, delta_definition_t *pdefinition) +{ + delta_link_t *newlink; + delta_link_t link; + + while (true) + { + if (!_stricmp(com_token, "}")) + { + COM_UngetToken(); + break; + } + + *ppstream = COM_Parse(*ppstream); + if (com_token[0] == '\0') { + break; + } + + memset(&link, 0, sizeof(link)); + link.delta = (delta_description_t *)Mem_ZeroMalloc(sizeof(delta_description_t)); + if (!ParseField(count, pdefinition, &link, ppstream)) { + return false; + } + + newlink = (delta_link_t *)Mem_ZeroMalloc(sizeof(delta_link_t)); + newlink->delta = link.delta; + newlink->next = *pplist; + *pplist = newlink; + } + + return true; +} + +bool Delta::ParseDescription(char *name, delta_t **ppdesc, char *pstream) +{ + delta_link_t *links = nullptr; + delta_definition_t *pdefinition; + char encoder[32] = ""; + char source[32]; + int count = 0; + + if (!ppdesc) { + m_System->Errorf("Delta::ParseDescription: called with no delta_description_t\n"); + return false; + } + + *ppdesc = nullptr; + + if (!pstream) { + m_System->Errorf("Delta::ParseDescription: called with no data stream\n"); + return false; + } + + while (true) + { + // Parse delta name + pstream = COM_Parse(pstream); + if (com_token[0] == '\0') { + break; + } + + if (_stricmp(com_token, name)) + { + SkipDescription(&pstream); + } + else + { + pdefinition = FindDefinition(com_token, &count); + if (!pdefinition) { + m_System->Errorf("Delta::ParseDescription: Unknown data type: %s\n", com_token); + return false; + } + + // Parse source of conditional encoder + pstream = COM_Parse(pstream); + if (com_token[0] == '\0') { + m_System->Errorf("Delta::ParseDescription: Unknown encoder: %s\nValid values:\nnone\ngamedll funcname\nclientdll funcname\n", com_token); + return false; + } + + if (_stricmp(com_token, "none")) + { + strcopy(source, com_token); + + // Parse custom encoder function name + pstream = COM_Parse(pstream); + if (com_token[0] == '\0') { + m_System->Errorf("Delta::ParseDescription: Expecting encoder\n"); + return false; + } + + strcopy(encoder, com_token); + } + + // Parse fields + while (true) + { + pstream = COM_Parse(pstream); + if (com_token[0] == '\0') { + break; + } + + if (!_stricmp(com_token, "}")) { + break; + } + + if (_stricmp(com_token, "{")) { + m_System->Printf("Delta::ParseDescription: Expecting {, got %s\n", com_token); + return false; + } + + if (!ParseOneField(&pstream, &links, count, pdefinition)) { + return false; + } + } + } + } + + *ppdesc = BuildFromLinks(&links); + + if (encoder[0]) + { + strcopy((*ppdesc)->conditionalencodename, encoder); + (*ppdesc)->conditionalencodename[sizeof((*ppdesc)->conditionalencodename) - 1] = '\0'; + (*ppdesc)->conditionalencode = nullptr; + } + + return true; +} + +bool Delta::Load(char *name, delta_t **ppdesc, char *pszFile) +{ + char *pbuf = (char *)m_System->LoadFile(pszFile); + if (!pbuf) { + m_System->Errorf("Delta::Load: Couldn't load file %s\n", pszFile); + return false; + } + + bool res = ParseDescription(name, ppdesc, pbuf); + free(pbuf); + return res; +} + +void Delta::RegisterDescription(char *name) +{ + delta_registry_t *p = (delta_registry_t *)Mem_ZeroMalloc(sizeof(delta_registry_t)); + p->next = m_DeltaRegistry; + m_DeltaRegistry = p; + p->name = _strdup(name); + p->pdesc = 0; +} + +void Delta::ClearRegistrations() +{ + delta_registry_t *n, *p = m_DeltaRegistry; + while (p) + { + n = p->next; + free(p->name); + + if (p->pdesc) { + FreeDescription(&p->pdesc); + } + + free(p); + p = n; + } + + m_DeltaRegistry = nullptr; +} + +void Delta::ClearStats(delta_t *p) +{ + if (!p) { + return; + } + + for (int i = 0; i < p->fieldCount; i++) + { + p->pdd[i].stats.sendcount = 0; + p->pdd[i].stats.receivedcount = 0; + } +} + +void Delta::SetTime(double time) +{ + m_Time = time; +} + +void Delta::SetLargeTimeBufferSize(bool bigBuffers) +{ + m_LargeTime_Buffers = bigBuffers; +} + +#endif // HOOK_HLTV diff --git a/rehlds/HLTV/Core/src/Delta.h b/rehlds/HLTV/Core/src/Delta.h new file mode 100644 index 0000000..17a540a --- /dev/null +++ b/rehlds/HLTV/Core/src/Delta.h @@ -0,0 +1,208 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "event_args.h" +#include "BaseSystemModule.h" + +#define DELTA_MAX_FIELDS 56 // 7*8 + +#define DT_BYTE BIT(0) // A byte +#define DT_SHORT BIT(1) // 2 byte field +#define DT_FLOAT BIT(2) // A floating point field +#define DT_INTEGER BIT(3) // 4 byte integer +#define DT_ANGLE BIT(4) // A floating point angle +#define DT_TIMEWINDOW_8 BIT(5) // A floating point timestamp relative to server time +#define DT_TIMEWINDOW_BIG BIT(6) // A floating point timestamp relative to server time (with more precision and custom multiplier) +#define DT_STRING BIT(7) // A null terminated string, sent as 8 byte chars +#define DT_SIGNED BIT(31) // sign modificator + +#define FDT_MARK BIT(0) // Delta mark for sending + +typedef void (*encoder_t)(struct delta_s *, const unsigned char *, const unsigned char *); + +typedef struct delta_encoder_s +{ + struct delta_encoder_s *next; + char *name; + encoder_t conditionalencode; +} delta_encoder_t; + +typedef struct delta_stats_s +{ + int sendcount; + int receivedcount; +} delta_stats_t; + +typedef struct delta_description_s +{ + int fieldType; + char fieldName[32]; + int fieldOffset; + short int fieldSize; + int significant_bits; + float premultiply; + float postmultiply; + short int flags; + delta_stats_t stats; +} delta_description_t; + +typedef struct deltacallback_s +{ + int numbase; + int num; + bool remove; + bool custom; + bool newbl; + int newblindex; + bool full; + int offset; + bool instanced_baseline; +} deltacallback_t; + +typedef struct delta_s +{ + int dynamic; + int fieldCount; + char conditionalencodename[32]; + encoder_t conditionalencode; + delta_description_t *pdd; +} delta_t; + +#include "hookers/HLTV/Core/DeltaEx.h" + +#ifndef HOOK_HLTV + +class Delta { +public: + void Init(IBaseSystem *system); + void Shutdown(); + void UpdateDescriptions(); + void WriteHeader(BitBuffer *stream, deltacallback_t *header); + bool WriteDelta(BitBuffer *stream, unsigned char *from, unsigned char *to, bool force, delta_t *pFields, deltacallback_t *header = nullptr); + int ParseDelta(BitBuffer *stream, unsigned char *from, unsigned char *to, delta_t *pFields); + void SetTime(double time); + void SetLargeTimeBufferSize(bool bigBuffers); + int TestDelta(unsigned char *from, unsigned char *to, delta_t *pFields); + delta_t **LookupRegistration(char *name); + void FreeDescription(delta_t **ppdesc); + +private: + typedef struct delta_link_s + { + struct delta_link_s *next; + delta_description_t *delta; + } delta_link_t; + + typedef struct delta_definition_s + { + char *fieldName; + size_t fieldOffset; + } delta_definition_t; + + typedef struct delta_definition_list_s + { + struct delta_definition_list_s *next; + char *ptypename; + int numelements; + delta_definition_t *pdefinition; + } delta_definition_list_t; + + typedef struct delta_registry_s + { + struct delta_registry_s *next; + char *name; + delta_t *pdesc; + } delta_registry_t; + + delta_registry_t *GetRegistry() const { return m_DeltaRegistry; } + delta_description_t *FindField(delta_t *pFields, const char *pszField); + int FindFieldIndex(delta_t *pFields, const char *fieldname); + void SetField(delta_t *pFields, const char *fieldname); + void UnsetField(delta_t *pFields, const char *fieldname); + void SetFieldByIndex(delta_t *pFields, int fieldNumber); + void UnsetFieldByIndex(delta_t *pFields, int fieldNumber); + void ClearFlags(delta_t *pFields); + int CountSendFields(delta_t *pFields); + void MarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields); + void SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount); + void WriteMarkedFields(BitBuffer *stream, unsigned char *from, unsigned char *to, delta_t *pFields); + bool CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields); + void AddEncoder(char *name, encoder_t conditionalencode); + void ClearEncoders(); + encoder_t LookupEncoder(char *name); + int CountLinks(delta_link_t *plinks); + void ReverseLinks(delta_link_t **plinks); + void ClearLinks(delta_link_t **plinks); + delta_t *BuildFromLinks(delta_link_t **pplinks); + int FindOffset(int count, delta_definition_t *pdef, char *fieldname); + bool ParseType(delta_description_t *pdelta, char **pstream); + bool ParseField(int count, delta_definition_t *pdefinition, delta_link_t *pField, char **pstream); + void AddDefinition(char *name, delta_definition_t *pdef, int numelements); + void ClearDefinitions(); + delta_definition_t *FindDefinition(char *name, int *count); + void SkipDescription(char **pstream); + bool ParseOneField(char **ppstream, delta_link_t **pplist, int count, delta_definition_t *pdefinition); + bool ParseDescription(char *name, delta_t **ppdesc, char *pstream); + bool Load(char *name, delta_t **ppdesc, char *pszFile); + void RegisterDescription(char *name); + void ClearRegistrations(); + void ClearStats(delta_t *p); + +public: + static delta_t m_MetaDelta[]; + static delta_description_t m_MetaDescription[]; + static delta_definition_t m_DeltaDataDefinition[]; + static delta_definition_t m_EventDataDefinition[]; + static delta_definition_t m_EntityDataDefinition[]; + static delta_definition_t m_UsercmdDataDefinition[]; + static delta_definition_t m_WeaponDataDefinition[]; + static delta_definition_t m_ClientDataDefinition[]; + + static delta_t *m_EntityDelta; + static delta_t *m_PlayerDelta; + static delta_t *m_CustomentityDelta; + + static delta_t *m_ClientDelta; + static delta_t *m_WeaponDelta; + static delta_t *m_EventDelta; + +private: + friend class World; + IBaseSystem *m_System; + + delta_definition_list_t *m_Defs; + delta_encoder_t *m_Encoders; + delta_registry_t *m_DeltaRegistry; + + double m_Time; + bool m_LargeTime_Buffers; +}; + +#endif // HOOK_HLTV diff --git a/rehlds/HLTV/Core/src/NetSocket.cpp b/rehlds/HLTV/Core/src/NetSocket.cpp new file mode 100644 index 0000000..2ba4eed --- /dev/null +++ b/rehlds/HLTV/Core/src/NetSocket.cpp @@ -0,0 +1,555 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +bool NetSocket::AddChannel(INetChannel *channel) +{ + return m_Channels.AddTail(channel); +} + +bool NetSocket::RemoveChannel(INetChannel *channel) +{ + return m_Channels.Remove(channel); +} + +int NetSocket::DispatchIncoming() +{ + int length = 0; + int count = 0; + + NetAddress from; + while ((length = ReceivePacketIntern(&from))) + { + if (length == -1) + break; + + INetChannel *channel = (INetChannel *)m_Channels.GetFirst(); + while (channel) + { + if (from.Equal(channel->GetTargetAddress())) { + channel->ProcessIncoming(m_Buffer, length); + break; + } + + channel = (INetChannel *)m_Channels.GetNext(); + } + + // not found an existing channel for this address. + // create a new channel + if (!channel) + { + // do accept only connectionless (\xFF\xFF\xFF\xFF) incoming packet. + if (*(int *)m_Buffer == CONNECTIONLESS_HEADER) + { + NetPacket *p = new NetPacket; + p->time = m_System->GetTime(); + p->address.FromNetAddress(&from); + p->connectionless = true; + p->seqnr = -1; + + // cut connectionless data + p->data.Resize(length - 4); + p->data.WriteBuf(&m_Buffer[4], length - 4); + p->data.Reset(); + m_IncomingPackets.AddHead(p); + } + } + + count++; + } + + return count; +} + +bool NetSocket::SendPacket(NetPacket *packet) +{ + return SendPacket(&packet->address, packet->data.GetData(), packet->data.CurrentSize()); +} + +bool NetSocket::SendPacket(NetAddress *to, const void *data, int length) +{ + struct sockaddr addr; + int ret; + + if (m_Network->m_FakeLoss && RandomFloat(0, 1) < m_Network->m_FakeLoss) { + return true; + } + + if (length <= 0 || !data || !to) { + return true; + } + + to->ToSockadr(&addr); + + if (length > MAX_ROUTEABLE_PACKET) + { + ret = SendLong((const char *)data, length, 0, &addr, sizeof(addr)); + } + else + { + if (length < sizeof(addr)) + ret = SendShort((const char *)data, length, 0, &addr, sizeof(addr)); + else + ret = sendto(m_Socket, (const char *)data, length, 0, &addr, sizeof(addr)); + } + + if (ret == -1) + { + int err = m_Network->GetLastErrorCode(); + + // wouldblock is silent + if (err == WSAEWOULDBLOCK) + return true; + + if (err == WSAECONNREFUSED || err == WSAECONNRESET) + return true; + + // some PPP links dont allow broadcasts + if (err == WSAEADDRNOTAVAIL) + return true; + + m_System->Printf("WARNING! NetSocket::SendPacket: %s\n", m_Network->GetErrorText(err)); + return false; + } + + m_BytesOut += ret + UDP_HEADER_SIZE; + return true; +} + +INetwork *NetSocket::GetNetwork() +{ + return m_Network; +} + +int NetSocket::ReceivePacketIntern(NetAddress *fromHost) +{ + sockaddr from; + socklen_t fromlen = sizeof(from); + int size = recvfrom(m_Socket, (char *)m_Buffer, sizeof(m_Buffer), 0, &from, &fromlen); + if (size == -1) + { + int err = m_Network->GetLastErrorCode(); + if (err != WSAEWOULDBLOCK && err != WSAECONNRESET && err != WSAECONNREFUSED) + { + if (err == WSAEMSGSIZE) + { + m_System->DPrintf("WARNING! NetSocket::ReceivePacket: Ignoring oversized network message\n"); + } + else + { + m_System->DPrintf("WARNING! NetSocket::ReceivePacket: %s %d %i\n", m_Network->GetErrorText(err), err, errno); + perror("err"); + } + } + + return false; + } + + if (size == 0 || RandomFloat(0, 1) < m_Network->m_FakeLoss) { + return 0; + } + + if (size > 0 && size < 4) { + m_System->DPrintf("WARNING! NetSocket::ReceivePacket: Ignoring undersized network message\n"); + return 0; + } + + if (size >= MAX_UDP_PACKET) { + m_System->DPrintf("WARNING! NetSocket::ReceivePacket: Oversize packet from %s\n", fromHost->ToString()); + return 0; + } + + if (*(uint32 *)m_Buffer == NET_HEADER_FLAG_SPLITPACKET) + { + if (size < sizeof(SPLITPACKET)) + { + m_System->Printf("Invalid split packet length %i\n", size); + return 0; + } + + size = GetLong(m_Buffer, size); + } + + fromHost->FromSockadr(&from); + m_BytesIn += size + UDP_HEADER_SIZE; + return size; +} + +void NetSocket::Close() +{ + INetChannel *channel; + while ((channel = (INetChannel *)m_Channels.RemoveHead())) { + channel->Close(); + } + + Flush(); + m_Network->RemoveSocket(this); + + shutdown(m_Socket, 2); + SOCKET_CLOSE(m_Socket); +} + +bool NetSocket::JoinGroup(NetAddress *group) +{ + ip_mreq mreq; + SIN_SET_ADDR(&mreq.imr_multiaddr, *(unsigned int *)&group->m_IP[0]); + SIN_SET_ADDR(&mreq.imr_interface, 0); + + if (setsockopt(m_Socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)) == SOCKET_ERROR) + { + int err = m_Network->GetLastErrorCode(); + if (err != WSAEAFNOSUPPORT) { + m_System->DPrintf("WARNING! NetSocket::JoinGroup: IP_ADD_MEMBERSHIP: %s\n", m_Network->GetErrorText(err)); + } + + return false; + } + + return true; +} + +bool NetSocket::LeaveGroup(NetAddress *group) +{ + ip_mreq mreq; + SIN_SET_ADDR(&mreq.imr_multiaddr, *(unsigned int *)&group->m_IP[0]); + SIN_SET_ADDR(&mreq.imr_interface, 0); + + if (setsockopt(m_Socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) == SOCKET_ERROR) + { + int err = m_Network->GetLastErrorCode(); + if (err != WSAEAFNOSUPPORT) { + m_System->DPrintf("WARNING! NetSocket::LeaveGroup: IP_DROP_MEMBERSHIP: %s\n", m_Network->GetErrorText(err)); + } + + return false; + } + + return true; +} + +int NetSocket::DrainChannels() +{ + int count = 0; + INetChannel *channel = (INetChannel *)m_Channels.GetFirst(); + while (channel) + { + if (channel->IsReadyToSend() + && channel->KeepAlive() + && channel->IsConnected()) + { + count++; + channel->TransmitOutgoing(); + } + + channel = (INetChannel *)m_Channels.GetNext(); + } + + return count; +} + +int NetSocket::GetLong(unsigned char *pData, int size) +{ + unsigned int packetNumber; + unsigned int packetCount; + int sequenceNumber; + unsigned char packetID; + static int netSplitFlags[MAX_SPLIT_FRAGMENTS] = { -1, -1, -1, -1, -1 }; + SPLITPACKET *pHeader = (SPLITPACKET *)pData; + + sequenceNumber = pHeader->sequenceNumber; + packetID = pHeader->packetID; + packetCount = packetID & 0xF; + packetNumber = (unsigned int)packetID >> 4; + + if (packetNumber >= MAX_SPLIT_FRAGMENTS || packetCount > MAX_SPLIT_FRAGMENTS) + { + m_System->Printf("Malformed packet number (%i)\n", packetNumber); + return 0; + } + + if (m_NetSplitPacket.currentSequence == -1 || sequenceNumber != m_NetSplitPacket.currentSequence) + { + m_NetSplitPacket.currentSequence = sequenceNumber; + m_NetSplitPacket.splitCount = packetCount; + } + + unsigned int packetPayloadSize = size - sizeof(SPLITPACKET); + if (netSplitFlags[packetNumber] == sequenceNumber) + { + m_System->DPrintf("NetSocket::GetLong: Ignoring duplicated split packet %i of %i ( %i bytes )\n", packetNumber + 1, packetCount, packetPayloadSize); + } + else + { + if (packetNumber == packetCount - 1) { + m_NetSplitPacket.totalSize = packetPayloadSize + SPLIT_SIZE * (packetCount - 1); + } + + --m_NetSplitPacket.splitCount; + netSplitFlags[packetNumber] = sequenceNumber; + } + + memcpy(&m_NetSplitPacket.buffer[SPLIT_SIZE * packetNumber], pHeader + 1, packetPayloadSize); + + if (m_NetSplitPacket.splitCount > 0) { + return 0; + } + + m_NetSplitPacket.currentSequence = -1; + if (m_NetSplitPacket.totalSize > MAX_UDP_PACKET) + { + m_System->DPrintf("WARNING! NetSocket::GetLong: Split packet too large! %d bytes\n", m_NetSplitPacket.totalSize); + return -1; + + } + + memcpy(pData, m_NetSplitPacket.buffer, m_NetSplitPacket.totalSize); + return m_NetSplitPacket.totalSize; +} + +void NetSocket::OutOfBandPrintf(NetAddress *to, const char *format, ...) +{ + va_list argptr; + char string[NET_MAX_MESSAGE]; + + *(int *)string = CONNECTIONLESS_HEADER; + + va_start(argptr, format); + _vsnprintf(&string[4], sizeof(string) - 4, format, argptr); + va_end(argptr); + + SendPacket(to, string, strlen(string) + 1); +} + +void NetSocket::GetFlowStats(float *avgInKBSec, float *avgOutKBSec) +{ + *avgInKBSec = m_AvgBytesIn / 1024; + *avgOutKBSec = m_AvgBytesOut / 1024; +} + +NetPacket *NetSocket::ReceivePacket() +{ + return (NetPacket *)m_IncomingPackets.RemoveTail(); +} + +void NetSocket::FreePacket(NetPacket *packet) +{ + if (packet) { + delete packet; + } +} + +void NetSocket::AddPacket(NetPacket *packet) +{ + if (!packet->connectionless) { + m_System->DPrintf("WARNING! NetSocket::AddPacket: only connectionless packets accepted.\n"); + return; + } + + NetPacket *newpacket = new NetPacket; + + newpacket->time = packet->time; + newpacket->address.FromNetAddress(&packet->address); + newpacket->connectionless = true; + newpacket->seqnr = -1; + + newpacket->data.Resize(packet->data.GetMaxSize()); + newpacket->data.WriteBuf(packet->data.GetData(), packet->data.GetMaxSize()); + newpacket->data.Reset(); + + m_IncomingPackets.AddHead(newpacket); +} + +void NetSocket::Flush() +{ + NetPacket *in; + while ((in = (NetPacket *)m_IncomingPackets.RemoveTail())) { + FreePacket(in); + } + + if (m_Socket != INVALID_SOCKET) + { + sockaddr from; + socklen_t fromlen = sizeof(from); + while (recvfrom(m_Socket, (char *)m_Buffer, sizeof(m_Buffer), 0, &from, &fromlen) > 0) + ; + } +} + +bool NetSocket::Create(Network *network, int port, bool reuse, bool loopback) +{ + sockaddr_in address; + char _true = 1; + uint32 i = 1; + + m_Network = network; + m_System = network->GetSystem(); + + m_Channels.Init(); + + memset(m_Buffer, 0, sizeof(m_Buffer)); + memset(&m_NetSplitPacket, 0, sizeof(m_NetSplitPacket)); + + if ((m_Socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { + return false; + } + + if (SOCKET_FIONBIO(m_Socket, i) == SOCKET_ERROR) { + return false; + } + + if (setsockopt(m_Socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == SOCKET_ERROR) { + return false; + } + + // resue + if (reuse && setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, &_true, sizeof(_true)) == SOCKET_ERROR) { + return false; + } + + if (m_Network->m_IsMultihomed) + { + m_Network->GetLocalAddress()->ToSockadr((sockaddr *)&address); + } + else + { + address.sin_addr.s_addr = 0; + } + + m_Port = port; + address.sin_port = htons(port); + address.sin_family = AF_INET; + + if (bind(m_Socket, (struct sockaddr *)&address, sizeof(address)) == SOCKET_ERROR) { + SOCKET_CLOSE(m_Socket); + return false; + } + + // Time-To-Live (TTL) for Multicast Packets + // As the values of the TTL field increase, routers will expand the number of hops they will forward a multicast packet. + // To provide meaningful scope control, multicast routers enforce the following + // "thresholds" on forwarding based on the TTL field: + // + // 0: restricted to the same host + // 1: restricted to the same subnet + // 32: restricted to the same site + // 64: restricted to the same region + // 128: restricted to the same continent + // 255: unrestricted + + uint32 ttl = 32; + char *ttlparam = m_System->CheckParam("-multicastttl"); + if (ttlparam) { + ttl = atoi(ttlparam); + } + + if (setsockopt(m_Socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)) == SOCKET_ERROR) { + return false; + } + + m_BytesOut = 0; + m_BytesIn = 0; + m_LastUpdateTime = 0; + + m_AvgBytesOut = 0; + m_AvgBytesIn = 0; + + return true; +} + +int NetSocket::GetPort() +{ + return m_Port; +} + +void NetSocket::UpdateStats(double time) +{ + float timeDiff = time - m_LastUpdateTime; + if (timeDiff > 0) + { + m_AvgBytesIn = m_BytesIn / timeDiff * 0.3 + m_AvgBytesIn * 0.6; + m_AvgBytesOut = m_BytesOut / timeDiff * 0.3 + m_AvgBytesOut * 0.6; + + m_BytesIn = 0; + m_BytesOut = 0; + m_LastUpdateTime = time; + } +} + +int NetSocket::SendLong(const char *pData, int len, int flags, const sockaddr *to, int tolen) +{ + char packet[MAX_ROUTEABLE_PACKET]; + int totalSent, ret, size, packetCount, packetNumber; + SPLITPACKET *pPacket; + + if (++m_netSplitSequenceNumber < 0) { + m_netSplitSequenceNumber = 1; + } + + pPacket = (SPLITPACKET *)packet; + pPacket->netID = -2; + pPacket->sequenceNumber = m_netSplitSequenceNumber; + packetNumber = 0; + totalSent = 0; + packetCount = (len + SPLIT_SIZE - 1) / SPLIT_SIZE; + + while (len > 0) + { + size = min(SPLIT_SIZE, (unsigned)len); + pPacket->packetID = (packetNumber << 4) + packetCount; + memcpy(packet + sizeof(SPLITPACKET), pData + (packetNumber * SPLIT_SIZE), size); + + ret = sendto(m_Socket, packet, size + sizeof(SPLITPACKET), flags, to, tolen); + if (ret < 0) { + return ret; + } + + if (ret >= size) { + totalSent += size; + } + + len -= size; + packetNumber++; + } + + return totalSent; +} + +int NetSocket::SendShort(const char *pData, int len, int flags, const sockaddr *to, int tolen) +{ + if (len > MIN_ROUTEABLE_PACKET) { + m_System->DPrintf("WARNING! NetSocket::SendShort: length > MIN_ROUTEABLE_PACKET.\n"); + return 0; + } + + char packet[MAX_ROUTEABLE_PACKET]; + memcpy(packet, pData, len); + memset(&packet[len], 0, sizeof(packet) - len); + + return sendto(m_Socket, packet, sizeof(packet), flags, to, tolen); +} diff --git a/rehlds/HLTV/Core/src/NetSocket.h b/rehlds/HLTV/Core/src/NetSocket.h new file mode 100644 index 0000000..b14a047 --- /dev/null +++ b/rehlds/HLTV/Core/src/NetSocket.h @@ -0,0 +1,108 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include + +class Network; +class IBaseSytem; + +class NetSocket: public INetSocket { +public: + NetSocket() : m_netSplitSequenceNumber(0) {} + virtual ~NetSocket() {} + + NetPacket *ReceivePacket(); + void FreePacket(NetPacket *packet); + bool SendPacket(NetPacket *packet); + bool SendPacket(NetAddress *packet, const void *data, int length); + void AddPacket(NetPacket *packet); + bool AddChannel(INetChannel *channel); + bool RemoveChannel(INetChannel *channel); + INetwork *GetNetwork(); + void OutOfBandPrintf(NetAddress *to, const char *format, ...); + void Flush(); + void GetFlowStats(float *avgInKBSec, float *avgOutKBSec); + bool LeaveGroup(NetAddress *group); + bool JoinGroup(NetAddress *group); + void Close(); + int GetPort(); + + bool Create(Network *network, int port, bool reuse, bool loopback); + void UpdateStats(double time); + int DrainChannels(); + int DispatchIncoming(); + +private: + int ReceivePacketIntern(NetAddress *fromHost); + int SendLong(const char *pData, int len, int flags, const sockaddr *to, int tolen); + int SendShort(const char *pData, int len, int flags, const sockaddr *to, int tolen); + int GetLong(unsigned char *pData, int size); + +protected: + int m_Port; + unsigned char m_Buffer[MAX_UDP_PACKET]; + + ObjectList m_IncomingPackets; + ObjectList m_Channels; + SOCKET m_Socket; + Network *m_Network; + IBaseSystem *m_System; + + enum { MAX_SPLIT_FRAGMENTS = 5 }; + // Use this to pick apart the network stream, must be packed + #pragma pack(push, 1) + typedef struct SPLITPACKET_t + { + int netID; + int sequenceNumber; + unsigned char packetID; + } SPLITPACKET; + #pragma pack(pop) + + // Split long packets. Anything over 1460 is failing on some routers. + typedef struct LONGPACKET_t + { + int currentSequence; + int splitCount; + int totalSize; + // TODO: It should be NET_MAX_MESSAGE, but value differs + char buffer[MAX_UDP_PACKET]; // This has to be big enough to hold the largest message + } LONGPACKET; + + LONGPACKET m_NetSplitPacket; + + int m_netSplitSequenceNumber; + int m_netSplitFlags[MAX_SPLIT_FRAGMENTS]; + int m_BytesIn; + int m_BytesOut; + double m_LastUpdateTime; + float m_AvgBytesIn; + float m_AvgBytesOut; +}; diff --git a/rehlds/HLTV/Core/src/Network.cpp b/rehlds/HLTV/Core/src/Network.cpp new file mode 100644 index 0000000..91a732b --- /dev/null +++ b/rehlds/HLTV/Core/src/Network.cpp @@ -0,0 +1,445 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +bool Network::Init(IBaseSystem *system, int serial, char *name) +{ + BaseSystemModule::Init(system, serial, name); + + if (!name) { + SetName(NETWORK_INTERFACE_VERSION); + } + + m_FakeLoss = 0; + m_IsMultihomed = false; + m_NoDNS = false; + + m_Sockets.Init(); + m_System->RegisterCommand("fakeloss", this, CMD_ID_FAKELOSS); + +#ifdef _WIN32 + // Startup winock + WORD version = MAKEWORD(2, 2); // for use Winsock 2.2, version should be 514 + WSADATA wsaData; + int err = WSAStartup(version, &wsaData); + if (err != NO_ERROR) + { + m_System->Printf("Network Error WSAStartup:%s\n", GetErrorText(GetLastErrorCode())); + return false; + } +#endif // _WIN32 + + if (m_System->CheckParam("-nodns")) { + m_NoDNS = true; + } + + if (ResolveAddress(m_System->CheckParam("-ip"), &m_LocalAddress)) + { + m_IsMultihomed = true; + m_System->Printf("Network uses %s as host IP.\n", m_LocalAddress.ToBaseString()); + } + else + { + char hostname[512]; + gethostname(hostname, sizeof(hostname)); + ResolveAddress(hostname, &m_LocalAddress); + } + + char *portparam = m_System->CheckParam("-port"); + if (!portparam) { + portparam = "27020"; + } + + m_LocalAddress.m_Port = htons(atoi(portparam)); + m_LastStatsUpdateTime = 0; + + m_State = MODULE_RUNNING; + m_System->Printf("Network initialized.\n"); + return true; +} + +void Network::ExecuteCommand(int commandID, char *commandLine) +{ + if (commandID == CMD_ID_FAKELOSS) { + CMD_FakeLoss(commandLine); + return; + } + + m_System->Printf("ERROR! Network::ExecuteCommand: unknown command ID %i.\n", commandID); +} + +void Network::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) { + return; + } + + NetSocket *sock; + while ((sock = (NetSocket *)m_Sockets.RemoveTail())) + { + sock->Close(); + delete sock; + } + +#ifdef _WIN32 + if (WSACleanup() == SOCKET_ERROR) { + m_System->Printf("Network Error WSACleanup:%s\n", GetErrorText(GetLastErrorCode())); + } +#endif // _WIN32 + + m_System->Printf("Network module shutdown.\n"); + BaseSystemModule::ShutDown(); +} + +INetSocket *Network::CreateSocket(int port, bool reuse, bool loopback) +{ + NetSocket *socket = GetSocket(port); + if (socket) { + return socket; + } + + socket = new NetSocket; + if (!socket) { + m_System->Printf("ERROR! Network::CreateSocket: out of memory.\n"); + return nullptr; + } + + if (!socket->Create(this, port, reuse, loopback)) + { + m_System->Printf("ERROR! Network::CreateSocket: %s.\n", GetErrorText(GetLastErrorCode())); + + delete socket; + return nullptr; + } + + m_Sockets.Add(socket); + return socket; +} + +bool Network::RemoveSocket(INetSocket *netsocket) +{ + return m_Sockets.Remove(netsocket); +} + +char *Network::GetType() +{ + return NETWORK_INTERFACE_VERSION; +} + +int Network::ReceiveData() +{ + int countPackets = 0; + NetSocket *sock = (NetSocket *)m_Sockets.GetFirst(); + while (sock) + { + countPackets += sock->DispatchIncoming(); + sock = (NetSocket *)m_Sockets.GetNext(); + } + + return countPackets; +} + +int Network::SendData() +{ + int countPackets = 0; + NetSocket *sock = (NetSocket *)m_Sockets.GetFirst(); + while (sock) + { + countPackets += sock->DrainChannels(); + sock = (NetSocket *)m_Sockets.GetNext(); + } + + return countPackets; +} + +NetSocket *Network::GetSocket(int port) +{ + NetSocket *sock = (NetSocket *)m_Sockets.GetFirst(); + if (!sock) { + return nullptr; + } + + while (sock) + { + if (sock->GetPort() == port || !port) { + return sock; + } + + sock = (NetSocket *)m_Sockets.GetNext(); + } + + return nullptr; +} + +void Network::RunFrame(double time) +{ + BaseSystemModule::RunFrame(time); + + SendData(); + ReceiveData(); + UpdateStats(); +} + +NetAddress *Network::GetLocalAddress() +{ + return &m_LocalAddress; +} + +char *Network::GetStatusLine() +{ + static char string[256]; + float in, out; + + GetFlowStats(&in, &out); + _snprintf(string, sizeof(string), "Local IP %s, Sockets %i, In %.2f, Out %.2f.\n", m_LocalAddress.ToBaseString(), m_Sockets.CountElements(), in, out); + return string; +} + +void Network::GetFlowStats(float *totalIn, float *totalOut) +{ + *totalIn = 0; + *totalOut = 0; + + NetSocket *sock = (NetSocket *)m_Sockets.GetFirst(); + while (sock) + { + float in, out; + sock->GetFlowStats(&in, &out); + + *totalIn += in; + *totalOut += out; + + sock = (NetSocket *)m_Sockets.GetNext(); + } +} + +void Network::CMD_FakeLoss(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) { + m_System->Printf("Syntax: fakeloss \n"); + m_System->Printf("Current fakeloss is %.2f\n", m_FakeLoss); + return; + } + + m_FakeLoss = atof(params.GetToken(1)); +} + +int Network::GetLastErrorCode() +{ + return WSAGetLastError(); +} + +bool Network::ResolveAddress(char *string, NetAddress *address) +{ + sockaddr sadr; + hostent *h; + char copy[128]; + + address->Clear(); + + if (!string || !strlen(string)) { + return 0; + } + + memset(&sadr, 0, sizeof(sadr)); + ((sockaddr_in *)&sadr)->sin_family = AF_INET; + ((sockaddr_in *)&sadr)->sin_port = 0; + + strcopy(copy, string); + + // Parse port + char *colon = copy; + while (*colon != '\0') + { + if (*colon == ':') + { + *colon = '\0'; + int val = atoi(colon + 1); + ((sockaddr_in *)&sadr)->sin_port = htons(val); + } + colon++; + } + + // Parse address + // Validate IPv4 + if (copy[0] >= '0' && copy[0] <= '9' && strstr(copy, ".")) + { + uint32 ret = inet_addr(copy); + if (ret == INADDR_NONE) { + return false; + } + + ((sockaddr_in *)&sadr)->sin_addr.s_addr = ret; + } + else if (m_NoDNS) + { + // do not resolve address via DNS. + return false; + } + // If we allow the use of DNS, + // let's get the address by the hostname. + else + { + h = gethostbyname(copy); + if (!h || !h->h_addr) { + return false; + } + + ((sockaddr_in *)&sadr)->sin_addr.s_addr = *(uint32 *)h->h_addr; + } + + return address->FromSockadr(&sadr); +} + +char *Network::GetErrorText(int code) +{ + switch (code) + { + case WSAEINTR: return "WSAEINTR"; + case WSAEBADF: return "WSAEBADF"; + case WSAEACCES: return "WSAEACCES"; + case WSAEFAULT: return "WSAEFAULT"; + case WSAEINVAL: return "WSAEINVAL"; + case WSAEMFILE: return "WSAEMFILE"; + case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK"; + case WSAEINPROGRESS: return "WSAEINPROGRESS"; + case WSAEALREADY: return "WSAEALREADY"; + case WSAENOTSOCK: return "WSAENOTSOCK"; + case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ"; + case WSAEMSGSIZE: return "WSAEMSGSIZE"; + case WSAEPROTOTYPE: return "WSAEPROTOTYPE"; + case WSAENOPROTOOPT: return "WSAENOPROTOOPT"; + case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT"; + case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT"; + case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP"; + case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT"; + case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT"; + case WSAEADDRINUSE: return "WSAEADDRINUSE"; + case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL"; + case WSAENETDOWN: return "WSAENETDOWN"; + case WSAENETUNREACH: return "WSAENETUNREACH"; + case WSAENETRESET: return "WSAENETRESET"; + case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR"; + case WSAECONNRESET: return "WSAECONNRESET"; + case WSAENOBUFS: return "WSAENOBUFS"; + case WSAEISCONN: return "WSAEISCONN"; + case WSAENOTCONN: return "WSAENOTCONN"; + case WSAESHUTDOWN: return "WSAESHUTDOWN"; + case WSAETOOMANYREFS: return "WSAETOOMANYREFS"; + case WSAETIMEDOUT: return "WSAETIMEDOUT"; + case WSAECONNREFUSED: return "WSAECONNREFUSED"; + case WSAELOOP: return "WSAELOOP"; + case WSAENAMETOOLONG: return "WSAENAMETOOLONG"; + case WSAEHOSTDOWN: return "WSAEHOSTDOWN"; + default: return "UNKNOWN ERROR"; + +#ifdef _WIN32 + case WSASYSNOTREADY: return "WSASYSNOTREADY"; + case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED"; + case WSANOTINITIALISED: return "WSANOTINITIALISED"; + case WSAEDISCON: return "WSAEDISCON"; + case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND"; + case WSATRY_AGAIN: return "WSATRY_AGAIN"; + case WSANO_RECOVERY: return "WSANO_RECOVERY"; + case WSANO_DATA: return "WSANO_DATA"; +#endif // _WIN32 + } +} + +void Network::SetName(char *newName) +{ + strcopy(m_Name, newName); +} + +void Network::UpdateStats() +{ + if (m_LastStatsUpdateTime + 0.5 > m_SystemTime) { + return; + } + + NetSocket *sock = (NetSocket *)m_Sockets.GetFirst(); + while (sock) + { + sock->UpdateStats(m_SystemTime); + sock = (NetSocket *)m_Sockets.GetNext(); + } + + m_LastStatsUpdateTime = m_SystemTime; +} + +void Network::ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) +{ + BaseSystemModule::ReceiveSignal(module, signal, data); +} + +void Network::RegisterListener(ISystemModule *module) +{ + BaseSystemModule::RegisterListener(module); +} + +void Network::RemoveListener(ISystemModule *module) +{ + BaseSystemModule::RemoveListener(module); +} + +IBaseSystem *Network::GetSystem() +{ + return BaseSystemModule::GetSystem(); +} + +int Network::GetSerial() +{ + return BaseSystemModule::GetSerial(); +} + +char *Network::GetName() +{ + return BaseSystemModule::GetName(); +} + +int Network::GetState() +{ + return BaseSystemModule::GetState(); +} + +int Network::GetVersion() +{ + return BaseSystemModule::GetVersion(); +} + +IBaseInterface *CreateNetwork() +{ + INetwork *pNetwork = new Network; + return (IBaseInterface *)pNetwork; +} + +#ifndef HOOK_HLTV +EXPOSE_INTERFACE_FN(CreateNetwork, Network, NETWORK_INTERFACE_VERSION); +#endif // HOOK_HLTV diff --git a/rehlds/HLTV/Core/src/Network.h b/rehlds/HLTV/Core/src/Network.h new file mode 100644 index 0000000..c2f68f7 --- /dev/null +++ b/rehlds/HLTV/Core/src/Network.h @@ -0,0 +1,130 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include +#include "BaseSystemModule.h" + +#ifndef _WIN32 +#define WSAEWOULDBLOCK EWOULDBLOCK // Operation would block EAGAIN (11) +#define WSAEMSGSIZE EMSGSIZE // Message too long (90) +#define WSAEADDRNOTAVAIL EADDRNOTAVAIL // Cannot assign requested address (99) +#define WSAEAFNOSUPPORT EAFNOSUPPORT // Address family not supported by protocol (97) +#define WSAECONNRESET ECONNRESET // Connection reset by peer (104) +#define WSAECONNREFUSED ECONNREFUSED // Connection refused (111) +#define WSAEADDRINUSE EADDRINUSE // Address already in use (98) +#define WSAENOBUFS ENOBUFS // No buffer space available (105) + +#define WSAEINTR EINTR // Interrupted system call +#define WSAEBADF EBADF // Bad file number +#define WSAEACCES EACCES // Permission denied +#define WSAEFAULT EFAULT // Bad address +#define WSAEINVAL EINVAL // Invalid argument +#define WSAEMFILE EMFILE // Too many open files +#define WSAEWOULDBLOCK EWOULDBLOCK // Operation would block +#define WSAEINPROGRESS EINPROGRESS // Operation now in progress +#define WSAEALREADY EALREADY // Operation already in progress +#define WSAENOTSOCK ENOTSOCK // Socket operation on non-socket +#define WSAEDESTADDRREQ EDESTADDRREQ // Destination address required +#define WSAEMSGSIZE EMSGSIZE // Message too long +#define WSAEPROTOTYPE EPROTOTYPE // Protocol wrong type for socket +#define WSAENOPROTOOPT ENOPROTOOPT // Protocol not available +#define WSAEPROTONOSUPPORT EPROTONOSUPPORT // Protocol not supported +#define WSAESOCKTNOSUPPORT ESOCKTNOSUPPORT // Socket type not supported +#define WSAEOPNOTSUPP EOPNOTSUPP // Operation not supported on transport endpoint +#define WSAEPFNOSUPPORT EPFNOSUPPORT // Protocol family not supported +#define WSAEAFNOSUPPORT EAFNOSUPPORT // Address family not supported by protocol +#define WSAEADDRINUSE EADDRINUSE // Address already in use +#define WSAEADDRNOTAVAIL EADDRNOTAVAIL // Cannot assign requested address +#define WSAENETDOWN ENETDOWN // Network is down +#define WSAENETUNREACH ENETUNREACH // Network is unreachable +#define WSAENETRESET ENETRESET // Network dropped connection because of reset +#define WSAECONNABORTED ECONNABORTED // Software caused connection abort +#define WSAECONNRESET ECONNRESET // Connection reset by peer +#define WSAENOBUFS ENOBUFS // No buffer space available +#define WSAEISCONN EISCONN // Transport endpoint is already connected +#define WSAENOTCONN ENOTCONN // Transport endpoint is not connected +#define WSAESHUTDOWN ESHUTDOWN // Cannot send after transport endpoint shutdown +#define WSAETOOMANYREFS ETOOMANYREFS // Too many references: cannot splice +#define WSAETIMEDOUT ETIMEDOUT // Connection timed out +#define WSAECONNREFUSED ECONNREFUSED // Connection refused +#define WSAELOOP ELOOP // Too many symbolic links encountered +#define WSAENAMETOOLONG ENAMETOOLONG // File name too long +#define WSAEHOSTDOWN EHOSTDOWN // Host is down +#endif // _WIN32 + +class NetSocket; +class Network: public BaseSystemModule, public INetwork { +public: + Network() {} + virtual ~Network() {} + + bool Init(IBaseSystem *system, int serial, char *name); + void RunFrame(double time); + void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data); + void ExecuteCommand(int commandID, char *commandLine); + void RegisterListener(ISystemModule *module); + void RemoveListener(ISystemModule *module); + IBaseSystem *GetSystem(); + int GetSerial(); + char *GetStatusLine(); + char *GetType(); + char *GetName(); + int GetState(); + int GetVersion(); + void ShutDown(); + + INetSocket *CreateSocket(int port, bool reuse, bool loopback); + bool RemoveSocket(INetSocket *netsocket); + NetAddress *GetLocalAddress(); + bool ResolveAddress(char *string, NetAddress *address); + void GetFlowStats(float *totalIn, float *totalOut); + int GetLastErrorCode(); + char *GetErrorText(int code); + +protected: + enum LocalCommandIDs { CMD_ID_FAKELOSS = 1 }; + void CMD_FakeLoss(char *cmdLine); + + void SetName(char *newName); + void UpdateStats(); + NetSocket *GetSocket(int port); + int SendData(); + int ReceiveData(); + +protected: + friend class NetSocket; + + float m_FakeLoss; + NetAddress m_LocalAddress; + bool m_IsMultihomed; + bool m_NoDNS; + double m_LastStatsUpdateTime; + ObjectList m_Sockets; +}; diff --git a/rehlds/HLTV/Core/src/Server.cpp b/rehlds/HLTV/Core/src/Server.cpp new file mode 100644 index 0000000..24f257d --- /dev/null +++ b/rehlds/HLTV/Core/src/Server.cpp @@ -0,0 +1,2388 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +Server::svc_func_s Server::m_ClientFuncs[] +{ + { svc_bad, "svc_bad", &Server::ParseBad }, + { svc_nop, "svc_nop", &Server::ParseNop }, + { svc_disconnect, "svc_disconnect", &Server::ParseDisconnect }, + { svc_event, "svc_event", &Server::ParseEvent }, + { svc_version, "svc_version", &Server::ParseVersion }, + { svc_setview, "svc_setview", &Server::ParseSetView }, + { svc_sound, "svc_sound", &Server::ParseSound }, + { svc_time, "svc_time", &Server::ParseTime }, + { svc_print, "svc_print", &Server::ParsePrint }, + { svc_stufftext, "svc_stufftext", &Server::ParseStuffText }, + { svc_setangle, "svc_setangle", &Server::ParseSetAngle }, + { svc_serverinfo, "svc_serverinfo", &Server::ParseServerinfo }, + { svc_lightstyle, "svc_lightstyle", &Server::ParseLightStyle }, + { svc_updateuserinfo, "svc_updateuserinfo", &Server::ParseUpdateUserInfo }, + { svc_deltadescription, "svc_deltadescription", &Server::ParseDeltaDescription }, + { svc_clientdata, "svc_clientdata", &Server::ParseClientData }, + { svc_stopsound, "svc_stopsound", &Server::ParseStopSound }, + { svc_pings, "svc_pings", &Server::ParsePings }, + { svc_particle, "svc_particle", &Server::ParseParticle }, + { svc_damage, "svc_damage", &Server::ParseNop }, + { svc_spawnstatic, "svc_spawnstatic", &Server::ParseNop }, + { svc_event_reliable, "svc_event_reliable", &Server::ParseEventReliable }, + { svc_spawnbaseline, "svc_spawnbaseline", &Server::ParseBaseline }, + { svc_temp_entity, "svc_temp_entity", &Server::ParseTempEntity }, + { svc_setpause, "svc_setpause", &Server::ParseSetPause }, + { svc_signonnum, "svc_signonnum", &Server::ParseSignonNum }, + { svc_centerprint, "svc_centerprint", &Server::ParseCenterPrint }, + { svc_killedmonster, "svc_killedmonster", &Server::ParseNop }, + { svc_foundsecret, "svc_foundsecret", &Server::ParseNop }, + { svc_spawnstaticsound, "svc_spawnstaticsound", &Server::ParseSpawnStaticSound }, + { svc_intermission, "svc_intermission", &Server::ParseIntermission }, + { svc_finale, "svc_finale", &Server::ParseFinale }, + { svc_cdtrack, "svc_cdtrack", &Server::ParseCDTrack }, + { svc_restore, "svc_restore", &Server::ParseRestore }, + { svc_cutscene, "svc_cutscene", &Server::ParseCutscene }, + { svc_weaponanim, "svc_weaponanim", &Server::ParseWeaponAnim }, + { svc_decalname, "svc_decalname", &Server::ParseDecalName }, + { svc_roomtype, "svc_roomtype", &Server::ParseRoomType }, + { svc_addangle, "svc_addangle", &Server::ParseAddAngle }, + { svc_newusermsg, "svc_newusermsg", &Server::ParseNewUserMsg }, + { svc_packetentities, "svc_packetentities", &Server::ParsePacketEntities }, + { svc_deltapacketentities, "svc_deltapacketentities", &Server::ParseDeltaPacketEntities }, + { svc_choke, "svc_choke", &Server::ParseChoke }, + { svc_resourcelist, "svc_resourcelist", &Server::ParseResourceList }, + { svc_newmovevars, "svc_newmovevars", &Server::ParseMoveVars }, + { svc_resourcerequest, "svc_resourcerequest", &Server::ParseResourceRequest }, + { svc_customization, "svc_customization", &Server::ParseCustomization }, + { svc_crosshairangle, "svc_crosshairangle", &Server::ParseCrosshairAngle }, + { svc_soundfade, "svc_soundfade", &Server::ParseSoundFade }, + { svc_filetxferfailed, "svc_filetxferfailed", &Server::ParseFileTransferFailed }, + { svc_hltv, "svc_hltv", &Server::ParseHLTV }, + { svc_director, "svc_director", &Server::ParseDirector }, + { svc_voiceinit, "svc_voiceinit", &Server::ParseVoiceInit }, + { svc_voicedata, "svc_voicedata", &Server::ParseVoiceData }, + { svc_sendextrainfo, "svc_sendextrainfo", &Server::ParseSendExtraInfo }, + { svc_timescale, "svc_timescale", &Server::ParseTimeScale }, + { svc_resourcelocation, "svc_resourcelocation", &Server::ParseResourceLocation }, + { svc_sendcvarvalue, "svc_sendcvarvalue", &Server::ParseSendCvarValue }, + { svc_sendcvarvalue2, "svc_sendcvarvalue2", &Server::ParseSendCvarValue2 }, + { svc_endoflist, "End of List", nullptr } +}; + +bool Server::Init(IBaseSystem *system, int serial, char *name) +{ + SetState(SERVER_INITIALIZING); + BaseSystemModule::Init(system, serial, name); + + if (!name) { + SetName(SERVER_INTERFACE_VERSION); + } + + m_FileSystem = m_System->GetFileSystem(); + m_Rate = 10000; + m_UpdateRate = 20; + m_NextAutoRetry = 0; + m_DelayReconnect = true; + m_Protocol = PROTOCOL_VERSION; + + m_UserInfo.SetMaxSize(256); + m_UserInfo.SetValueForKey("name", "HLTV Proxy"); + m_UserInfo.SetValueForKey("cl_lw", "1"); + m_UserInfo.SetValueForKey("cl_lc", "1"); + m_UserInfo.SetValueForKey("*hltv", "1"); + m_UserInfo.SetValueForKey("rate", COM_VarArgs("%i", m_Rate)); + m_UserInfo.SetValueForKey("cl_updaterate", COM_VarArgs("%i", m_UpdateRate)); + + m_IsGameServer = false; + m_IsVoiceBlocking = false; + m_ServerSocket = nullptr; + m_ServerChannel.Create(system); + m_ServerInfo.SetMaxSize(512); + + SetState(SERVER_DISCONNECTED); + + m_ReliableData.Resize(MAX_UDP_PACKET); + m_UnreliableData.Resize(MAX_UDP_PACKET); + m_VoiceData.Resize(MAX_UDP_PACKET); + m_UserMessages.Resize(MAX_UDP_PACKET); + m_ClientData.Resize(MAX_UDP_PACKET); + m_DemoData.Resize(MAX_UDP_PACKET); + + memset(&m_Frame, 0, sizeof(m_Frame)); + + m_Frame.reliableData = m_ReliableData.GetData(); + m_Frame.unreliableData = m_UnreliableData.GetData(); + m_Frame.voiceData = m_VoiceData.GetData(); + m_Frame.userMessages = m_UserMessages.GetData(); + m_Frame.clientData = m_ClientData.GetData(); + m_Frame.demoData = m_DemoData.GetData(); + + m_UnreliableData.Clear(); + m_ReliableData.Clear(); + m_VoiceData.Clear(); + m_UserMessages.Clear(); + m_ClientData.Clear(); + m_DemoData.Clear(); + + strcopy(m_CDKey, "2123437429222"); + strcopy(m_HostName, "Unkown Host"); + + memset(m_SeqNrMap, 0, sizeof(m_SeqNrMap)); + m_validSequence = 0; + m_AutoRetry = true; + m_IsHLTV = true; + m_ForceHLTV = false; + m_IsPaused = false; + + m_World = nullptr; + m_Proxy = nullptr; + m_Director = nullptr; + + m_DemoFile.Reset(); + m_State = MODULE_RUNNING; + m_System->Printf("Server module initialized.\n"); + + return true; +} + +void Server::SetGameDirectory(const char *defaultDir, const char *gameDir) +{ + char temp[MAX_PATH]; + m_FileSystem->RemoveAllSearchPaths(); + + if (gameDir && _stricmp(gameDir, defaultDir) != 0) + { + sprintf(temp, "%s/%s", GetBaseDir(), gameDir); + m_FileSystem->AddSearchPath(temp, "GAME"); + } + + sprintf(temp, "%s/%s", GetBaseDir(), defaultDir); + m_FileSystem->AddSearchPath(temp, "DEFAULTGAME"); + m_FileSystem->AddSearchPath(GetBaseDir(), "ROOT"); +} + +void Server::ExecuteCommand(int commandID, char *commandLine) +{ + m_System->Printf("ERROR! Server::ExecuteCommand: unknown command ID %i.\n", commandID); +} + +void Server::Challenge() +{ + const int MAX_CONNECT_RETRIES = 3; + const float CONNECT_RETRY_INTERVAL = 4.0; + + static float nextRetry = 0; + if (!m_CurrentRetry) + { + nextRetry = 0; + m_CurrentRetry++; + } + + if (nextRetry >= m_SystemTime) { + return; + } + + if (m_CurrentRetry > MAX_CONNECT_RETRIES) + { + m_System->Printf("WARNING! Server::Challenge: Timeout after %i retries\n", MAX_CONNECT_RETRIES); + SetState(SERVER_DISCONNECTED); + ScheduleAutoRetry(); + return; + } + + m_ServerChannel.OutOfBandPrintf("%s\n", "getchallenge"); + m_System->Printf("Challenging %s (%i/%i).\n", m_ServerChannel.GetTargetAddress()->ToString(), m_CurrentRetry, MAX_CONNECT_RETRIES); + nextRetry = m_SystemTime + CONNECT_RETRY_INTERVAL; + m_CurrentRetry++; +} + +void Server::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) { + return; + } + + Disconnect(); + m_ServerChannel.Close(); + m_ReliableData.Free(); + m_UnreliableData.Free(); + m_VoiceData.Free(); + m_UserMessages.Free(); + m_ClientData.Free(); + m_DemoData.Free(); + m_Listener.Clear(); + m_System->Printf("Server module shutdown.\n"); + + BaseSystemModule::ShutDown(); +} + +void Server::RunFrame(double time) +{ + BaseSystemModule::RunFrame(time); + CheckConnection(); + + if (IsDemoFile()) { + m_DemoFile.ReadDemoPacket(&m_DemoData, &m_DemoInfo); + } + + int packets = 0; + NetPacket *packet; + while ((packet = m_ServerChannel.GetPacket())) + { + if (packet->connectionless) + { + if (!ProcessConnectionlessMessage(&packet->address, &packet->data) && m_Proxy) + { + packet->data.Reset(); + m_Proxy->ProcessConnectionlessMessage(&packet->address, &packet->data); + } + } + else + { + m_Instream = &packet->data; + ProcessMessage(packet->seqnr); + } + + m_ServerChannel.FreePacket(packet); + + if (++packets > 32) { + break; + } + + if (IsDemoFile()) { + m_DemoFile.ReadDemoPacket(&m_DemoData, &m_DemoInfo); + } + } + + switch (m_ServerState) + { + case SERVER_CONNECTED: + break; + case SERVER_DISCONNECTED: + CheckAutoRetry(); + break; + case SERVER_CHALLENGING: + Challenge(); + break; + case SERVER_CONNECTING: + SendConnectPacket(); + break; + case SERVER_RUNNING: + case SERVER_INTERMISSION: + if (m_ServerChannel.IsReadyToSend()) { + SendServerCommands(); + } + break; + default: + m_System->Errorf("Server::RunFrame: not valid state.\n"); + break; + } +} + +bool Server::ProcessConnectionlessMessage(NetAddress *from, BitBuffer *stream) +{ + TokenLine params; + + char *firstToken = stream->ReadString(); + if (!params.SetLine(firstToken)) { + m_System->Printf("WARNING! Server::ProcessConnectionlessMessage: message too long.\n"); + return true; + } + + if (!params.CountToken()) { + m_System->Printf("WARNING! Invalid packet from %s.\n", from->ToString()); + return true; + } + + char *c = params.GetToken(0); + switch (c[0]) + { + case S2C_CONNECTION: + AcceptConnection(); + break; + case S2C_CHALLENGE: + AcceptChallenge(params.GetLine()); + break; + case A2A_PRINT: + m_System->Printf(">%s\n", params.GetLine() + 1); + break; + case S2C_REJECT_BADPASSWORD: + AcceptBadPassword(); + break; + case S2C_REJECT: + AcceptRejection(params.GetLine() + 1); + break; + case S2A_PROXY_LISTEN: + AcceptChallenge(params.GetLine()); + break; + case S2A_PROXY_REDIRECT: + AcceptRedirect(params.GetLine() + 1); + break; + case S2A_INFO: + ParseInfo(stream, false); + break; + case S2A_INFO_DETAILED: + ParseInfo(stream, true); + break; + default: + m_System->DPrintf("Server::ProcessConnectionlessServerMessage: unknown command \"%c\"\n", *c); + return false; + } + + return true; +} + +void Server::ProcessMessage(unsigned int seqNr) +{ + if (!IsConnected()) { + return; + } + + m_Frame.seqnr = seqNr; + + while (m_ServerState != SERVER_DISCONNECTED) + { + if (m_Instream->IsOverflowed()) { + m_System->Printf("WARNING! Server::ProcessMessage: packet read overflow.\n"); + return; + } + + int cmd = m_Instream->ReadByte(); + if (cmd == -1) { + break; + } + + if (cmd > svc_startofusermessages) + { + if (!ParseUserMessage(cmd)) { + break; + } + + continue; + } + + if (!m_ClientFuncs[cmd].func) { + m_System->Printf("TODO! Server::ProcessMessage: missing parsing routine for %s.\n", m_ClientFuncs[cmd].pszname); + return; + } + + (this->*m_ClientFuncs[cmd].func)(); + } + + if (m_Frame.entitynum) + { + if (!m_ReliableData.IsOverflowed()) { + m_Frame.reliableDataSize = m_ReliableData.CurrentSize(); + } + + if (!m_UnreliableData.IsOverflowed()) { + m_Frame.unreliableDataSize = m_UnreliableData.CurrentSize(); + } + + if (!m_VoiceData.IsOverflowed()) { + m_Frame.voiceDataSize = m_VoiceData.CurrentSize(); + } + + if (!m_ClientData.IsOverflowed()) { + m_Frame.clientDataSize = m_ClientData.CurrentSize(); + } + + if (!m_UserMessages.IsOverflowed()) { + m_Frame.userMessagesSize = m_UserMessages.CurrentSize(); + } + + if (!m_DemoData.IsOverflowed() && !m_ForceHLTV) { + m_Frame.demoDataSize = m_DemoData.CurrentSize(); + } + + if (!m_IsHLTV && !m_ForceHLTV) { + m_Frame.demoInfo = &m_DemoInfo; + } + + if (m_ForceHLTV) { + ProcessEntityUpdate(); + } + + m_SeqNrMap[seqNr & 0xFF] = m_World->AddFrame(&m_Frame); + m_validSequence = seqNr; + ClearFrame(true); + } + else + { + ClearFrame(m_World->IsActive() ? false : true); + } +} + +void Server::AcceptChallenge(char *cmdLine) +{ + TokenLine params(cmdLine); + if (m_ServerState != SERVER_CHALLENGING) { + m_System->Printf("WARNING! Server::AcceptChallenge: ignoring unwanted challenge return.\n"); + return; + } + + if (params.CountToken() < 3) { + m_System->Printf("WARNING! Server::AcceptChallenge: invalid challenge format.\n"); + return; + } + + m_ChallengeNumber = atoi(params.GetToken(1)); + m_AuthProtocol = atoi(params.GetToken(2)); + m_AuthProtocol = 2; + + if (m_AuthProtocol == 2) + { + m_System->Printf("Get challenge (HASHEDCDKEY)\n"); + SetState(SERVER_CONNECTING); + } + else + { + m_System->Printf("Invalid auth type\n"); + } + + m_CurrentRetry = 0; +} + +bool Server::IsVoiceBlocking() +{ + return m_IsVoiceBlocking; +} + +void Server::SetVoiceBlocking(bool state) +{ + m_IsVoiceBlocking = state; +} + +void Server::SetRate(int rate) +{ + m_Rate = clamp(rate, 1000, MAX_SERVER_RATE); + SetUserInfo("rate", COM_VarArgs("%i", m_Rate)); +} + +void Server::SetUpdateRate(int updaterate) +{ + m_UpdateRate = clamp(updaterate, 1, MAX_SERVER_UPDATERATE); + SetUserInfo("cl_updaterate", COM_VarArgs("%i", m_UpdateRate)); +} + +void Server::SetState(ServerState newState) +{ + if (newState == m_ServerState) + return; + + bool stateError = false; + switch (newState) + { + case SERVER_INITIALIZING: + break; + case SERVER_DISCONNECTED: + { + if (m_ServerState != SERVER_INITIALIZING) { + m_ServerChannel.Close(); + } + + break; + } + case SERVER_CHALLENGING: + { + if (m_ServerState != SERVER_DISCONNECTED) { + stateError = true; + } + m_ServerChannel.SetUpdateRate(1); + break; + } + case SERVER_AUTHENTICATING: + { + if (m_ServerState != SERVER_CHALLENGING) { + stateError = true; + } + break; + } + case SERVER_CONNECTING: + { + if (m_ServerState != SERVER_AUTHENTICATING + && m_ServerState != SERVER_CHALLENGING) { + stateError = true; + } + break; + } + case SERVER_CONNECTED: + { + if (m_ServerState != SERVER_CONNECTING + && m_ServerState != SERVER_RUNNING + && m_ServerState != SERVER_INTERMISSION && !IsDemoFile()) { + stateError = true; + } + + m_ServerChannel.SetTimeOut(60); + m_ServerChannel.SetUpdateRate(30); + m_ServerChannel.SetKeepAlive(true); + break; + } + case SERVER_RUNNING: + { + if (m_ServerState != SERVER_CONNECTED + && m_ServerState != SERVER_INTERMISSION) { + stateError = true; + } + + m_ServerChannel.SetKeepAlive(false); + m_ServerChannel.SetTimeOut(30); + break; + } + case SERVER_INTERMISSION: + { + if (m_ServerState != SERVER_RUNNING) { + stateError = true; + } + break; + } + default: + stateError = true; + break; + } + + if (stateError) + { + m_System->Errorf("Server::SetState: not valid m_ServerState (%i -> %i).\n", m_ServerState, newState); + return; + } + + m_ServerState = newState; +} + +void Server::SendConnectPacket() +{ + const int MAX_CONNECT_RETRIES = 3; + const float CONNECT_RETRY_INTERVAL = 4.0; + + char data[2048]; + char buffer[1024]; + InfoString protinfo(1024); + + static float nextRetry = 0; + if (!m_CurrentRetry) { + nextRetry = 0; + m_CurrentRetry++; + } + + if (nextRetry >= m_SystemTime) { + return; + } + + if (m_CurrentRetry > MAX_CONNECT_RETRIES) + { + m_System->Printf("WARNING! Server::SendConnectPacket: Timeout \n"); + SetState(SERVER_DISCONNECTED); + ScheduleAutoRetry(); + return; + } + + if (m_AuthProtocol == 2) + { + if (!m_CDKey[0]) + { + m_System->Printf("Invalid CD Key\n"); + SetState(SERVER_DISCONNECTED); + return; + } + + strcopy(buffer, MD5_GetCDKeyHash(m_CDKey)); + } + + protinfo.SetValueForKey("prot", COM_VarArgs("%i", m_AuthProtocol)); + protinfo.SetValueForKey("unique", COM_VarArgs("%i", -1)); + protinfo.SetValueForKey("raw", buffer); + + if (m_AuthProtocol != 2) { + protinfo.SetValueForKey("cdkey", MD5_GetCDKeyHash(m_CDKey)); + } + + _snprintf(data, sizeof(data), "%c%c%c%cconnect %i %i \"%s\" \"%s\"\n", 0xFF, 0xFF, 0xFF, 0xFF, m_Protocol, m_ChallengeNumber, protinfo.GetString(), m_UserInfo.GetString()); + m_ServerSocket->SendPacket(m_ServerChannel.GetTargetAddress(), data, strlen(data)); + + m_System->Printf("Connecting to %s (%i/%i).\n", m_ServerChannel.GetTargetAddress()->ToString(), m_CurrentRetry, MAX_CONNECT_RETRIES); + nextRetry = m_SystemTime + CONNECT_RETRY_INTERVAL; + m_CurrentRetry++; +} + +void Server::AcceptBadPassword() +{ + if (m_ServerState != SERVER_CONNECTING) { + m_System->Printf("WARNING! Server::AcceptBadPassword: ignoring unwanted bad password return.\n"); + return; + } + + m_System->Printf("Bad server password.\n"); + SetState(SERVER_DISCONNECTED); +} + +void Server::AcceptRejection(char *reason) +{ + if (m_ServerState != SERVER_CONNECTING) { + m_System->Printf("WARNING! Server::AcceptRejection: ignoring unwanted rejection message.\n"); + return; + } + + m_System->Printf("Connection rejected: %s\n", reason); + SetState(SERVER_DISCONNECTED); + ScheduleAutoRetry(); +} + +void Server::AcceptConnection() +{ + if (m_ServerState != SERVER_CONNECTING) { + m_System->Printf("WARNING! Server::AcceptConnection: ignoring unwanted connection return.\n"); + return; + } + + SetState(SERVER_CONNECTED); + m_ServerChannel.SetConnected(true); + + m_System->DPrintf("Connection accepted by %s\n", m_ServerAddress.ToString()); + SendStringCommand("new"); + + BaseSystemModule::FireSignal(1, &m_ServerAddress); +} + +void Server::AcceptRedirect(char *toAddress) +{ + if (m_ServerState != SERVER_CONNECTING) { + m_System->Printf("WARNING! Server::AcceptRedirect: ignoring unwanted redirect message.\n"); + return; + } + + INetwork *newtwork = m_ServerSocket->GetNetwork(); + newtwork->ResolveAddress(toAddress, &m_ServerAddress); + m_System->Printf("Redirected to %s\n", m_ServerAddress.ToString()); + + SetState(SERVER_DISCONNECTED); + BaseSystemModule::FireSignal(3, &m_ServerAddress); + Retry(); +} + +void Server::ParsePrint() +{ + char *string = m_Instream->ReadString(); + if (*string < 32) { + string++; + } + + m_System->Printf(">%s\n", string); +} + +void Server::ParseVoiceInit() +{ + unsigned char *start = m_Instream->CurrentByte(); + char *codec = m_Instream->ReadString(); + unsigned char quality = m_Instream->ReadByte(); + + int length = strlen(codec); + if (m_ServerState == SERVER_CONNECTED) { + m_World->AddSignonData(svc_voiceinit, start, length + 2); + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_ReliableData.WriteByte(svc_voiceinit); + m_ReliableData.WriteString(codec); + m_ReliableData.WriteByte(quality); + } + else { + m_System->Errorf("Server::ParseVoiceInit: unexpected server state.\n"); + } + + m_World->SetVoiceEnabled(codec[0] ? true : false); +} + +void Server::ParseVoiceData() +{ + int index = m_Instream->ReadByte(); + int dataLength = m_Instream->ReadShort(); + + if (!m_IsVoiceBlocking && m_ServerState >= SERVER_RUNNING) + { + m_VoiceData.WriteByte(svc_voicedata); + m_VoiceData.WriteByte(index); + m_VoiceData.WriteShort(dataLength); + m_VoiceData.WriteBuf(m_Instream->CurrentByte(), dataLength); + } + + m_Instream->SkipBytes(dataLength); +} + +void Server::ParseNop() +{ +} + +void Server::ParseBad() +{ + m_System->Printf("WARNING! Server::ParseBad: illegal server message.\n"); + m_Instream->m_Overflowed = true; +} + +void Server::ParseServerinfo() +{ + if (IsDemoFile() && m_ServerState == SERVER_RUNNING) { + Disconnect(); + return; + } + + m_System->DPrintf("Serverinfo packet received.\n"); + + int protocol = m_Instream->ReadLong(); + if (protocol != m_Protocol) + { + m_System->Printf("WARNING! Server returned protocol version %i, not %i\n", protocol, m_Protocol); + Disconnect(); + return; + } + + m_ServerCount = m_Instream->ReadLong(); + m_World->NewGame(m_ServerCount); + m_ServerCRC = m_Instream->ReadLong(); + + unsigned char clientdllmd5[16]; + m_Instream->ReadBuf(sizeof(clientdllmd5), clientdllmd5); + + int maxclients = m_Instream->ReadByte(); + int playernum = m_Instream->ReadByte(); + m_ClientPlayerNum = playernum; + + COM_UnMunge3((byte *)&m_ServerCRC, sizeof(m_ServerCRC), (-1 - playernum) & 0xFF); + if (m_ForceHLTV) + { + if (maxclients == 1) { + maxclients = 2; + } + + playernum = maxclients - 1; + } + + char gamedir[MAX_PATH]; + char levelname[MAX_PATH]; + int gametype = m_Instream->ReadByte(); + + strcopy(gamedir, m_Instream->ReadString()); + strcopy(m_HostName, m_Instream->ReadString()); + strcopy(levelname, m_Instream->ReadString()); + + m_Instream->SkipString(); + + if (m_Instream->ReadByte()) + { + int length = m_Instream->ReadByte(); + m_Instream->SkipBytes(length); + m_Instream->SkipBytes(16); + } + + m_World->SetServerInfo(protocol, m_ServerCRC, clientdllmd5, maxclients, playernum, gametype, gamedir, m_HostName, levelname); + + if (!IsDemoFile()) { + SetGameDirectory("valve", gamedir); + } + + m_World->SetHLTV((m_IsHLTV || m_ForceHLTV) ? true : false); + + SetState(SERVER_CONNECTED); + SendStringCommand("sendres"); +} + +void Server::ParseDeltaDescription() +{ + m_World->ParseDeltaDescription(m_Instream); +} + +void Server::ParseDecalName() +{ + m_ReliableData.WriteByte(svc_decalname); + m_ReliableData.WriteByte(m_Instream->ReadByte()); + m_ReliableData.WriteString(m_Instream->ReadString()); +} + +void Server::ParseMoveVars() +{ + movevars_t movevars; + movevars.gravity = m_Instream->ReadFloat(); + movevars.stopspeed = m_Instream->ReadFloat(); + movevars.maxspeed = m_Instream->ReadFloat(); + movevars.spectatormaxspeed = m_Instream->ReadFloat(); + movevars.accelerate = m_Instream->ReadFloat(); + movevars.airaccelerate = m_Instream->ReadFloat(); + movevars.wateraccelerate = m_Instream->ReadFloat(); + movevars.friction = m_Instream->ReadFloat(); + movevars.edgefriction = m_Instream->ReadFloat(); + movevars.waterfriction = m_Instream->ReadFloat(); + movevars.entgravity = m_Instream->ReadFloat(); + movevars.bounce = m_Instream->ReadFloat(); + movevars.stepsize = m_Instream->ReadFloat(); + movevars.maxvelocity = m_Instream->ReadFloat(); + movevars.zmax = m_Instream->ReadFloat(); + movevars.waveHeight = m_Instream->ReadFloat(); + movevars.footsteps = m_Instream->ReadByte (); + movevars.rollangle = m_Instream->ReadFloat(); + movevars.rollspeed = m_Instream->ReadFloat(); + movevars.skycolor_r = m_Instream->ReadFloat(); + movevars.skycolor_g = m_Instream->ReadFloat(); + movevars.skycolor_b = m_Instream->ReadFloat(); + movevars.skyvec_x = m_Instream->ReadFloat(); + movevars.skyvec_y = m_Instream->ReadFloat(); + movevars.skyvec_z = m_Instream->ReadFloat(); + + strcopy(movevars.skyName, m_Instream->ReadString()); + m_World->SetMoveVars(&movevars); +} + +void Server::ParseCDTrack() +{ + int cdtrack = m_Instream->ReadByte(); + int looptrack = m_Instream->ReadByte(); + + m_World->SetCDInfo(cdtrack, looptrack); +} + +void Server::ParseRestore() +{ + m_Instream->SkipString(); + + int mapCount = m_Instream->ReadByte(); + for (int i = 0; i < mapCount; i++) { + m_Instream->SkipString(); + } +} + +void Server::ParseSetView() +{ + if (m_ServerState == SERVER_CONNECTED) + { + m_World->SetViewEntity(m_Instream->ReadShort()); + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_ReliableData.WriteByte(svc_setview); + m_ReliableData.WriteBuf(m_Instream->CurrentByte(), 2); + m_ReliableData.SkipBytes(2); + } + else + { + m_System->Errorf("Server::ParseAddAngle: unexpected server state.\n"); + } +} + +void Server::ParseResourceRequest() +{ + if (m_ServerState != SERVER_CONNECTED) { + m_System->Printf("WARNING! Server::ParseResourceRequest: custom resource request not valid - not connected\n"); + return; + } + + int arg = m_Instream->ReadLong(); + if (arg != m_ServerCount) { + m_System->Printf("WARNING! Server::ParseResourceRequest: from old level\n"); + return; + } + + int nStartIndex = m_Instream->ReadLong(); + if (nStartIndex) { + m_System->Printf("WARNING! Server::ParseResourceRequest: custom resource list request out of range\n"); + return; + } + + m_ServerChannel.m_reliableStream.WriteByte(clc_resourcelist); + m_ServerChannel.m_reliableStream.WriteShort(0); +} + +void Server::ParseCrosshairAngle() +{ + m_ReliableData.WriteByte(svc_crosshairangle); + m_ReliableData.WriteChar(m_Instream->ReadChar()); + m_ReliableData.WriteChar(m_Instream->ReadChar()); +} + +void Server::ParseSoundFade() +{ + m_ReliableData.WriteByte(svc_soundfade); + m_ReliableData.WriteByte(m_Instream->ReadByte()); + m_ReliableData.WriteByte(m_Instream->ReadByte()); + m_ReliableData.WriteByte(m_Instream->ReadByte()); + m_ReliableData.WriteByte(m_Instream->ReadByte()); +} + +void Server::ParseNewUserMsg() +{ + int iMsg = m_Instream->ReadByte(); + int iSize = m_Instream->ReadByte(); + if (iSize == 255) { + iSize = -1; + } + + char name[16]; + m_Instream->ReadBuf(sizeof(name), name); + + m_System->DPrintf("Adding user message:%s(%i).\n", name, iMsg); + m_World->AddUserMessage(iMsg, iSize, name); +} + +void Server::ParseWeaponAnim() +{ + m_Instream->SkipBytes(2); +} + +void Server::ParseStuffText() +{ + TokenLine cmdLine; + if (!cmdLine.SetLine(m_Instream->ReadString())) { + m_System->Printf("WARNING! Server::ParseStuffText: command too long.\n"); + return; + } + + char *cmd = cmdLine.GetToken(0); + if (!cmd) { + m_System->Printf("WARNING! Server::ParseStuffText: command is NULL.\n"); + return; + } + + if (!_stricmp(cmd, "fullserverinfo")) + { + char *infostring = cmdLine.GetToken(1); + m_ServerInfo.SetString(infostring); + m_World->SetServerInfoString(infostring); + + if (IsDemoFile()) + { + m_IsGameServer = false; + } + else + { + NetAddress gameAddr; + m_ServerSocket->GetNetwork()->ResolveAddress(m_ServerInfo.ValueForKey("proxy"), &gameAddr); + + if (gameAddr.IsValid()) + { + m_IsGameServer = false; + m_World->SetGameServerAddress(&gameAddr); + } + else + { + m_IsGameServer = true; + m_World->SetGameServerAddress(&m_ServerAddress); + m_World->GetServerInfoString()->SetValueForKey("proxy", m_ServerAddress.ToString()); + } + } + + BaseSystemModule::FireSignal(4); + return; + } + else if (!_stricmp(cmd, "reconnect")) + { + if (IsDemoFile()) + { + Disconnect(); + } + else if (m_DelayReconnect) + { + BaseSystemModule::FireSignal(5); + m_System->DPrintf("Delaying reconnect to broadcast complete game.\n"); + } + else + { + Reconnect(); + } + + m_IsPaused = false; + return; + } + else if (!_stricmp(cmd, "connect")) + { + if (m_ServerSocket && m_World) + { + NetAddress to; + m_ServerSocket->GetNetwork()->ResolveAddress(cmdLine.GetToken(1), &to); + + Connect(m_World, &to, m_ServerSocket); + BaseSystemModule::FireSignal(3); + } + else + { + m_System->Printf("ERROR! Server::ParseStuffText: received redirect while offline.\n"); + Disconnect(); + } + + return; + } + else if (!_stricmp(cmd, "rate") + || !_stricmp(cmd, "cl_updaterate") + || !_stricmp(cmd, "ex_interp") + || !_stricmp(cmd, "cl_cmdrate") + || !_stricmp(cmd, "cl_cmdbackup")) + { + return; + } + + if (m_ServerState == SERVER_CONNECTED) + { + m_World->AddSignonData(svc_stufftext, (unsigned char *)cmdLine.GetLine(), strlen(cmdLine.GetLine()) + 1); + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_UnreliableData.WriteByte(svc_stufftext); + m_UnreliableData.WriteString(cmdLine.GetLine()); + } + else + { + m_System->Errorf("Server::ParseStuffText: unexpected state.\n"); + } +} + +void Server::ParseUpdateUserInfo() +{ + unsigned char *start = m_Instream->CurrentByte(); + int playernumber = m_Instream->ReadByte(); + int userID = m_Instream->ReadLong(); + char *infostring = m_Instream->ReadString(); + + char hashedcdkey[16]; + m_Instream->ReadBuf(sizeof(hashedcdkey), hashedcdkey); + m_World->UpdatePlayer(playernumber, userID, infostring, hashedcdkey); + + if (m_ServerState == SERVER_CONNECTED) + { + /* do nothing */ + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_ReliableData.WriteByte(svc_updateuserinfo); + m_ReliableData.WriteBuf(start, m_Instream->CurrentByte() - start); + } + else + { + m_System->Errorf("Server::ParseUpdateUserInfo: unexpected state.\n"); + } +} + +void Server::ParseResourceList() +{ + m_Instream->StartBitMode(); + int total = m_Instream->ReadBits(12); + for (int i = 0; i < total; i++) + { + resource_t resource; + memset(&resource, 0, sizeof(resource)); + + resource.type = (resourcetype_t)m_Instream->ReadBits(4); + + strcopy(resource.szFileName, m_Instream->ReadBitString()); + + resource.nIndex = m_Instream->ReadBits(12); + resource.nDownloadSize = m_Instream->ReadBits(24); + resource.ucFlags = m_Instream->ReadBits(3); + + if (resource.ucFlags & RES_CUSTOM) { + m_Instream->ReadBitData(resource.rgucMD5_hash, sizeof(resource.rgucMD5_hash)); + } + + if (m_Instream->ReadBit()) { + m_Instream->ReadBitData(resource.rguc_reserved, sizeof(resource.rguc_reserved)); + } + + if (strncmp(resource.szFileName, "gfx/temp/", 9) != 0) { + m_World->AddResource(&resource); + } + } + + m_System->Printf("Added %i resources.\n", total); + + if (m_Instream->ReadBit()) + { + if (!IsDemoFile()) { + m_System->Printf("WARNING: HLTV proxy doesn't support file consistency check.\nWARNING: Disable mp_consistency on server."); + } + + while (m_Instream->ReadBit()) + { + if (m_Instream->ReadBit()) + m_Instream->ReadBits(5); + else + m_Instream->ReadBits(10); + } + } + + m_Instream->EndBitMode(); + + CRC32_t mungebuffer = m_ServerCRC; + COM_Munge2((byte *)&mungebuffer, sizeof(mungebuffer), (-1 - m_ServerCount) & 0xFF); + SendStringCommand(COM_VarArgs("spawn %i %i", m_ServerCount, mungebuffer)); +} + +static const int TE_LENGTH[TE_MAX] = +{ + 24, 20, 6, 11, 6, 10, 12, 17, 16, 6, 6, 6, 8, -1, 9, 19, + -2, 10, 16, 24, 24, 24, 10, 11, 16, 19, -2, 12, 16, -1, 19, 17, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, 2, 10, 14, 12, 14, 9, 5, 17, 13, 24, 9, 17, 7, + 10, 19, 19, 12, 7, 7, 9, 16, 18, 6, 10, 13, 7, 1, 18, 15, +}; + +void Server::ParseTempEntity() +{ + unsigned char *start = m_Instream->CurrentByte(); + int type = m_Instream->ReadByte(); + + if (type >= TE_MAX) { + m_System->Errorf("Server::ParseTempEntity:type >= TE_MAX.\n"); + return; + } + + int length = TE_LENGTH[type]; + if (length == -2) { + m_System->Errorf("Server::ParseTempEntity:invalid type %i.\n", type); + return; + } + + if (length == -1) + { + if (type == TE_BSPDECAL) + { + m_Instream->SkipBytes(8); + if (m_Instream->ReadWord()) + { + m_Instream->SkipBytes(2); + length = 12; + } + else + length = 10; + } + else if (type == TE_TEXTMESSAGE) + { + m_Instream->SkipBytes(5); + if (m_Instream->ReadByte() == 2) + { + m_Instream->SkipBytes(2); + length = 8; + } + else + length = 6; + + m_Instream->SkipBytes(14); + length += m_Instream->SkipString() + 14; + } + else + { + m_System->Printf("ERROR! Server::ParseTempEntity: unknown type with dynamic length.\n"); + } + } + else + { + m_Instream->SkipBytes(length); + } + + if (m_ServerState == SERVER_CONNECTED) + { + m_World->AddSignonData(svc_temp_entity, start, length + 1); + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_UnreliableData.WriteByte(svc_temp_entity); + m_UnreliableData.WriteBuf(start, length + 1); + } + else { + m_System->Errorf("Server::ParseTempEntity: unexpected server state.\n"); + } +} + +void Server::ParseBaseline() +{ + m_World->ParseBaseline(m_Instream); +} + +void Server::ParseVersion() +{ + int protocol = m_Instream->ReadLong(); + if (protocol != m_Protocol) { + m_System->Printf("Server::ParseVersion: Server is protocol %i instead of %i\n", protocol, PROTOCOL_VERSION); + } +} + +void Server::ParseTime() +{ + m_Time = m_Instream->ReadFloat(); + m_Frame.time = m_Time; +} + +void Server::ParseLightStyle() +{ + int index = m_Instream->ReadByte(); + char *style = m_Instream->ReadString(); + + if (m_ServerState == SERVER_CONNECTED) + { + m_World->AddLightStyle(index, style); + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_UnreliableData.WriteByte(svc_lightstyle); + m_UnreliableData.WriteByte(index); + m_UnreliableData.WriteString(style); + } + else + { + m_System->Errorf("Server::ParseLightStyle: unexpected server state.\n"); + } +} + +void Server::ParseSetAngle() +{ + if (m_ServerState == SERVER_CONNECTED) + { + m_World->AddSignonData(svc_setangle, m_Instream->CurrentByte(), 6); + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_UnreliableData.WriteByte(svc_setangle); + m_UnreliableData.WriteBuf(m_Instream->CurrentByte(), 6); + } + else + { + m_System->Errorf("Server::ParseSetAngle: unexpected server state.\n"); + } + + m_Instream->SkipBytes(6); +} + +void Server::ParseAddAngle() +{ + + if (m_ServerState == SERVER_CONNECTED) + { + m_World->AddSignonData(svc_addangle, m_Instream->CurrentByte(), 2); + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_UnreliableData.WriteByte(svc_addangle); + m_UnreliableData.WriteBuf(m_Instream->CurrentByte(), 2); + } + else + { + m_System->Errorf("Server::ParseAddAngle: unexpected server state.\n"); + } + + m_Instream->SkipBytes(2); +} + +void Server::ParseChoke() +{ +} + +void Server::ParseDisconnect() +{ + char *msg = m_Instream->ReadString(); + if (msg && *msg) { + m_System->Printf("Dropped from %s (%s).\n", m_ServerChannel.GetTargetAddress()->ToString(), msg); + } + else { + m_System->Printf("Dropped from %s.\n", m_ServerChannel.GetTargetAddress()->ToString()); + } + + if (IsConnected()) { + ScheduleAutoRetry(); + } + + Disconnect(); +} + +void Server::ParseFileTransferFailed() +{ + char *name = m_Instream->ReadString(); + if (!name || !name[0]) { + m_System->Printf("WARNING! Server::ParseFileTransferFailed: empty filename.\n"); + return; + } + + m_System->Printf("WARNING! Downloading \"%s\" failed.\n", name); +} + +void Server::ParseSignonNum() +{ + int num = m_Instream->ReadByte(); + m_System->DPrintf("Received signon (%i).\n", num); + + if (IsDemoFile()) + { + m_World->SetServerInfo(&m_DemoFile.m_ServerInfo); + } + else + { + m_ServerChannel.OutOfBandPrintf("details"); + + m_World->UpdateServerInfo(); + SendStringCommand("sendents"); + SendStringCommand("spectate"); + SendStringCommand(COM_VarArgs("VModEnable %d", m_IsVoiceBlocking ? 0 : 1)); + + char string[128]; + strcopy(string, "vban"); + + for (int i = 0; i < MAX_CLIENTS; i++) { + strcat(string, " 0"); + } + + SendStringCommand(string); + } + + SetState(SERVER_RUNNING); +} + +void Server::ParseCustomization() +{ + int index = m_Instream->ReadByte(); + if (index < 0 || index >= MAX_CLIENTS) + { + m_System->DPrintf("Bogus player index (%i) during customization parsing.\n", index); + m_Instream->m_Overflowed = true; + return; + } + + resource_t *resource = (resource_t *)Mem_ZeroMalloc(sizeof(resource_t)); + resource->type = (resourcetype_t)m_Instream->ReadByte(); + + strcopy(resource->szFileName, m_Instream->ReadString()); + + resource->nIndex = m_Instream->ReadShort(); + resource->nDownloadSize = m_Instream->ReadLong(); + resource->ucFlags = m_Instream->ReadByte() & (~RES_WASMISSING); + resource->pNext = nullptr; + + if (resource->ucFlags & RES_CUSTOM) { + m_Instream->ReadBuf(16, resource->rgucMD5_hash); + } + + resource->playernum = index; + m_System->DPrintf("Ignoring player customization (%s).\n", resource->szFileName); + free(resource); +} + +void Server::ClearFrame(bool completely) +{ + if (completely) + { + m_UserMessages.FastClear(); + m_ReliableData.FastClear(); + + m_Frame.reliableDataSize = 0; + m_Frame.userMessagesSize = 0; + } + + m_UnreliableData.FastClear(); + m_VoiceData.FastClear(); + m_ClientData.FastClear(); + m_DemoData.FastClear(); + + m_Frame.time = 0; + m_Frame.entities = 0; + m_Frame.entitynum = 0; + m_Frame.entitiesSize = 0; + m_Frame.events = 0; + m_Frame.eventnum = 0; + m_Frame.eventsSize = 0; + m_Frame.demoInfo = 0; + + memset(&m_DemoInfo, 0, sizeof(m_DemoInfo)); + m_Frame.unreliableDataSize = 0; + m_Frame.voiceDataSize = 0; + m_Frame.clientDataSize = 0; + m_Frame.demoDataSize = 0; +} + +bool Server::ParseUserMessage(int cmd) +{ + UserMsg *usermsg = m_World->GetUserMsg(cmd); + if (!usermsg) { + m_System->Printf("WARNING! Server::ProcessMessage: unknown user message (%i).\n", cmd); + return false; + } + + unsigned char *start = m_Instream->CurrentByte(); + + int length = 0; + int msgSize = usermsg->iSize; + + if (msgSize == -1) { + msgSize = m_Instream->ReadByte(); + length = msgSize + 1; + } + else + length = msgSize; + + if (msgSize > MAX_USER_MSG_DATA) { + m_System->Printf("WARNING! Server::ParseUserMessage: User Msg %d sent too much data (%i bytes)\n", cmd, msgSize); + return false; + } + + m_Instream->SkipBytes(msgSize); + + if (m_ServerState == SERVER_CONNECTED) + { + m_World->AddSignonData(cmd, start, length); + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_UserMessages.WriteByte(cmd); + m_UserMessages.WriteBuf(start, length); + } + else + { + m_System->Printf("WARNING! Server::ParseUserMessage: unexpected server state.\n"); + } + + if (!strcmp(usermsg->szName, "SayText")) + { + m_System->Printf("%s\n", start + 2); + } + else if (!strcmp(usermsg->szName, "TextMsg")) + { + m_System->DPrintf("%s\n", start + 2); + } + else if (!strcmp(usermsg->szName, "ReqState")) + { + char cmdString[32]; + _snprintf(cmdString, sizeof(cmdString), "VModEnable %d", m_IsVoiceBlocking == 0); + SendStringCommand(cmdString); + + char string[128]; + strcopy(string, "vban"); + + for (int i = 0; i < MAX_CLIENTS; i++) { + strcat(string, " 0"); + } + + SendStringCommand(string); + } + + return true; +} + +void Server::ParsePacketEntities() +{ + int entnum = m_Instream->ReadShort(); + if (entnum > MAX_PACKET_ENTITIES) { + m_System->Errorf("ERROR! Server::ParsePacketEntities: entnum > MAX_PACKET_ENTITIES.\n"); + m_Instream->m_Overflowed = true; + return; + } + + m_Frame.delta = 0; + m_Frame.entitynum = entnum; + m_Frame.entitiesSize = sizeof(entity_state_t) * entnum; + m_Frame.entities = m_EntityBuffer; + + memset(m_EntityBuffer, 0, m_Frame.entitiesSize); + m_World->UncompressEntitiesFromStream(&m_Frame, m_Instream); +} + +void Server::ParseDeltaPacketEntities() +{ + int entnum = m_Instream->ReadShort(); + if (entnum > MAX_PACKET_ENTITIES) { + m_System->Errorf("Server::ParsePacketEntities: entnum > MAX_PACKET_ENTITIES.\n"); + } + + m_Frame.delta = 0; + m_Frame.entitynum = entnum; + m_Frame.entitiesSize = sizeof(entity_state_t) * entnum; + m_Frame.entities = m_EntityBuffer; + memset(m_EntityBuffer, 0, m_Frame.entitiesSize); + + int from = m_Instream->ReadByte(); + if (!m_World->UncompressEntitiesFromStream(&m_Frame, m_Instream, m_SeqNrMap[from])) { + m_Instream->m_Overflowed = true; + } +} + +void Server::SendServerCommands() +{ + if (m_validSequence && m_ServerState >= SERVER_RUNNING) + { + m_ServerChannel.m_unreliableStream.WriteByte(clc_delta); + m_ServerChannel.m_unreliableStream.WriteByte(m_validSequence & 0xFF); + } + + m_ServerChannel.TransmitOutgoing(); +} + +void Server::ParseSound() +{ + m_Instream->StartBitMode(); + + vec3_t pos; + unsigned char *start = this->m_Instream->m_CurByte; + int field_mask = m_Instream->ReadBits(9); + + if (field_mask & SND_FL_VOLUME) { + m_Instream->ReadBits(8); + } + + if (field_mask & SND_FL_ATTENUATION) { + m_Instream->ReadBits(8); + } + + m_Instream->ReadBits(22); + + if (field_mask & SND_FL_LARGE_INDEX) { + m_Instream->ReadBits(8); + } + + m_Instream->ReadBitVec3Coord(pos); + + if (field_mask & SND_FL_PITCH) { + m_Instream->ReadBits(8); + } + + m_Instream->EndBitMode(); + + m_UnreliableData.WriteByte(6); + m_UnreliableData.WriteBuf(start, m_Instream->m_CurByte - start); +} + +void Server::ParseEvent() +{ + m_Instream->StartBitMode(); + + m_Frame.events = m_Instream->m_CurByte; + m_Frame.eventnum = m_Instream->ReadBits(5); + + for (unsigned int i = 0; i < m_Frame.eventnum; i++) + { + m_Instream->SkipBits(10); + if (m_Instream->ReadBit()) + m_Instream->SkipBits(11); + + if (m_Instream->ReadBit()) + m_World->ParseEvent(m_Instream); + + if (m_Instream->ReadBit()) + m_Instream->SkipBits(16); + } + + m_Instream->EndBitMode(); + m_Frame.eventsSize = m_Instream->CurrentByte() - m_Frame.events; +} + +void Server::ParseStopSound() +{ + int i = m_Instream->ReadShort(); + + m_UnreliableData.WriteByte(svc_stopsound); + m_UnreliableData.WriteShort(i); +} + +void Server::ParsePings() +{ + m_Instream->StartBitMode(); + + unsigned char *start = m_Instream->CurrentByte(); + while (m_Instream->ReadBit()) { + m_Instream->ReadBits(24); + } + + m_Instream->EndBitMode(); + + m_UnreliableData.WriteByte(svc_pings); + m_UnreliableData.WriteBuf(start, m_Instream->CurrentByte() - start); +} + +void Server::ParseEventReliable() +{ + m_Instream->StartBitMode(); + + unsigned char *start = m_Instream->CurrentByte(); + + m_Instream->SkipBits(10); + m_World->ParseEvent(m_Instream); + + if (m_Instream->ReadBit()) { + m_Instream->SkipBits(16); + } + + m_Instream->EndBitMode(); + + m_ReliableData.WriteByte(svc_event_reliable); + m_ReliableData.WriteBuf(start, m_Instream->CurrentByte() - start); +} + +void Server::ParseSpawnStaticSound() +{ + if (m_ServerState == SERVER_CONNECTED) { + m_World->AddSignonData(svc_spawnstaticsound, m_Instream->CurrentByte(), 14); + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_UnreliableData.WriteByte(svc_spawnstaticsound); + m_UnreliableData.WriteBuf(m_Instream->CurrentByte(), 14); + } + else { + m_System->Errorf("Server::ParseSpawnStaticSound: unexpected server state.\n"); + } + + m_Instream->SkipBytes(14); +} + +void Server::ParseRoomType() +{ + m_ReliableData.WriteByte(svc_roomtype); + m_ReliableData.WriteShort(m_Instream->ReadShort()); +} + +void Server::ParseParticle() +{ + m_UnreliableData.WriteByte(svc_particle); + m_UnreliableData.WriteBuf(m_Instream->CurrentByte(), 11); + + m_Instream->SkipBytes(11); +} + +InfoString *Server::GetServerInfoString() +{ + return &m_ServerInfo; +} + +int Server::GetRate() +{ + return m_Rate; +} + +int Server::GetUpdateRate() +{ + return m_UpdateRate; +} + +char *Server::GetHostName() +{ + return m_HostName; +} + +int Server::GetProtocol() +{ + return m_Protocol; +} + +bool Server::SetProtocol(int version) +{ + if (version != 46 + && version != 47 + && version != PROTOCOL_VERSION) { + return false; + } + + m_Protocol = version; + return true; +} + +void Server::SetPlayerName(char *newName) +{ + COM_RemoveEvilChars(newName); + SetUserInfo("name", newName); +} + +char *Server::GetPlayerName() +{ + return m_UserInfo.ValueForKey("name"); +} + +char *Server::GetType() +{ + return SERVER_INTERFACE_VERSION; +} + +IWorld *Server::GetWorld() +{ + return m_World; +} + +NetAddress *Server::GetAddress() +{ + if (IsDemoFile()) { + return nullptr; + } + + return &m_ServerAddress; +} + +char *Server::GetDemoFileName() +{ + if (!IsDemoFile()) { + return nullptr; + } + + return m_DemoFile.GetFileName(); +} + +bool Server::GetAutoRetry() +{ + return m_AutoRetry; +} + +float Server::GetPacketLoss() +{ + return m_ServerChannel.GetLoss(); +} + +char *Server::GetStatusLine() +{ + float in, out; + static char string[256]; + + switch (m_ServerState) + { + case SERVER_INITIALIZING: + _snprintf(string, sizeof(string), "Initializing.\n"); + break; + case SERVER_DISCONNECTED: + _snprintf(string, sizeof(string), "Disconnected.\n"); + break; + case SERVER_CHALLENGING: + _snprintf(string, sizeof(string), "challenging %s.\n", m_ServerChannel.GetTargetAddress()->ToString()); + break; + case SERVER_AUTHENTICATING: + _snprintf(string, sizeof(string), "Authenticating.\n"); + break; + case SERVER_CONNECTING: + _snprintf(string, sizeof(string), "Connecting to %s.\n", m_ServerChannel.GetTargetAddress()->ToString()); + break; + case SERVER_CONNECTED: + case SERVER_RUNNING: + m_ServerChannel.GetFlowStats(&in, &out); + _snprintf(string, sizeof(string), "Connected to %s, Time %.0f, In %.2f, Out %.2f.\n", m_ServerChannel.GetTargetAddress()->ToString(), m_SystemTime - m_ServerChannel.m_connect_time, in, out); + break; + case SERVER_INTERMISSION: + _snprintf(string, sizeof(string), "Intermission (%s).\n", m_ServerChannel.GetTargetAddress()->ToString()); + break; + default: + m_System->Errorf("Server::GetStatusLine: not valid state.\n"); + break; + } + + return string; +} + +void Server::ParseHLTV() +{ + unsigned char *start = m_Instream->CurrentByte(); + unsigned char cmd = m_Instream->ReadByte(); + + switch (cmd) + { + case HLTV_ACTIVE: + m_IsHLTV = true; + m_ForceHLTV = false; + break; + case HLTV_STATUS: + { + if (m_Proxy) { + m_Proxy->ParseStatusMsg(m_Instream); + return; + } + + m_Instream->SkipBytes(10); + break; + } + case HLTV_LISTEN: + m_System->Printf("WARNING! Server::ParseHLTV: unexpected \"listen\" command.\n"); + break; + default: + m_System->Printf("WARNING! Server::ParseHLTV: unknown director command.\n"); + m_Instream->m_Overflowed = true; + break; + } +} + +void Server::SetProxy(IProxy *proxy) +{ + m_Proxy = proxy; + m_Director = proxy->GetDirector(); +} + +void Server::SetDirector(IDirector *director) +{ + m_Director = director; +} + +void Server::ParseDirector() +{ + unsigned char *start = m_Instream->CurrentByte(); + int length = m_Instream->ReadByte(); + + if (m_Director) + { + DirectorCmd cmd; + cmd.ReadFromStream(m_Instream); + cmd.SetTime(m_Time); + + m_Director->AddCommand(&cmd); + return; + } + + m_Instream->SkipBytes(length); + + if (m_ServerState == SERVER_CONNECTED) { + m_World->AddSignonData(svc_director, start, length + 1); + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_ReliableData.WriteByte(svc_director); + m_ReliableData.WriteBuf(start, length + 1); + } + else { + m_System->Errorf("Server::ParseDirector: unexpected server state.\n"); + } +} + +void Server::ParseInfo(BitBuffer *stream, bool detailed) +{ + serverinfo_t si; + + strcopy(si.address, m_ServerChannel.GetTargetAddress()->ToBaseString()); + strcopy(si.name, stream->ReadString()); + strcopy(si.map, stream->ReadString()); + strcopy(si.gamedir, stream->ReadString()); + strcopy(si.description, stream->ReadString()); + + si.activePlayers = stream->ReadByte(); + si.maxPlayers = stream->ReadByte(); + si.protocol = stream->ReadByte(); + + if (detailed) + { + si.type = stream->ReadByte(); + si.os = stream->ReadByte(); + si.pw = stream->ReadByte(); + si.mod = stream->ReadByte() != 0; + + if (si.mod) + { + strcopy(si.url_info, stream->ReadString()); + strcopy(si.url_dl, stream->ReadString()); + strcopy(si.hlversion, stream->ReadString()); + + si.ver = stream->ReadLong(); + si.size = stream->ReadLong(); + si.svonly = stream->ReadByte() != 0; + si.cldll = stream->ReadByte() != 0; + } + else + { + si.url_info[0] = '\0'; + si.url_dl[0] = '\0'; + + si.ver = 0; + si.size = 0; + } + + stream->ReadByte(); + } + else + { + si.type = '?'; + si.os = '?'; + si.pw = '?'; + si.mod = 0; + } + + if (si.activePlayers >= MAX_PROXY_CLIENTS || si.maxPlayers >= MAX_PROXY_CLIENTS) + { + si.activePlayers = stream->ReadLong(); + si.maxPlayers = stream->ReadLong(); + } + + if (m_World) { + m_World->SetServerInfo(&si); + } +} + +void Server::Reconnect() +{ + if (IsConnected()) + { + m_System->DPrintf("Reconnecting...\n"); + SetState(SERVER_CONNECTED); + + m_ServerChannel.Clear(); + m_validSequence = 0; + + BaseSystemModule::FireSignal(2); + SendStringCommand("new"); + } +} + +void Server::Disconnect() +{ + if (m_ServerState == SERVER_DISCONNECTED) { + return; + } + + BaseSystemModule::FireSignal(6); + m_ServerChannel.ClearFragments(); + + if (IsDemoFile()) + { + m_DemoFile.StopPlayBack(); + m_System->Printf("Demo playback stopped.\n"); + } + else + { + for (int i = 0; i < 3; i++) + { + SendStringCommand("dropclient\n"); + m_ServerChannel.TransmitOutgoing(); + } + + m_System->Printf("Disconnected.\n"); + } + + m_World->FinishGame(); + Reset(); + ScheduleAutoRetry(); + m_ServerChannel.Close(); +} + +void Server::ParseClientData() +{ + if (m_IsHLTV) { + return; + } + + unsigned int fromSeqNr = 0; + m_Instream->StartBitMode(); + + if (m_Instream->ReadBit()) { + fromSeqNr = m_SeqNrMap[m_Instream->ReadByte()]; + } + + m_World->ParseClientData(m_Instream, fromSeqNr, &m_ClientData, &m_ClientDataStruct); + m_Instream->EndBitMode(); +} + +void Server::ParseIntermission() +{ + SetState(SERVER_INTERMISSION); + + if (!IsDemoFile()) { + m_ReliableData.WriteByte(svc_intermission); + } +} + +void Server::ParseFinale() +{ + m_ReliableData.WriteByte(svc_finale); + m_ReliableData.WriteString(m_Instream->ReadString()); +} + +void Server::ParseCutscene() +{ + m_ReliableData.WriteByte(svc_cutscene); + m_ReliableData.WriteString(m_Instream->ReadString()); +} + +void Server::SendUserVar(char *key, char *value) +{ + char cmdString[1024]; + + if (!IsConnected()) { + return; + } + + if (*value) + { + _snprintf(cmdString, sizeof(cmdString), "setinfo \"%s\" \"%s\"\n", key, value); + SendStringCommand(cmdString); + } +} + +bool Server::IsConnected() +{ + if (m_ServerState >= SERVER_CONNECTED) { + return true; + } + + return false; +} + +bool Server::IsDemoFile() +{ + return m_DemoFile.IsPlaying(); +} + +bool Server::IsGameServer() +{ + return m_IsGameServer; +} + +bool Server::IsRelayProxy() +{ + return !m_IsGameServer; +} + +void Server::ParseCenterPrint() +{ + char *string = m_Instream->ReadString(); + if (m_ServerState == SERVER_CONNECTED) + { + m_World->AddSignonData(svc_centerprint, (unsigned char *)string, strlen(string) + 1); + } + else if (m_ServerState == SERVER_RUNNING || m_ServerState == SERVER_INTERMISSION) + { + m_UnreliableData.WriteByte(svc_centerprint); + m_UnreliableData.WriteString(string); + } + else { + m_System->Errorf("Server::ParseStuffText: unexpected state.\n"); + } +} + +void Server::CheckAutoRetry() +{ + if (m_NextAutoRetry > 0 && m_NextAutoRetry < m_SystemTime) + { + m_NextAutoRetry = 0; + + Retry(); + m_System->Printf("Automatic connection retry...\n"); + } +} + +void Server::ScheduleAutoRetry() +{ + if (m_AutoRetry) { + m_NextAutoRetry = m_SystemTime + 4; + return; + } + + m_NextAutoRetry = 0; +} + +bool Server::Connect(IWorld *world, NetAddress *address, INetSocket *socket) +{ + if (!socket || !world || !address) { + m_System->Printf("ERROR! Server::Connect: invalid parameters.\n"); + return false; + } + + INetwork *network = socket->GetNetwork(); + if (address->Equal(network->GetLocalAddress())) { + m_System->Printf("ERROR! Server::Connect: can't connect to myself.\n"); + return false; + } + + Reset(); + m_ServerAddress.FromNetAddress(address); + + m_ServerSocket = socket; + m_ServerChannel.Create(m_System, m_ServerSocket, &m_ServerAddress); + m_World = world; + + SetState(SERVER_CHALLENGING); + return true; +} + +bool Server::LoadDemo(IWorld *world, char *filename, bool forceHLTV, bool continuous) +{ + Reset(); + m_World = world; + m_ServerSocket = nullptr; + + m_ServerChannel.Create(m_System); + m_DemoFile.Init(m_World, this, &m_ServerChannel); + + if (!m_DemoFile.LoadDemo(filename)) { + return false; + } + + m_DemoFile.SetContinuous(continuous); + + m_IsHLTV = false; + m_ForceHLTV = forceHLTV; + + SetState(SERVER_CONNECTED); + m_ServerChannel.SetConnected(true); + + return true; +} + +void Server::SetUserInfo(char *key, char *value) +{ + if (!key || !value) { + return; + } + + m_UserInfo.SetValueForKey(key, value); + SendUserVar(key, value); +} + +void Server::ParseSetPause() +{ + m_IsPaused = m_Instream->ReadByte() != 0; + if (!m_IsPaused) { + m_validSequence = 0; + } + + m_World->SetPaused(m_IsPaused); +} + +void Server::SendStringCommand(char *command) +{ + if (!m_ServerChannel.IsFakeChannel()) + { + m_ServerChannel.m_reliableStream.WriteByte(clc_stringcmd); + m_ServerChannel.m_reliableStream.WriteString(command); + } +} + +void Server::SendHLTVCommand(BitBuffer *msg) +{ + if (!m_ServerChannel.IsFakeChannel()) + { + m_ServerChannel.m_reliableStream.WriteByte(clc_hltv); + m_ServerChannel.m_reliableStream.WriteBuf(msg->GetData(), msg->CurrentSize()); + } +} + +void Server::ParseSendExtraInfo() +{ + char *clientfallback = m_Instream->ReadString(); + int allowCheats = m_Instream->ReadByte(); + + m_World->SetExtraInfo(clientfallback, allowCheats); +} + +void Server::ParseTimeScale() +{ + float timescale = m_Instream->ReadFloat(); + if (m_Director) { + return; + } + + if (m_ServerState == SERVER_CONNECTED) + { + m_System->Printf("Server::ParseTimeScale: invalid during signon.\n"); + } + else if (m_ServerState == SERVER_RUNNING && m_ServerState == SERVER_INTERMISSION) + { + m_ReliableData.WriteByte(svc_timescale); + m_ReliableData.WriteFloat(timescale); + } + else { + m_System->Errorf("Server::ParseTimeScale: unexpected server state.\n"); + } +} + +void Server::ParseResourceLocation() +{ + char *url = m_Instream->ReadString(); + if (url) { + strcopy(g_DownloadURL, url); + } +} + +float Server::GetTime() +{ + return m_Time; +} + +void Server::CheckConnection() +{ + if (m_ServerState == SERVER_DISCONNECTED) { + return; + } + + if (!m_ServerChannel.IsTimedOut() && !m_ServerChannel.IsCrashed()) { + return; + } + + m_System->Printf("Server connection lost (%s).\n", m_ServerChannel.IsCrashed() ? "data mismatch" : "time out"); + + Disconnect(); + ScheduleAutoRetry(); +} + +void Server::StopRetry() +{ + m_NextAutoRetry = 0; +} + +void Server::Retry() +{ + if (m_ServerAddress.IsValid() && m_ServerSocket && m_World) + { + Connect(m_World, &m_ServerAddress, m_ServerSocket); + BaseSystemModule::FireSignal(7); + } + else + { + m_System->DPrintf("HLTV proxy wasn't connected before.\n"); + } +} + +void Server::SetAutoRetry(bool state) +{ + if (!state) { + m_NextAutoRetry = 0; + } + + m_AutoRetry = state; +} + +void Server::SetDelayReconnect(bool state) +{ + m_DelayReconnect = state; +} + +void Server::Reset() +{ + m_ServerChannel.ClearFragments(); + m_ServerChannel.Close(); + + ClearFrame(true); + memset(m_SeqNrMap, 0, sizeof(m_SeqNrMap)); + + m_validSequence = 0; + m_CurrentRetry = 0; + m_IsHLTV = true; + m_ForceHLTV = false; + m_IsPaused = false; + m_IsGameServer = false; + m_Time = 0; + + m_DemoFile.Reset(); + SetState(SERVER_DISCONNECTED); +} + +char *Server::GetCmdName(int cmd) +{ + static char description[64]; + if (cmd > svc_startofusermessages && m_World) + { + UserMsg *usermsg = m_World->GetUserMsg(cmd); + if (usermsg) + { + _snprintf(description, sizeof(description), "UserMsg:%s", usermsg->szName); + } + else + { + _snprintf(description, sizeof(description), "Invalid UserMsg"); + } + } + else + { + _snprintf(description, sizeof(description), "EngMsg:%s", m_ClientFuncs[cmd].pszname); + } + + return description; +} + +void Server::SetName(char *newName) +{ + strcopy(m_Name, newName); +} + +void Server::ProcessEntityUpdate() +{ + if (!m_Frame.entities) { + return; + } + + for (unsigned int num = 0; num < m_Frame.entitynum; num++) + { + entity_state_t *state = &((entity_state_t *)m_Frame.entities)[num]; + if (m_ClientPlayerNum == state->number - 1) + { + state->origin[0] = m_ClientDataStruct.origin[0]; + state->origin[1] = m_ClientDataStruct.origin[1]; + state->origin[2] = m_ClientDataStruct.origin[2]; + } + } +} + +void Server::ParseSendCvarValue() +{ + char *name = m_Instream->ReadString(); +} + +void Server::ParseSendCvarValue2() +{ + int requestID = m_Instream->ReadLong(); + char *name = m_Instream->ReadString(); +} + +void Server::ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) +{ + BaseSystemModule::ReceiveSignal(module, signal, data); +} + +void Server::RegisterListener(ISystemModule *module) +{ + BaseSystemModule::RegisterListener(module); +} + +void Server::RemoveListener(ISystemModule *module) +{ + BaseSystemModule::RemoveListener(module); +} + +IBaseSystem *Server::GetSystem() +{ + return BaseSystemModule::GetSystem(); +} + +int Server::GetSerial() +{ + return BaseSystemModule::GetSerial(); +} + +char *Server::GetName() +{ + return BaseSystemModule::GetName(); +} + +int Server::GetState() +{ + return BaseSystemModule::GetState(); +} + +int Server::GetVersion() +{ + return BaseSystemModule::GetVersion(); +} + +IBaseInterface *CreateServer() +{ + IServer *pServer = new Server; + return (IBaseInterface *)pServer; +} + +#ifndef HOOK_HLTV +EXPOSE_INTERFACE_FN(CreateServer, Server, SERVER_INTERFACE_VERSION); +#endif // HOOK_HLTV diff --git a/rehlds/HLTV/Core/src/Server.h b/rehlds/HLTV/Core/src/Server.h new file mode 100644 index 0000000..f238424 --- /dev/null +++ b/rehlds/HLTV/Core/src/Server.h @@ -0,0 +1,266 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include +#include "BaseSystemModule.h" +#include "TokenLine.h" + +class IWorld; +class IProxy; +class IDirector; +class IFileSystem; +class NetPacket; +class INetSocket; + +#define MAX_SERVER_RATE 20000 +#define MAX_SERVER_UPDATERATE 100 + +#define TE_MAX 128 + +// Sound flags +enum +{ + SND_FL_VOLUME = BIT(0), // send volume + SND_FL_ATTENUATION = BIT(1), // send attenuation + SND_FL_LARGE_INDEX = BIT(2), // send sound number as short instead of byte + SND_FL_PITCH = BIT(3), // send pitch + SND_FL_SENTENCE = BIT(4), // set if sound num is actually a sentence num + SND_FL_STOP = BIT(5), // stop the sound + SND_FL_CHANGE_VOL = BIT(6), // change sound vol + SND_FL_CHANGE_PITCH = BIT(7), // change sound pitch + SND_FL_SPAWNING = BIT(8) // we're spawning, used in some cases for ambients (not sent across network) +}; + +class Server: public IServer, public BaseSystemModule { +public: + Server() {} + virtual ~Server() {} + + bool Init(IBaseSystem *system, int serial, char *name); + void RunFrame(double time); + void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data); + void ExecuteCommand(int commandID, char *commandLine); + void RegisterListener(ISystemModule *module); + void RemoveListener(ISystemModule *module); + IBaseSystem *GetSystem(); + int GetSerial(); + char *GetStatusLine(); + char *GetType(); + char *GetName(); + int GetState(); + int GetVersion(); + void ShutDown(); + + bool Connect(IWorld *world, NetAddress *address, INetSocket *socket); + bool LoadDemo(IWorld *world, char *filename, bool forceHLTV, bool continuous); + void Reconnect(); + void Disconnect(); + void Retry(); + void StopRetry(); + void SendStringCommand(char *command); + void SendHLTVCommand(BitBuffer *msg); + void SetPlayerName(char *newName); + void SetProxy(IProxy *proxy); + void SetDirector(IDirector *director); + void SetDelayReconnect(bool state); + void SetAutoRetry(bool state); + void SetVoiceBlocking(bool state); + void SetRate(int rate); + void SetUpdateRate(int updaterate); + void SetUserInfo(char *key, char *value); + bool SetProtocol(int version); + void SetGameDirectory(const char *defaultDir, const char *gameDir); + bool IsConnected(); + bool IsDemoFile(); + bool IsGameServer(); + bool IsRelayProxy(); + bool IsVoiceBlocking(); + int GetRate(); + int GetUpdateRate(); + char *GetPlayerName(); + InfoString *GetServerInfoString(); + + float GetTime(); + IWorld *GetWorld(); + char *GetDemoFileName(); + NetAddress *GetAddress(); + bool GetAutoRetry(); + char *GetHostName(); + float GetPacketLoss(); + int GetProtocol(); + +private: +public: + void CheckAutoRetry(); + void CheckConnection(); + void ScheduleAutoRetry(); + void AcceptConnection(); + void AcceptBadPassword(); + void AcceptRejection(char *reason); + void AcceptRedirect(char *toAddress); + void SendConnectPacket(); + void SendServerCommands(); + + enum ServerState { + SERVER_UNDEFINED, + SERVER_INITIALIZING, + SERVER_DISCONNECTED, + SERVER_CHALLENGING, + SERVER_AUTHENTICATING, + SERVER_CONNECTING, + SERVER_CONNECTED, + SERVER_RUNNING, + SERVER_INTERMISSION, + }; + + void SetState(ServerState newState); + void Challenge(); + void Reset(); + void AcceptChallenge(char *cmdLine); + void SendUserVar(char *key, char *value); + char *GetCmdName(int cmd); + void SetName(char *newName); + void ProcessMessage(unsigned int seqNr); + void ProcessEntityUpdate(); + bool ProcessConnectionlessMessage(NetAddress *from, BitBuffer *stream); + void ClearFrame(bool completely); + void ParseHLTV(); + void ParseDirector(); + void ParseFileTransferFailed(); + void ParseInfo(BitBuffer *stream, bool detailed); + void ParseParticle(); + void ParseRoomType(); + void ParseSpawnStaticSound(); + void ParseEventReliable(); + void ParsePings(); + void ParseStopSound(); + void ParseEvent(); + void ParseSound(); + void ParseDeltaPacketEntities(); + void ParsePacketEntities(); + bool ParseUserMessage(int cmd); + void ParseCustomization(); + void ParseCrosshairAngle(); + void ParseSoundFade(); + void ParseSignonNum(); + void ParseDisconnect(); + void ParseChoke(); + void ParseSetAngle(); + void ParseAddAngle(); + void ParseLightStyle(); + void ParseTime(); + void ParseVersion(); + void ParseBaseline(); + void ParseTempEntity(); + void ParseResourceList(); + void ParseUpdateUserInfo(); + void ParseStuffText(); + void ParseNewUserMsg(); + void ParseResourceRequest(); + void ParseSetView(); + void ParseCDTrack(); + void ParseRestore(); + void ParseMoveVars(); + void ParseDeltaDescription(); + void ParseServerinfo(); + void ParseBad(); + void ParseNop(); + void ParsePrint(); + void ParseVoiceInit(); + void ParseVoiceData(); + void ParseTimeScale(); + void ParseSendExtraInfo(); + void ParseCenterPrint(); + void ParseSetPause(); + void ParseCutscene(); + void ParseWeaponAnim(); + void ParseDecalName(); + void ParseFinale(); + void ParseIntermission(); + void ParseClientData(); + void ParseResourceLocation(); + void ParseSendCvarValue(); + void ParseSendCvarValue2(); + +protected: + struct svc_func_s { + svc_commands_e opcode; + char *pszname; + void (Server::*func)(); + }; + static svc_func_s m_ClientFuncs[]; + + IWorld *m_World; + IProxy *m_Proxy; + IDirector *m_Director; + IFileSystem *m_FileSystem; + int m_ChallengeNumber; + + INetSocket *m_ServerSocket; + NetChannel m_ServerChannel; + NetAddress m_ServerAddress; + + int m_ServerState; + char m_HostName[MAX_PATH]; + int m_CurrentRetry; + InfoString m_UserInfo; + char m_CDKey[32]; + int m_AuthProtocol; + frame_t m_Frame; + unsigned char m_EntityBuffer[87040]; + int m_Rate; + int m_UpdateRate; + float m_Time; + BitBuffer m_ReliableData; + BitBuffer m_UnreliableData; + BitBuffer m_VoiceData; + BitBuffer m_UserMessages; + BitBuffer m_ClientData; + BitBuffer *m_Instream; + int m_validSequence; + bool m_AutoRetry; + double m_NextAutoRetry; + bool m_IsHLTV; + bool m_ForceHLTV; + bool m_IsGameServer; + bool m_IsPaused; + bool m_IsVoiceBlocking; + DemoFile m_DemoFile; + demo_info_t m_DemoInfo; + BitBuffer m_DemoData; + CRC32_t m_ServerCRC; + int m_ServerCount; + int m_ClientPlayerNum; + int m_Protocol; + clientdata_t m_ClientDataStruct; + InfoString m_ServerInfo; + bool m_DelayReconnect; + unsigned int m_SeqNrMap[256]; +}; diff --git a/rehlds/HLTV/Core/src/World.cpp b/rehlds/HLTV/Core/src/World.cpp new file mode 100644 index 0000000..54e0669 --- /dev/null +++ b/rehlds/HLTV/Core/src/World.cpp @@ -0,0 +1,2380 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +char g_DownloadURL[128]; + +bool World::Init(IBaseSystem *system, int serial, char *name) +{ + BaseSystemModule::Init(system, serial, name); + SetState(WORLD_INITIALIZING); + + if (!name) { + SetName(WORLD_INTERFACE_VERSION); + } + + m_ClientUserMsgs = 0; + m_ResourcesList = 0; + m_ResourcesNum = 0; + m_Protocol = PROTOCOL_VERSION; + + m_SignonData.Resize(MAX_BUFFER_SIGNONDATA); + m_ServerInfo.SetMaxSize(MAX_SERVERINFO_STRING); + + memset(m_HostName, 0, sizeof(m_HostName)); + strcopy(m_ServerName, "Unnamed HLTV"); + + m_Frames.Init(); + m_FramesByTime.Init(); + + m_WorldModel.Init(system); + m_Delta.Init(system); + + m_MaxBufferLength = -1.0f; + m_MaxCacheIndex = MAX_FRAME_CACHE; + + char *maxCacheparam = m_System->CheckParam("-cachesize"); + if (maxCacheparam) { + m_MaxCacheIndex = atoi(maxCacheparam); + } + + if (m_MaxCacheIndex <= 0) { + m_MaxCacheIndex = MAX_FRAME_CACHE; + } + + m_FrameCache = (frameCache_t *)Mem_ZeroMalloc(sizeof(frameCache_t) * m_MaxCacheIndex); + m_DeltaCache = (deltaCache_t *)Mem_ZeroMalloc(sizeof(deltaCache_t) * m_MaxCacheIndex); + + if (!m_FrameCache || !m_DeltaCache) { + m_System->Errorf("World::Init: Not enough memory for caches. Reduce -cachesize.\n"); + return false; + } + + Reset(); + SetState(WORLD_DISCONNECTED); + m_State = MODULE_RUNNING; + m_System->Printf("World module initialized.\n"); + + return true; +} + +void World::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) { + return; + } + + Reset(); + SetState(WORLD_DISCONNECTED); + BaseSystemModule::FireSignal(8); + + m_Delta.Shutdown(); + m_Listener.Clear(); + + if (m_DeltaCache) + { + free(m_DeltaCache); + m_DeltaCache = nullptr; + } + + if (m_FrameCache) + { + free(m_FrameCache); + m_FrameCache = nullptr; + } + + BaseSystemModule::ShutDown(); + m_System->Printf("World module shutdown.\n"); +} + +void World::Reset() +{ + ClearUserMessages(); + ClearResources(); + ClearBaseline(); + ClearInstancedBaseline(); + ClearLightStyles(); + ClearPlayers(); + ClearEntityCache(); + ClearServerInfo(); + ClearFrames(); + + m_SignonData.Clear(); + m_WorldModel.Clear(); + + m_SequenceNr = 0; + m_ViewEntity = 0; + m_WorldTime = 0; + m_StartTime = 0; + m_VoiceEnabled = false; + + memset(m_ClientFallback, 0, sizeof(m_ClientFallback)); + + m_AllowCheats = false; + m_IsHLTV = false; + m_IsPaused = false; + + m_GameServerAddress.Clear(); + g_DownloadURL[0] = '\0'; +} + +bool World::SetMaxClients(int max) +{ + if (max <= 0 || max > MAX_CLIENTS) { + m_System->Printf("WARNING! World::SetMaxClients: Bad maxclients (%u)\n", max); + return false; + } + + m_Maxclients = max; + return true; +} + +void World::ClearUserMessages() +{ + UserMsg *pList, *pNext; + for (pList = m_ClientUserMsgs; pList; pList = pNext) + { + pNext = pList->next; + free(pList); + } + + m_ClientUserMsgs = nullptr; +} + +bool World::AddUserMessage(int msgNumber, int size, char *name) +{ + UserMsg umsg; + memset(&umsg, 0, sizeof(umsg)); + + umsg.iMsg = msgNumber; + umsg.iSize = size; + + if (size == 255) { + umsg.iSize = -1; + } + + strcopy(umsg.szName, name); + + bool bFound = false; + for (UserMsg *pList = m_ClientUserMsgs; pList; pList = pList->next) + { + if (!_stricmp(pList->szName, umsg.szName)) { + bFound = true; + pList->iMsg = umsg.iMsg; + pList->iSize = umsg.iSize; + } + } + + if (!bFound) + { + UserMsg *pumsg = (UserMsg *)malloc(sizeof(UserMsg)); + memcpy(pumsg, &umsg, sizeof(*pumsg)); + pumsg->next = m_ClientUserMsgs; + m_ClientUserMsgs = pumsg; + return true; + } + + return false; +} + +void World::UpdatePlayer(int playerNum, int userId, char *infostring, char *hashedcdkey) +{ + InfoString infostr(infostring); + if (playerNum >= MAX_CLIENTS) { + m_System->Errorf("World::UpdatePlayer: player number %i >= MAX_CLIENTS\n", playerNum); + return; + } + + player_info_t *player = &m_Players[playerNum]; + if (!infostring[0]) { + return; + } + + player->active = true; + player->userid = userId; + memcpy(player->hashedcdkey, hashedcdkey, sizeof(player->hashedcdkey)); + + m_System->DPrintf("Player update(%i:%s)\n", playerNum, player->name); + infostr.RemovePrefixedKeys('_'); + + strcopy(player->userinfo, infostr.GetString()); + strcopy(player->name, infostr.ValueForKey("name")); + strcopy(player->model, infostr.ValueForKey("model")); + + player->topcolor = atoi(infostr.ValueForKey("topcolor")); + player->bottomcolor = atoi(infostr.ValueForKey("bottomcolor")); + player->spectator = atoi(infostr.ValueForKey("*hltv")); + player->trackerID = atoi(infostr.ValueForKey("*fid")); + + BaseSystemModule::FireSignal(4, &playerNum); +} + +bool World::AddResource(resource_t *resource) +{ + resource_t *newresource = (resource_t *)Mem_ZeroMalloc(sizeof(resource_t)); + if (!newresource) { + return false; + } + + memcpy(newresource, resource, sizeof(*newresource)); + + newresource->data = nullptr; + newresource->pNext = m_ResourcesList; + + m_ResourcesList = newresource; + m_ResourcesNum++; + + return true; +} + +void World::ClearResources() +{ + resource_t *res, *next; + for (res = m_ResourcesList; res; res = next) { + next = res->pNext; + free(res); + } + + m_ResourcesList = nullptr; + m_ResourcesNum = 0; +} + +UserMsg *World::GetUserMsg(int msgNumber) +{ + for (UserMsg *pList = m_ClientUserMsgs; pList; pList = pList->next) + { + if (pList->iMsg == msgNumber) { + return pList; + } + } + + return nullptr; +} + +void World::AddBaselineEntity(int index, entity_state_t *ent) +{ + if (index < 0 || index >= MAX_ENTITIES) { + m_System->Printf("WARNING! World::SetBaselineEntity: index (%i) out of bounds.\n", index); + return; + } + + memcpy(&m_BaseLines[index], ent, sizeof(m_BaseLines[index])); +} + +bool World::IsPlayerIndex(int index) +{ + if (index <= 0 || index > m_Maxclients) { + return false; + } + + return true; +} + +void World::ClearBaseline() +{ + memset(m_BaseLines, 0, sizeof(m_BaseLines)); + + for (auto& base : m_BaseLines) { + base.entityType = ENTITY_UNINITIALIZED; + } +} + +void World::ClearInstancedBaseline() +{ + memset(m_Instanced_BaseLines, 0, sizeof(m_Instanced_BaseLines)); +} + +void World::AddInstancedBaselineEntity(int index, entity_state_t *ent) +{ + if (index < 0 || index >= MAX_INSTANCED_BASELINES) { + m_System->Printf("WARNING! World::SetInstancedBaselineEntity: index (%i) out of bounds.\n", index); + return; + } + + memcpy(&m_Instanced_BaseLines[index], ent, sizeof(m_Instanced_BaseLines[index])); +} + +void World::SetTime(double newTime) +{ + m_System->DPrintf("Synchronizing time %.2f ( %.2f)\n", newTime, newTime - m_WorldTime); + m_WorldTime = newTime; +} + +void World::SetHostName(char *name) +{ + if (!name || !name[0]) { + memset(m_HostName, 0, sizeof(m_HostName)); + return; + } + + strcopy(m_HostName, name); +} + +void World::ClearLightStyles() +{ + memset(m_Lightstyles, 0, sizeof(m_Lightstyles)); +} + +void World::AddLightStyle(int index, char *style) +{ + if (index < 0 || index >= MAX_LIGHTSTYLES) { + m_System->Printf("WARNING! World::SetLightStyle: index (%i) out of bounds.\n", index); + return; + } + + int length = strlen(style); + if (length >= sizeof(m_Lightstyles[0])) { + m_System->Printf("WARNING! World::SetLightStyle: style too long (%i).\n", length); + } + + strcopy(m_Lightstyles[index], style); +} + +void World::NewGame(int newServerCount) +{ + BaseSystemModule::FireSignal(1); + + Reset(); + m_ServerCount = newServerCount; + SetState(WORLD_CONNECTING); +} + +void World::SetState(WorldState newState) +{ + if (newState == m_WorldState) + return; + + bool stateError = false; + switch (newState) + { + case WORLD_INITIALIZING: + case WORLD_DISCONNECTED: + break; + case WORLD_CONNECTING: + { + if (m_WorldState != WORLD_DISCONNECTED + && m_WorldState != WORLD_RUNNING + && m_WorldState != WORLD_COMPLETE) { + stateError = true; + } + break; + } + case WORLD_RUNNING: + { + if (m_WorldState != WORLD_CONNECTING) { + stateError = true; + } + break; + } + case WORLD_COMPLETE: + { + if (m_WorldState != WORLD_RUNNING) { + stateError = true; + } + break; + } + default: + stateError = true; + break; + } + + if (stateError) + { + m_System->Errorf("World::SetState: not valid m_WorldState (%i -> %i).\n", m_WorldState, newState); + return; + } + + m_WorldState = newState; +} + +void World::ConnectionComplete() +{ + WriteBaseline(&m_SignonData); + m_StartTime = m_SystemTime; + + SetState(WORLD_RUNNING); + BaseSystemModule::FireSignal(2); +} + +int World::GetNumPlayers() +{ + int count = 0; + for (int i = 0; i < m_Maxclients; i++) + { + if (m_Players[i].active) { + count++; + } + } + + return count; +} + +bool World::IsActive() +{ + return (m_WorldState == WORLD_RUNNING + || m_WorldState == WORLD_COMPLETE); +} + +void World::ClearPlayers() +{ + memset(m_Players, 0, sizeof(m_Players)); +} + +void World::SetServerInfoString(char *infostring) +{ + m_ServerInfo.SetString(infostring); +} + +void World::WriteBaseline(BitBuffer *stream) +{ + if (!IsDeltaEncoder()) { + m_System->Errorf("World::WriteBaseline: delta encoder not found.\n"); + return; + } + + stream->WriteByte(svc_spawnbaseline); + stream->StartBitMode(); + + bool custom = false; + int entnum = 0; + entity_state_t nullstate; + memset(&nullstate, 0, sizeof(entity_state_t)); + + for (auto& base : m_BaseLines) + { + // ignore uninitialized entity, not passed parse process World::ParseBaseline + if (base.entityType != ENTITY_UNINITIALIZED) + { + stream->WriteBits(entnum, 11); + stream->WriteBits(m_BaseLines[entnum].entityType, 2); + + custom = ~m_BaseLines[entnum].entityType & ENTITY_NORMAL; + + delta_t *delta = GetDeltaEncoder(entnum, custom); + m_Delta.WriteDelta(stream, (byte *)&nullstate, (byte *)&base, true, delta); + } + + entnum++; + } + + stream->WriteBits(0xFFFF, 16); + stream->WriteBits(m_MaxInstanced_BaseLine, 6); + + for (entnum = 0; entnum < m_MaxInstanced_BaseLine; entnum++) { + m_Delta.WriteDelta(stream, (byte *)&nullstate, (byte *)&m_Instanced_BaseLines[entnum], true, GetEntityDelta()); + } + + stream->EndBitMode(); +} + +void World::WriteLightStyles(BitBuffer *stream) +{ + for (int i = 0; i < MAX_LIGHTSTYLES; i++) + { + stream->WriteByte(svc_lightstyle); + stream->WriteByte(i); + stream->WriteString(m_Lightstyles[i]); + } +} + +char *World::GetHostName() +{ + if (m_HostName[0]) { + return m_HostName; + } + + return m_ServerName; +} + +void World::WriteServerinfo(BitBuffer *stream) +{ + char message[2048]; + _snprintf(message, sizeof(message), "Protocol Version %i, Spawn count %i %s\n", m_Protocol, m_ServerCount, m_IsHLTV ? "(HLTV)" : ""); + + stream->WriteByte(svc_print); + stream->WriteString(message); + + if (m_IsHLTV) + { + stream->WriteByte(svc_hltv); + stream->WriteByte(HLTV_ACTIVE); + } + + stream->WriteByte(svc_serverinfo); + stream->WriteLong(m_Protocol); + stream->WriteLong(m_ServerCount); + + CRC32_t mungebuffer = m_ServerCRC; + COM_Munge3((byte *)&mungebuffer, sizeof(mungebuffer), (-1 - m_PlayerNum) & 0xFF); + + stream->WriteLong(mungebuffer); + stream->WriteBuf(m_ClientdllMD5, sizeof(m_ClientdllMD5)); + stream->WriteByte(m_Maxclients); + stream->WriteByte(m_PlayerNum); + stream->WriteByte(m_GameType); // deathmatch, coop etc + stream->WriteString(m_GameDir); + stream->WriteString(GetHostName()); + stream->WriteString(m_LevelName); + stream->WriteString("mapcycle failure"); + stream->WriteByte(0); + + stream->WriteByte(svc_sendextrainfo); + stream->WriteString(m_ClientFallback); + stream->WriteByte(m_AllowCheats); + + WriteDeltaDescriptions(stream); + WriteMovevars(stream); + + stream->WriteByte(svc_cdtrack); + stream->WriteByte(m_CDTrack); + stream->WriteByte(m_CDTrack); + + stream->WriteByte(svc_setview); + stream->WriteShort(m_ViewEntity); +} + +void World::WriteDeltaDescriptions(BitBuffer *stream) +{ + int i, c; + + delta_description_t nulldesc; + memset(&nulldesc, 0, sizeof(nulldesc)); + + for (auto p = m_Delta.GetRegistry(); p; p = p->next) + { + stream->WriteByte(svc_deltadescription); + stream->WriteString(p->name); + + if (!p->pdesc) + { + m_System->Errorf("World::WriteDeltaDescriptions : missing delta for %s\n", p->name); + return; + } + + c = p->pdesc->fieldCount; + stream->StartBitMode(); + stream->WriteBits(c, 16); + + for (i = 0; i < c; i++) + { + delta_description_t *from = &nulldesc; + delta_description_t *to = &p->pdesc->pdd[i]; + m_Delta.WriteDelta(stream, (byte *)from, (byte *)to, true, (delta_t *)&Delta::m_MetaDelta); + } + + stream->EndBitMode(); + } +} + +void World::WriteMovevars(BitBuffer *stream) +{ + stream->WriteByte (svc_newmovevars); + stream->WriteFloat(m_MoveVars.gravity); + stream->WriteFloat(m_MoveVars.stopspeed); + stream->WriteFloat(m_MoveVars.maxspeed); + stream->WriteFloat(m_MoveVars.spectatormaxspeed); + stream->WriteFloat(m_MoveVars.accelerate); + stream->WriteFloat(m_MoveVars.airaccelerate); + stream->WriteFloat(m_MoveVars.wateraccelerate); + stream->WriteFloat(m_MoveVars.friction); + stream->WriteFloat(m_MoveVars.edgefriction); + stream->WriteFloat(m_MoveVars.waterfriction); + stream->WriteFloat(m_MoveVars.entgravity); + stream->WriteFloat(m_MoveVars.bounce); + stream->WriteFloat(m_MoveVars.stepsize); + stream->WriteFloat(m_MoveVars.maxvelocity); + stream->WriteFloat(m_MoveVars.zmax); + stream->WriteFloat(m_MoveVars.waveHeight); + stream->WriteByte (m_MoveVars.footsteps != 0); + stream->WriteFloat(m_MoveVars.rollangle); + stream->WriteFloat(m_MoveVars.rollspeed); + stream->WriteFloat(m_MoveVars.skycolor_r); + stream->WriteFloat(m_MoveVars.skycolor_g); + stream->WriteFloat(m_MoveVars.skycolor_b); + stream->WriteFloat(m_MoveVars.skyvec_x); + stream->WriteFloat(m_MoveVars.skyvec_y); + stream->WriteFloat(m_MoveVars.skyvec_z); + stream->WriteString(m_MoveVars.skyName); +} + +void World::WriteRegisteredUserMessages(BitBuffer *stream) +{ + for (UserMsg *pMsg = m_ClientUserMsgs; pMsg; pMsg = pMsg->next) + { + stream->WriteByte(svc_newusermsg); + stream->WriteByte(pMsg->iMsg); + stream->WriteByte(pMsg->iSize); + stream->WriteBuf(pMsg->szName, sizeof(pMsg->szName)); + } +} + +void World::WriteResources(BitBuffer *stream) +{ + unsigned char nullbuffer[32]; + memset(nullbuffer, 0, sizeof(nullbuffer)); + + if (g_DownloadURL[0]) + { + stream->WriteByte(svc_resourcelocation); + stream->WriteString(g_DownloadURL); + } + + stream->WriteByte(svc_resourcelist); + stream->StartBitMode(); + stream->WriteBits(m_ResourcesNum, RESOURCE_INDEX_BITS); + + for (resource_t *resource = m_ResourcesList; resource; resource = resource->pNext) + { + stream->WriteBits(resource->type, 4); + stream->WriteBitString(resource->szFileName); + stream->WriteBits(resource->nIndex, RESOURCE_INDEX_BITS); + stream->WriteBits(resource->nDownloadSize, 24); + stream->WriteBits(resource->ucFlags & (RES_WASMISSING | RES_FATALIFMISSING), 3); + + if (resource->ucFlags & RES_CUSTOM) + { + stream->WriteBitData(resource->rgucMD5_hash, sizeof(resource->rgucMD5_hash)); + } + + if (!memcmp(resource->rguc_reserved, nullbuffer, sizeof(resource->rguc_reserved))) + { + stream->WriteBit(0); + } + else + { + stream->WriteBit(1); + stream->WriteBitData(resource->rguc_reserved, sizeof(resource->rguc_reserved)); + } + } + + stream->WriteBit(0); + stream->EndBitMode(); +} + +void World::WriteClientUpdate(BitBuffer *stream, int playerIndex) +{ + if (m_Players[playerIndex].active) + { + stream->WriteByte(svc_updateuserinfo); + stream->WriteByte(playerIndex); + stream->WriteLong(m_Players[playerIndex].userid); + stream->WriteString(m_Players[playerIndex].userinfo); + stream->WriteBuf(m_Players[playerIndex].hashedcdkey, sizeof(m_Players[playerIndex].hashedcdkey)); + } +} + +int World::AddFrame(frame_t *newFrame) +{ + if (!newFrame) + { + m_System->Errorf("World::AddFrame: newFrame == NULL.\n"); + return 0; + } + + m_SequenceNr++; + + frame_t *currentFrame; + currentFrame = (frame_t *)Mem_ZeroMalloc(sizeof(frame_t)); + currentFrame->seqnr = m_SequenceNr; + currentFrame->time = newFrame->time; + + if (newFrame->time < m_WorldTime) + { + m_System->DPrintf("Fixing frame time, delta %.3f\n", m_WorldTime - currentFrame->time); + ReorderFrameTimes(currentFrame->time - 0.05f); + } + + m_WorldTime = currentFrame->time; + + if (m_WorldState == WORLD_CONNECTING) { + ConnectionComplete(); + } + + int compressedEntitiesSize = 0; + if (newFrame->entitiesSize) + { + if (newFrame->delta) + { + m_System->Errorf("World::AddFrame: only uncompressed frames accepted.\n"); + return 0; + } + + m_Delta.SetLargeTimeBufferSize(true); + BitBuffer tempStream(m_EntityBuffer, sizeof(m_EntityBuffer)); + memset(m_EntityBuffer, 0, sizeof(m_EntityBuffer)); + + compressedEntitiesSize = CompressFrame(newFrame, &tempStream); + m_Delta.SetLargeTimeBufferSize(false); + + if (tempStream.IsOverflowed()) + { + m_System->Printf("WARNING! World::AddFrame: couldn't compress frame entities.\n"); + return 0; + } + } + + unsigned char *pdata; + int maxFrameSize = newFrame->demoDataSize + + newFrame->userMessagesSize + + newFrame->voiceDataSize + + newFrame->unreliableDataSize + + newFrame->reliableDataSize + + newFrame->clientDataSize + + newFrame->eventsSize + + compressedEntitiesSize + + 4; + + if (newFrame->demoInfo) + { + maxFrameSize += sizeof(demo_info_t); + } + + pdata = (unsigned char *)malloc(maxFrameSize); + + currentFrame->data = pdata; + currentFrame->delta = -1; + + if (newFrame->entitiesSize) + { + memcpy(pdata, m_EntityBuffer, compressedEntitiesSize); + currentFrame->entities = pdata; + currentFrame->entitiesSize = compressedEntitiesSize; + currentFrame->entitynum = newFrame->entitynum; + pdata += compressedEntitiesSize; + } + + if (newFrame->clientDataSize) + { + memcpy(pdata, newFrame->clientData, newFrame->clientDataSize); + currentFrame->clientData = pdata; + currentFrame->clientDataSize = newFrame->clientDataSize; + pdata += currentFrame->clientDataSize; + } + + if (newFrame->eventsSize) + { + memcpy(pdata, newFrame->events, newFrame->eventsSize); + currentFrame->events = pdata; + currentFrame->eventsSize = newFrame->eventsSize; + currentFrame->eventnum = newFrame->eventnum; + pdata += currentFrame->eventsSize; + } + + if (newFrame->reliableDataSize) + { + memcpy(pdata, newFrame->reliableData, newFrame->reliableDataSize); + currentFrame->reliableData = pdata; + currentFrame->reliableDataSize = newFrame->reliableDataSize; + pdata += currentFrame->reliableDataSize; + } + + if (newFrame->unreliableDataSize) + { + memcpy(pdata, newFrame->unreliableData, newFrame->unreliableDataSize); + currentFrame->unreliableData = pdata; + currentFrame->unreliableDataSize = newFrame->unreliableDataSize; + pdata += currentFrame->unreliableDataSize; + } + + if (newFrame->voiceDataSize) + { + memcpy(pdata, newFrame->voiceData, newFrame->voiceDataSize); + currentFrame->voiceData = pdata; + currentFrame->voiceDataSize = newFrame->voiceDataSize; + pdata += currentFrame->voiceDataSize; + } + + if (newFrame->userMessagesSize) + { + memcpy(pdata, newFrame->userMessages, newFrame->userMessagesSize); + currentFrame->userMessages = pdata; + currentFrame->userMessagesSize = newFrame->userMessagesSize; + pdata += currentFrame->userMessagesSize; + } + + if (newFrame->demoDataSize) + { + memcpy(pdata, newFrame->demoData, newFrame->demoDataSize); + currentFrame->demoData = pdata; + currentFrame->demoDataSize = newFrame->demoDataSize; + pdata += currentFrame->demoDataSize; + } + + if (newFrame->demoInfo) + { + memcpy(pdata, newFrame->demoInfo, sizeof(demo_info_t)); + currentFrame->demoInfo = pdata; + } + + m_Frames.Add(currentFrame, currentFrame->seqnr); + m_FramesByTime.Add(currentFrame, m_WorldTime); + + CheckFrameBufferSize(); + BaseSystemModule::FireSignal(3, &m_SequenceNr); + + return m_SequenceNr; +} + +frame_t *World::GetFrameBySeqNr(unsigned int seqnr) +{ + return (frame_t *)m_Frames.FindExactKey(seqnr); +} + +frame_t *World::GetLastFrame() +{ + return (frame_t *)m_Frames.GetLast(); +} + +frame_t *World::GetFirstFrame() +{ + return (frame_t *)m_Frames.GetFirst(); +} + +frame_t *World::GetFrameByTime(double time) +{ + frame_t *lastFrame = (frame_t *)m_FramesByTime.FindClosestKey(time); + if (!lastFrame) { + return nullptr; + } + + if (lastFrame->time < time) + { + frame_t *nextFrame = (frame_t *)m_FramesByTime.GetNext(); + if (nextFrame) { + lastFrame = nextFrame; + } + } + + return lastFrame; +} + +void World::WriteFrame(frame_t *frame, unsigned int lastFrameSeqnr, BitBuffer *reliableStream, BitBuffer *unreliableStream, unsigned int deltaSeqNr, unsigned int clientDelta, bool addVoice) +{ + frame_t fullFrame; + if (!GetUncompressedFrame(frame->seqnr, &fullFrame)) { + m_System->DPrintf("World::WriteFrame: couldn't uncompress frame.\n"); + return; + } + + if (m_IsHLTV) + { + unreliableStream->WriteByte(svc_clientdata); + } + else + { + clientdata_t clientData; + if (GetClientData(frame, &clientData)) + { + clientdata_t nullClientData; + memset(&nullClientData, 0, sizeof(nullClientData)); + + unreliableStream->WriteByte(svc_clientdata); + unreliableStream->StartBitMode(); + unreliableStream->WriteBit(0); + + m_Delta.WriteDelta(unreliableStream, (byte *)&nullClientData, (byte *)&clientData, true, GetClientDelta()); + + unreliableStream->WriteBit(0); + unreliableStream->EndBitMode(); + } + } + + bool validEntities = false; + if (deltaSeqNr && WriteDeltaEntities(unreliableStream, &fullFrame, deltaSeqNr, clientDelta)) { + validEntities = true; + } + else + { + unreliableStream->WriteByte(svc_packetentities); + unreliableStream->WriteShort(frame->entitynum); + + if (CompressFrame(&fullFrame, unreliableStream) > 0) { + validEntities = true; + } + else { + m_System->DPrintf("WARNING! World::WriteFrame: could write entities!\n"); + } + } + + if (frame->eventsSize && validEntities) + { + unreliableStream->WriteByte(svc_event); + unreliableStream->WriteBuf(frame->events, frame->eventsSize); + } + + frame_t *lastFrame = (frame_t *)m_Frames.FindExactKey(lastFrameSeqnr + 1); + while (lastFrame) + { + if (lastFrame->seqnr > frame->seqnr + || reliableStream->IsOverflowed()) { + break; + } + + if (lastFrame->reliableDataSize && (unsigned)reliableStream->SpaceLeft() > lastFrame->reliableDataSize) { + reliableStream->WriteBuf(lastFrame->reliableData, lastFrame->reliableDataSize); + } + + if (lastFrame->userMessagesSize && (unsigned)reliableStream->SpaceLeft() > lastFrame->userMessagesSize) { + reliableStream->WriteBuf(lastFrame->userMessages, lastFrame->userMessagesSize); + } + + if (lastFrame->seqnr + 8 > frame->seqnr) + { + if (lastFrame->unreliableDataSize && (unsigned)unreliableStream->SpaceLeft() > lastFrame->unreliableDataSize) { + unreliableStream->WriteBuf(lastFrame->unreliableData, lastFrame->unreliableDataSize); + } + + if (lastFrame->voiceDataSize) + { + if ((unsigned)unreliableStream->SpaceLeft() > lastFrame->voiceDataSize) { + unreliableStream->WriteBuf(lastFrame->voiceData, lastFrame->voiceDataSize); + } + } + } + + lastFrame = (frame_t *)m_Frames.GetNext(); + } +} + +bool World::GetUncompressedFrame(unsigned int seqNr, frame_t *frame) +{ + frame_t *deltaFrame = (frame_t *)m_Frames.FindExactKey(seqNr); + if (!deltaFrame) { + return false; + } + + if (deltaFrame->seqnr != seqNr) { + m_System->DPrintf("WARNING! World::GetUncompressedFrame: frame not found %i.\n", seqNr); + return false; + } + + return GetUncompressedFrame(deltaFrame, frame); +} + +bool World::GetClientData(unsigned int SeqNr, clientdata_t *clientData) +{ + frame_t *frame = (frame_t *)m_Frames.FindExactKey(SeqNr); + return GetClientData(frame, clientData); +} + +bool World::GetClientData(frame_t *frame, clientdata_t *clientData) +{ + if (!frame || !frame->clientData || !frame->clientDataSize) { + return false; + } + + clientdata_t BaseLineClientData; + memset(&BaseLineClientData, 0, sizeof(BaseLineClientData)); + + BitBuffer stream(frame->clientData, frame->clientDataSize); + stream.StartBitMode(); + m_Delta.ParseDelta(&stream, (byte *)&BaseLineClientData, (byte *)clientData, GetClientDelta()); + + return true; +} + +bool World::GetUncompressedFrame(frame_t *deltaFrame, frame_t *frame) +{ + BitBuffer frameStream; + if (!deltaFrame) { + return false; + } + + if (deltaFrame->delta != -1) { + m_System->DPrintf("World::GetUncompressedFrame: unexpected non baseline delta frame.\n"); + return false; + } + + memcpy(frame, deltaFrame, sizeof(*frame)); + + frame->delta = 0; + frame->entitiesSize = deltaFrame->entitynum * sizeof(entity_state_t); + + if (frame->entitynum > MAX_PACKET_ENTITIES) { + m_System->Errorf("World::GetUncompressedFrame: entnum >= MAX_PACKET_ENTITIES.\n"); + } + + if (frame->entitynum) + { + if (!GetFrameFromCache(deltaFrame->seqnr, (entity_state_t **)&frame->entities)) + { + m_Delta.SetLargeTimeBufferSize(true); + frameStream.SetBuffer(deltaFrame->entities, deltaFrame->entitiesSize); + UncompressEntitiesFromStream(frame, &frameStream); + m_Delta.SetLargeTimeBufferSize(false); + } + } + + return true; +} + +void World::ParseClientData(BitBuffer *stream, unsigned int deltaSeqNr, BitBuffer *to, clientdata_t *clientData) +{ + weapon_data_t nullWeaponData; + clientdata_t fromClientData, nullClientData; + + memset(&nullWeaponData, 0, sizeof(nullWeaponData)); + memset(&fromClientData, 0, sizeof(fromClientData)); + memset(&nullClientData, 0, sizeof(nullClientData)); + memset(clientData, 0, sizeof(*clientData)); + + if (deltaSeqNr && !GetClientData(deltaSeqNr, &fromClientData)) { + m_System->Printf("WARNING! World::ParseClientData: couldn't uncompress delta frame %i\n", deltaSeqNr); + } + + m_Delta.ParseDelta(stream, (byte *)&fromClientData, (byte *)clientData, GetClientDelta()); + to->StartBitMode(); + m_Delta.WriteDelta(to, (byte *)&nullClientData, (byte *)clientData, true, GetClientDelta()); + to->EndBitMode(); + + while (stream->ReadBit()) + { + stream->ReadBits(6); + m_Delta.ParseDelta(stream, (byte *)&nullWeaponData, (byte *)&nullWeaponData, GetWeaponDelta()); + } +} + +int World::ParseDeltaHeader(BitBuffer *stream, bool *remove, bool *custom, int *numbase, bool *newbl, int *newblindex, bool full, int *offset) +{ + int num; + + *custom = false; + *newbl = false; + + if (full) + { + *remove = false; + + if (stream->ReadBit() != 0) + { + num = *numbase + 1; + } + else if (stream->ReadBit() == 0) + { + num = stream->ReadBits(6) + *numbase; + } + else + { + num = stream->ReadBits(11); + } + } + else + { + *remove = stream->ReadBit() != 0; + + if (stream->ReadBit() == 0) + num = stream->ReadBits(6) + *numbase; + else + num = stream->ReadBits(11); + } + + *numbase = num; + + if (!*remove) + { + *custom = stream->ReadBit() != 0; + if (m_MaxInstanced_BaseLine) + { + *newbl = stream->ReadBit() != 0; + if (*newbl) + *newblindex = stream->ReadBits(6); + } + else + { + *newbl = false; + } + + if (!full || *newbl) + { + *offset = 0; + } + else + { + *offset = stream->ReadBit(); + if (*offset) { + *offset = stream->ReadBits(6); + } + } + } + + return num; +} + +int World::CompressFrame(frame_t *from, BitBuffer *stream) +{ + deltacallback_t header; + header.instanced_baseline = (m_MaxInstanced_BaseLine > 0) ? true : false; + header.num = 0; + header.offset = 0; + header.numbase = 0; + header.newblindex = 0; + header.full = true; + header.newbl = false; + header.remove = false; + header.custom = false; + + if (from->delta) + { + m_System->Errorf("World::CompressFrame: frame was not uncompressed.\n"); + return 0; + } + + m_Delta.SetTime(from->time); + stream->StartBitMode(); + + entity_state_t *entities = (entity_state_t *)from->entities; + unsigned char *start = stream->CurrentByte(); + for (auto entnum = 0u; entnum < from->entitynum; entnum++) + { + header.num = entities[entnum].number; + header.custom = (entities[entnum].entityType & ENTITY_BEAM) == ENTITY_BEAM; + header.newblindex = 0; + header.newbl = false; + + entity_state_t *baseline = &m_BaseLines[header.num]; + header.offset = FindBestBaseline(entnum, &baseline, entities, header.num, header.custom); + + delta_t *delta = GetDeltaEncoder(header.num, header.custom); + m_Delta.WriteDelta(stream, (byte *)baseline, (byte *)&entities[entnum], true, delta, &header); + } + + stream->WriteBits(0, 16); + stream->EndBitMode(); + + return stream->CurrentByte() - start; +} + +int World::FindBestBaseline(int index, entity_state_t **baseline, entity_state_t *to, int num, bool custom) +{ + int bestbitnumber; + delta_t *delta; + + delta = GetDeltaEncoder(num, custom); + bestbitnumber = m_Delta.TestDelta((byte *)*baseline, (byte *)&to[index], delta); + bestbitnumber -= 6; + + int i = 0; + int bitnumber = 0; + int bestfound = index; + + for (i = index - 1; bestbitnumber > 0 && i >= 0 && (index - i) <= 64; i--) + { + if (to[index].modelindex == to[i].modelindex) + { + bitnumber = m_Delta.TestDelta((byte *)&to[i], (byte *)&to[index], delta); + + if (bitnumber < bestbitnumber) + { + bestbitnumber = bitnumber; + bestfound = i; + } + } + } + + if (index != bestfound) { + *baseline = &to[bestfound]; + } + + return index - bestfound; +} + +void World::ClearEntityCache() +{ + if (m_DeltaCache) + { + for (int i = 0; i < m_MaxCacheIndex; i++) { + m_DeltaCache[i].buffer.Free(); + } + + memset(m_DeltaCache, 0, sizeof(deltaCache_t) * m_MaxCacheIndex); + } + + if (m_FrameCache) { + memset(m_FrameCache, 0, sizeof(frameCache_t) * m_MaxCacheIndex); + } + + m_CacheHits = 1; + m_CacheFaults = 1; +} + +bool World::GetFrameFromCache(unsigned int seqNr, entity_state_t **entities) +{ + for (int i = 0; i < m_MaxCacheIndex; i++) + { + if (m_FrameCache[i].seqNr == seqNr) + { + *entities = m_FrameCache[i].entities; + m_CacheHits++; + return true; + } + } + + static int next = 0; + m_FrameCache[next].seqNr = seqNr; + *entities = m_FrameCache[next].entities; + + if (++next == m_MaxCacheIndex) { + next = 0; + } + + m_CacheFaults++; + return false; +} + +bool World::GetDeltaFromCache(unsigned int seqNr, unsigned int deltaNr, BitBuffer **buffer) +{ + for (int i = 0; i < m_MaxCacheIndex; i++) + { + if (m_DeltaCache[i].seqNr == seqNr && m_DeltaCache[i].deltaNr == deltaNr) + { + *buffer = &m_DeltaCache[i].buffer; + m_CacheHits++; + return true; + } + } + + static int next = 0; + m_DeltaCache[next].seqNr = seqNr; + m_DeltaCache[next].deltaNr = deltaNr; + *buffer = &m_DeltaCache[next].buffer; + + if (++next == m_MaxCacheIndex) { + next = 0; + } + + m_CacheFaults++; + return 0; +} + +void World::WritePacketEntities(BitBuffer *stream, frame_t *frame, frame_t *deltaframe) +{ + int oldmax; + int oldindex; + int newindex; + int newnum; + int oldnum; + entity_state_t *frameEntities; + entity_state_t *deltaEntities; + + deltacallback_t header; + header.instanced_baseline = (m_MaxInstanced_BaseLine > 0) ? true : false; + header.num = 0; + header.offset = 0; + header.numbase = 0; + header.newblindex = 0; + header.full = false; + header.newbl = false; + header.remove = false; + header.custom = false; + + if (frame->delta || deltaframe->delta) { + m_System->Errorf("World::WritePacketEntities: frame and delta frame must be uncompressed.\n"); + return; + } + + m_Delta.SetTime(frame->time); + + oldmax = deltaframe->entitynum; + newnum = 0; // index in frame->entities + oldnum = 0; // index in deltaframe->entities + + frameEntities = (entity_state_t *)frame->entities; + deltaEntities = (entity_state_t *)deltaframe->entities; + + stream->StartBitMode(); + while (true) + { + if ((unsigned)newnum < frame->entitynum) + { + newindex = frameEntities[newnum].number; + } + else + { + if (oldnum >= oldmax) + break; + + // TODO: Unreachable code + if ((unsigned)newnum < frame->entitynum) + newindex = frameEntities[newnum].number; + else + newindex = 9999; + } + + if (oldnum < oldmax) + oldindex = deltaEntities[oldnum].number; + else + oldindex = 9999; + + if (newindex == oldindex) + { + header.custom = (frameEntities[newnum].entityType & ENTITY_BEAM) == ENTITY_BEAM; + header.num = newindex; + header.newblindex = 0; + header.newbl = false; + header.remove = false; + + delta_t *delta = GetDeltaEncoder(newindex, header.custom); + m_Delta.WriteDelta(stream, (byte *)&deltaEntities[oldnum], (byte *)&frameEntities[newnum], true, delta, &header); + + oldnum++; + newnum++; + continue; + } + + if (newindex >= oldindex) + { + if (newindex > oldindex) + { + header.num = oldindex; + header.remove = true; + header.newbl = false; + header.newblindex = 0; + + m_Delta.WriteHeader(stream, &header); + ++oldnum; + } + continue; + } + + header.custom = (frameEntities[newnum].entityType & ENTITY_BEAM) == ENTITY_BEAM; + header.newblindex = 0; + header.num = newindex; + header.remove = false; + header.newbl = false; + + delta_t *delta = GetDeltaEncoder(newindex, header.custom); + m_Delta.WriteDelta(stream, (byte *)&m_BaseLines[oldnum], (byte *)&frameEntities[newnum], true, delta, &header); + newnum++; + } + + stream->WriteBits(0, 16); + stream->EndBitMode(); +} + +char *World::GetType() +{ + return WORLD_INTERFACE_VERSION; +} + +char *World::GetStatusLine() +{ + static char string[256]; + if (IsActive()) + { + _snprintf(string, sizeof(string), + "Game \"%s\", Map \"%s\", Time %s, Players %i\nFrame cache use %.1f, Buffered time %.0f .\n", + m_GameDir, + m_LevelName, + COM_FormatTime(m_WorldTime), + GetNumPlayers(), + (float)m_CacheHits / (float)(m_CacheHits + m_CacheFaults), + GetBufferedGameTime()); + } + else + { + _snprintf(string, sizeof(string), "World not active.\n"); + } + + return string; +} + +void World::ClearServerInfo() +{ + m_ServerInfo.Clear(); + + memset(&m_DetailedServerInfo, 0, sizeof(m_DetailedServerInfo)); + m_DetailedServerInfo.type = '?'; + m_DetailedServerInfo.os = '?'; + m_DetailedServerInfo.pw = '?'; +} + +void World::SetServerInfo(serverinfo_t *serverinfo) +{ + memcpy(&m_DetailedServerInfo, serverinfo, sizeof(m_DetailedServerInfo)); +} + +void World::FinishGame() +{ + if (m_WorldState != WORLD_RUNNING) { + return; + } + + SetState(WORLD_COMPLETE); + BaseSystemModule::FireSignal(7); +} + +void World::StopGame() +{ + BaseSystemModule::FireSignal(1); + Reset(); + SetState(WORLD_DISCONNECTED); +} + +void World::WriteSigonData(BitBuffer *stream) +{ + stream->WriteBuf(m_SignonData.GetData(), m_SignonData.CurrentSize()); +} + +bool World::AddSignonData(unsigned char type, unsigned char *data, int size) +{ + m_SignonData.WriteByte(type); + m_SignonData.WriteBuf(data, size); + + return m_SignonData.m_Overflowed; +} + +int World::FindUserMsgByName(char *name) +{ + for (UserMsg *pList = m_ClientUserMsgs; pList; pList = pList->next) + { + if (!strcmp(pList->szName, name)) { + return pList->iMsg; + } + } + + return 0; +} + +double World::GetTime() +{ + return m_WorldTime; +} + +bool World::UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream, unsigned int from) +{ + int newnum, oldnum; + int oldindex, newindex; + + bool remove, custom, newbl; + int newblindex, numbase, offset; + + frame_t deltaFrame; + if (!GetUncompressedFrame(from, &deltaFrame)) { + m_System->DPrintf("WARNING! World::UncompressEntitiesFromStream: delta frame too old.\n"); + stream->m_Overflowed = true; + return false; + } + + oldindex = 0; + newindex = 0; + + remove = false; + custom = false; + newbl = false; + newblindex = 0; + numbase = 0; + + m_Delta.SetTime(frame->time); + stream->StartBitMode(); + + entity_state_t *entity = (entity_state_t *)frame->entities; + entity_state_t *deltaEntity = (entity_state_t *)deltaFrame.entities; + + while (stream->PeekBits(16)) + { + newnum = ParseDeltaHeader(stream, &remove, &custom, &numbase, &newbl, &newblindex, false, &offset); + + if ((unsigned)oldindex < deltaFrame.entitynum) + oldnum = deltaEntity[oldindex].number; + else + oldnum = 9999; + + while (newnum > oldnum) + { + if (newindex >= MAX_PACKET_ENTITIES) + { + m_System->DPrintf("WARNING!World::UncompressEntitiesFromStream: newindex >= MAX_PACKET_ENTITIES.\n"); + stream->m_Overflowed = true; + } + + memcpy(&entity[newindex], &deltaEntity[oldindex], sizeof(entity[newindex])); + + newindex++; + oldindex++; + + if ((unsigned)oldindex < deltaFrame.entitynum) + oldnum = deltaEntity[oldindex].number; + else + oldnum = 9999; + } + + if (newnum >= oldnum) + { + if (newnum == oldnum) + { + if (remove) + { + ++oldindex; + } + else + { + entity[newindex].entityType = custom ? ENTITY_BEAM : ENTITY_NORMAL; + + delta_t *delta = GetDeltaEncoder(newnum, custom); + m_Delta.ParseDelta(stream, (byte *)&deltaEntity[oldindex], (byte *)&entity[newindex], delta); + + entity[newindex].number = newnum; + ++newindex; + ++oldindex; + } + } + } + else if (!remove) + { + if (newindex >= MAX_PACKET_ENTITIES) + { + m_System->DPrintf("World::UncompressEntitiesFromStream: newindex >= MAX_PACKET_ENTITIES.\n"); + stream->m_Overflowed = true; + } + + entity_state_t *baseline; + if (newbl) + { + baseline = &m_Instanced_BaseLines[newblindex]; + } + else if (offset) + { + baseline = &entity[newindex - offset]; + } + else + { + baseline = &m_BaseLines[newnum]; + } + + entity[newindex].entityType = custom ? ENTITY_BEAM : ENTITY_NORMAL; + + delta_t *delta = GetDeltaEncoder(newnum, custom); + m_Delta.ParseDelta(stream, (byte *)baseline, (byte *)&entity[newindex], delta); + entity[newindex].number = newnum; + newindex++; + } + } + + if (stream->ReadShort()) + { + m_System->DPrintf("WARNING! World::UncompressEntitiesFromStream: missing end tag.\n"); + return false; + } + + stream->EndBitMode(); + + while ((unsigned)oldindex < deltaFrame.entitynum) + { + if (newindex >= MAX_PACKET_ENTITIES) + { + m_System->DPrintf("WARNING! World::UncompressEntitiesFromStream: newindex >= MAX_PACKET_ENTITIES.\n"); + stream->m_Overflowed = true; + } + + memcpy(&entity[newindex], &deltaEntity[oldindex], sizeof(entity[newindex])); + newindex++; + oldindex++; + } + + if (newindex != frame->entitynum) { + m_System->DPrintf("WARNING! World::UncompressEntitiesFromStream: newindex != frame->entitynum.\n"); + } + + return true; +} + +bool World::UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream) +{ + int num; + int newindex = 0; + int entnum = frame->entitynum; + entity_state_t *baseline; + bool remove, custom, newbl; + int newblindex, numbase, offset; + + newblindex = 0; + numbase = 0; + + remove = false; + custom = false; + newbl = false; + + entity_state_t *entities = (entity_state_t *)frame->entities; + m_Delta.SetTime(frame->time); + stream->StartBitMode(); + while (true) + { + if (stream->IsOverflowed()) { + m_System->Printf("WARNING! World::UncompressEntitiesFromStream: incoming entities are corrupt.\n"); + break; + } + + if (!stream->PeekBits(16)) { + break; + } + + num = ParseDeltaHeader(stream, &remove, &custom, &numbase, &newbl, &newblindex, true, &offset); + if (num >= MAX_ENTITIES) + { + m_System->Errorf("World::GetUncompressedFrame: entity number %i >= MAX_ENTITIES\n", num); + memset(frame, 0, sizeof(*frame)); + return false; + } + + if (remove) + { + m_System->Errorf("World::GetUncompressedFrame: remove invalid on non-delta compressed frames\n"); + memset(frame, 0, sizeof(*frame)); + return false; + } + + if (newbl) + { + baseline = &m_Instanced_BaseLines[newblindex]; + } + else if (offset) + { + baseline = &entities[newindex - offset]; + } + else + { + baseline = &m_BaseLines[num]; + } + + entities[num].entityType = custom ? ENTITY_BEAM : ENTITY_NORMAL; + + delta_t *delta = GetDeltaEncoder(num, custom); + m_Delta.ParseDelta(stream, (byte *)baseline, (byte *)&entities[newindex], delta); + entities[newindex].number = num; + newindex++; + } + + if (stream->ReadShort()) { + m_System->Printf("WARNING! World::UncompressEntitiesFromStream: missing end tag.\n"); + return false; + } + + stream->EndBitMode(); + + if (newindex != entnum) { + m_System->DPrintf("WARNING! World::UncompressEntitiesFromStream: newindex != entnum.\n"); + return false; + } + + return true; +} + +void World::WriteNewData(BitBuffer *stream) +{ + WriteServerinfo(stream); + WriteRegisteredUserMessages(stream); + + stream->WriteByte(svc_stufftext); + stream->WriteString(COM_VarArgs("fullserverinfo \"%s\"\n", m_ServerInfo.GetString())); + + WriteResources(stream); +} + +void World::SetName(char *newName) +{ + strcopy(m_Name, newName); +} + +float World::GetBufferedGameTime() +{ + if (!IsActive() || m_Frames.IsEmpty()) { + return 0; + } + + frame_t *firstFrame = (frame_t *)m_Frames.GetFirst(); + frame_t *lastFrame = (frame_t *)m_Frames.GetLast(); + + return lastFrame->time - firstFrame->time; +} + +int World::RemoveFrames(unsigned int startSeqNr, unsigned int endSeqNr) +{ + if (startSeqNr > endSeqNr) { + return 0; + } + + frame_t *startFrame = (frame_t *)m_Frames.FindExactKey(startSeqNr); + frame_t *endFrame = (frame_t *)m_Frames.FindExactKey(endSeqNr); + if (!startFrame || !endFrame) { + return 0; + } + + unsigned int nextseqnr = startFrame->seqnr; + unsigned int lastseqnr = endFrame->seqnr; + + int seqNrOffset = lastseqnr - nextseqnr + 1; + float timeOffset = endFrame->time - startFrame->time; + + frame_t *frame = startFrame; + while (frame) + { + if (frame->seqnr > lastseqnr) { + break; + } + + m_Frames.Remove(frame); + m_FramesByTime.Remove(frame); + + if (frame->data) { + free(frame->data); + } + + free(frame); + frame = (frame_t *)m_Frames.FindExactKey(++nextseqnr); + } + + if (frame != m_Frames.GetFirst()) + { + ClearEntityCache(); + while (frame) + { + RearrangeFrame(frame, seqNrOffset, timeOffset); + frame = (frame_t *)m_Frames.FindExactKey(++nextseqnr); + } + ClearEntityCache(); + } + + return seqNrOffset; +} + +int World::DuplicateFrames(unsigned int startSeqNr, unsigned int endSeqNr) +{ + m_System->Printf("TODO World::DuplicateFrames\n"); + return 0; +} + +int World::MoveFrames(unsigned int startSeqNr, unsigned int endSeqNr, double destSeqnr) +{ + m_System->Printf("TODO World::MoveFrames\n"); + return 0; +} + +int World::RevertFrames(unsigned int startSeqNr, unsigned int endSeqNr) +{ + m_System->Printf("TODO World::RevertFrames\n"); + return 0; +} + +void World::ClearFrames() +{ + frame_t *frame = (frame_t *)m_Frames.GetFirst(); + while (frame) + { + if (frame->data) { + free(frame->data); + } + + free(frame); + frame = (frame_t *)m_Frames.GetNext(); + } + + m_Frames.Clear(); + m_FramesByTime.Clear(); +} + +void World::CheckFrameBufferSize() +{ + if (m_MaxBufferLength <= 0) { + return; + } + + frame_t *frame = (frame_t *)m_Frames.GetLast(); + if (!frame) { + return; + } + + frame_t *firstFrame = (frame_t *)m_Frames.GetFirst(); + if (!firstFrame) { + return; + } + + frame_t *newfirstFrame = (frame_t *)m_FramesByTime.FindClosestKey(frame->time - m_MaxBufferLength); + if (newfirstFrame) { + RemoveFrames(firstFrame->seqnr, newfirstFrame->seqnr - 1); + } +} + +void World::ReorderFrameTimes(float newLastTime) +{ + frame_t *fprev = (frame_t *)m_Frames.GetLast(); + if (!fprev) { + return; + } + + frame_t *f; + float offset = newLastTime; + int fseqnr = fprev->seqnr - 1; + while ((f = (frame_t *)m_Frames.FindExactKey(fseqnr))) + { + float timediff = fprev->time - f->time; + + fseqnr--; + fprev->time = offset; + fprev = f; + + offset -= timediff; + f = (frame_t *)m_Frames.FindExactKey(fseqnr); + } + + fprev->time = offset; +} + +void World::SetServerInfo(int protocol, CRC32_t nserverCRC, unsigned char *nclientdllmd5, int nmaxclients, int nplayernum, int ngametype, char *ngamedir, char *nservername, char *nlevelname) +{ + m_Protocol = protocol; + m_ServerCRC = nserverCRC; + memcpy(m_ClientdllMD5, nclientdllmd5, sizeof(m_ClientdllMD5)); + + m_Maxclients = nmaxclients; + m_PlayerNum = nplayernum; + m_GameType = ngametype; + + strcopy(m_GameDir, ngamedir); + strcopy(m_LevelName, nlevelname); + + _snprintf(m_ServerName, sizeof(m_ServerName), "%s:%i", nservername, m_PlayerNum); +} + +void World::SetMoveVars(movevars_t *nmovevars) +{ + memcpy(&m_MoveVars, nmovevars, sizeof(m_MoveVars)); +} + +void World::SetPaused(bool state) +{ + if (m_IsPaused == state) { + return; + } + + m_IsPaused = state; + BaseSystemModule::FireSignal(m_IsPaused ? 5 : 6); +} + +bool World::IsPaused() +{ + return m_IsPaused; +} + +bool World::IsComplete() +{ + return m_WorldState == WORLD_COMPLETE; +} + +void World::SetBufferSize(float seconds) +{ + if (seconds <= 0) { + m_MaxBufferLength = -1; + return; + } + + m_MaxBufferLength = seconds + 10; +} + +void World::ParseDeltaDescription(BitBuffer *stream) +{ + delta_description_t *pdesc; + delta_description_t nulldesc; + memset(&nulldesc, 0, sizeof(nulldesc)); + + char *s = stream->ReadString(); + if (!s || !s[0]) { + m_System->Errorf("ParseDeltaDescription: Illegible description name\n"); + return; + } + + char szDesc[256]; + strcopy(szDesc, s); + + m_System->DPrintf("Reading delta description for: %s.\n", s); + + delta_t **ppdelta = m_Delta.LookupRegistration(szDesc); + if (ppdelta && *ppdelta) { + m_Delta.FreeDescription(ppdelta); + } + + stream->StartBitMode(); + + int c = stream->ReadShort(); + *ppdelta = (delta_t *)Mem_ZeroMalloc(sizeof(delta_t)); + pdesc = (delta_description_t *)Mem_ZeroMalloc(sizeof(delta_description_t) * c); + + (*ppdelta)->dynamic = 1; + (*ppdelta)->fieldCount = c; + + for (int i = 0; i < c; i++) { + m_Delta.ParseDelta(stream, (byte *)&nulldesc, (byte *)&pdesc[i], Delta::m_MetaDelta); + } + + (*ppdelta)->pdd = pdesc; + stream->EndBitMode(); + m_Delta.UpdateDescriptions(); +} + +void World::SetCDInfo(int ncdtrack, int nlooptrack) +{ + m_CDTrack = ncdtrack; + m_LoopTrack = nlooptrack; +} + +void World::SetGameServerAddress(NetAddress *address) +{ + m_GameServerAddress.FromNetAddress(address); +} + +InfoString *World::GetServerInfoString() +{ + return &m_ServerInfo; +} + +bool World::GetPlayerInfoString(int playerNum, InfoString *infoString) +{ + if (!infoString || playerNum >= MAX_CLIENTS || playerNum < 0) { + return false; + } + + if (!m_Players[playerNum].userinfo[0] + || !m_Players[playerNum].active) { + return false; + } + + return infoString->SetString(m_Players[playerNum].userinfo); +} + +void World::SetExtraInfo(char *nclientfallback, int nallowCheats) +{ + strcopy(m_ClientFallback, nclientfallback); + m_AllowCheats = nallowCheats ? true : false; +} + +void World::ParseEvent(BitBuffer *stream) +{ + event_args_t nullargs; + memset(&nullargs, 0, sizeof(nullargs)); + m_Delta.ParseDelta(stream, (byte *)&nullargs, (byte *)&nullargs, GetEventDelta()); +} + +void World::ParseBaseline(BitBuffer *stream) +{ + bool custom; + unsigned char type; + int count = 0; + + entity_state_t nullstate; + entity_state_t entstate; + delta_t **ppentity, **ppcustom, **ppplayer; + + ppentity = m_Delta.LookupRegistration("entity_state_t"); + ppplayer = m_Delta.LookupRegistration("entity_state_player_t"); + ppcustom = m_Delta.LookupRegistration("custom_entity_state_t"); + + if (!(ppentity && *ppentity && ppcustom && *ppcustom && ppplayer && *ppplayer)) { + m_System->Errorf("Server::ParseBaseline: needed delta encoder missing.\n"); + return; + } + + memset(&nullstate, 0, sizeof(nullstate)); + stream->StartBitMode(); + m_MaxBaseLines = 0; + ClearBaseline(); + + while (stream->PeekBits(16) != 0xFFFF) + { + int index = stream->ReadBits(11); + m_MaxBaseLines = max(index, m_MaxBaseLines); + + memset(&entstate, 0, sizeof(nullstate)); + + type = stream->ReadBits(2); + custom = (type & ENTITY_BEAM) == ENTITY_BEAM; + + delta_t *delta; + if (custom) + { + delta = *ppcustom; + } + else + { + delta = IsPlayerIndex(index) ? *ppplayer : *ppentity; + } + + m_Delta.ParseDelta(stream, (byte *)&nullstate, (byte *)&entstate, delta); + + entstate.entityType = type; + AddBaselineEntity(index, &entstate); + count++; + } + + m_System->Printf("Received baseline with %i entities.\n", count); + + stream->ReadBits(16); + ClearInstancedBaseline(); + m_MaxInstanced_BaseLine = stream->ReadBits(6); + for (int i = 0; i < m_MaxInstanced_BaseLine; i++) + { + memset(&entstate, 0, sizeof(entstate)); + m_Delta.ParseDelta(stream, (byte *)&nullstate, (byte *)&entstate, *ppentity); + AddInstancedBaselineEntity(i, &entstate); + } + + if (m_MaxInstanced_BaseLine) { + m_System->Printf("Received instanced baseline with %i entities.\n", m_MaxInstanced_BaseLine); + } + + stream->EndBitMode(); +} + +bool World::IsVoiceEnabled() +{ + return m_VoiceEnabled; +} + +int World::GetSlotNumber() +{ + return m_PlayerNum; +} + +void World::SetViewEntity(int nviewentity) +{ + m_ViewEntity = nviewentity; +} + +void World::SetVoiceEnabled(bool state) +{ + m_VoiceEnabled = state; +} + +NetAddress *World::GetGameServerAddress() +{ + return &m_GameServerAddress; +} + +char *World::GetLevelName() +{ + return m_LevelName; +} + +IBSPModel *World::GetWorldModel() +{ + if (!m_WorldModel.IsValid()) { + m_WorldModel.Load(m_LevelName, true); + } + + return &m_WorldModel; +} + +char *World::GetGameDir() +{ + return m_GameDir; +} + +int World::GetServerCount() +{ + return m_ServerCount; +} + +int World::GetMaxClients() +{ + return m_Maxclients; +} + +bool World::SaveAsDemo(char *filename, IDirector *director) +{ + DemoFile demoFile; + NetChannel demoChannel; + + client_data_t cdata; + double lastFrameTime = 0; + double originalWorldTime = m_WorldTime; + unsigned int clientDelta = 0; + unsigned int lastFrameSeqNr = 0; + + memset(&cdata, 0, sizeof(cdata)); + + frame_t *frame = (frame_t *)m_Frames.GetFirst(); + if (!frame) { + return false; + } + + m_WorldTime = frame->time; + demoChannel.Create(m_System, 0, 0); + demoFile.Init(this, 0, &demoChannel); + + if (!demoFile.StartRecording(filename)) { + return false; + } + + m_System->Printf("Saving game to \"%s\". This can take some time...\n", filename); + + while (frame) + { + m_WorldTime = frame->time; + + if (!lastFrameSeqNr || lastFrameSeqNr > frame->seqnr) { + lastFrameSeqNr = frame->seqnr - 1; + } + + if (lastFrameSeqNr < frame->seqnr) + { + demoChannel.m_unreliableStream.WriteByte(svc_time); + demoChannel.m_unreliableStream.WriteByte(frame->time); + + WriteFrame(frame, lastFrameSeqNr, &demoChannel.m_reliableStream, &demoChannel.m_unreliableStream, lastFrameSeqNr, clientDelta, true); + + if (director) { + director->WriteCommands(&demoChannel.m_reliableStream, lastFrameTime, frame->time); + } + + lastFrameSeqNr = frame->seqnr; + clientDelta = (demoChannel.m_outgoing_sequence & 0xFF); + + if (demoChannel.m_reliableStream.IsOverflowed()) { + m_System->Printf("WARNING! World::SaveAsDemo: reliable data overflow.\n"); + return false; + } + + if (demoChannel.m_unreliableStream.IsOverflowed()) { + demoChannel.m_unreliableStream.Clear(); + } + + demoFile.WriteDemoMessage(&demoChannel.m_unreliableStream, &demoChannel.m_reliableStream); + demoChannel.TransmitOutgoing(); + demoFile.WriteUpdateClientData(&cdata); + + lastFrameTime = frame->time; + frame = (frame_t *)m_Frames.FindExactKey(lastFrameSeqNr + 1); + } + } + + return true; +} + +serverinfo_t *World::GetServerInfo() +{ + return &m_DetailedServerInfo; +} + +bool World::WriteDeltaEntities(BitBuffer *stream, frame_t *fullFrame, unsigned int deltaSeqNr, unsigned int clientDelta) +{ + BitBuffer *buffer; + if (!GetDeltaFromCache(fullFrame->seqnr, deltaSeqNr, &buffer)) + { + frame_t deltaFrame; + if (!GetUncompressedFrame(deltaSeqNr, &deltaFrame)) + { + m_System->DPrintf("WARNING! World::WriteFrame: delta frame too old (%i).\n", deltaSeqNr); + return false; + } + + buffer->Resize(fullFrame->entitiesSize); + WritePacketEntities(buffer, fullFrame, &deltaFrame); + } + + stream->WriteByte(svc_deltapacketentities); + stream->WriteShort(fullFrame->entitynum); + stream->WriteByte(clientDelta); + stream->ConcatBuffer(buffer); + return true; +} + +void World::RearrangeFrame(frame_t *frame, int seqNrOffset, float timeOffset) +{ + frame_t fullFrame; + if (!GetUncompressedFrame(frame, &fullFrame)) { + return; + } + + m_FramesByTime.ChangeKey(frame, frame->time - timeOffset); + m_Frames.ChangeKey(frame, frame->seqnr - seqNrOffset); + + frame->time -= timeOffset; + frame->seqnr -= seqNrOffset; + + m_Delta.SetLargeTimeBufferSize(true); + + if (frame->entitynum) + { + for (unsigned int i = 0; i < fullFrame.entitynum; i++) + { + entity_state_t *entity = &((entity_state_t *)fullFrame.entities)[i]; + if (entity->animtime != m_BaseLines[entity->number].animtime) { + entity->animtime -= timeOffset; + } + + if (entity->impacttime != m_BaseLines[entity->number].impacttime) { + entity->impacttime -= timeOffset; + } + + if (entity->starttime != m_BaseLines[entity->number].starttime) { + entity->starttime -= timeOffset; + } + } + + BitBuffer tempStream(frame->entities, frame->entitiesSize); + memset(frame->entities, 0, frame->entitiesSize); + + int newsize = CompressFrame(&fullFrame, &tempStream); + if ((unsigned)newsize > frame->entitiesSize || tempStream.IsOverflowed()) { + m_System->Printf("WARNING! World::RearrangeFrame: wrong entities size (%i != %i).\n", frame->entitiesSize, newsize); + return; + } + + frame->entitiesSize = newsize; + } + + m_Delta.SetLargeTimeBufferSize(false); +} + +void World::UpdateServerInfo() +{ + strcopy(m_DetailedServerInfo.address, ""); + strcopy(m_DetailedServerInfo.name, GetHostName()); + + COM_FileBase(m_LevelName, m_DetailedServerInfo.map); + m_DetailedServerInfo.map[sizeof(m_DetailedServerInfo.map) - 1] = '\0'; + + strcopy(m_DetailedServerInfo.gamedir, m_GameDir); + strcopy(m_DetailedServerInfo.description, "HLTV"); + + m_DetailedServerInfo.activePlayers = m_PlayerNum; + m_DetailedServerInfo.maxPlayers = m_Maxclients; + m_DetailedServerInfo.protocol = m_Protocol; + m_DetailedServerInfo.type = GetServerType(HLST_Dedicated)[0]; + m_DetailedServerInfo.os = GetServerOS()[0]; + m_DetailedServerInfo.pw = PROTOCOL_VERSION; + m_DetailedServerInfo.mod = false; +} + +void World::SetHLTV(bool state) +{ + m_IsHLTV = state; +} + +bool World::IsHLTV() +{ + return m_IsHLTV; +} + +void World::RunFrame(double time) +{ + BaseSystemModule::RunFrame(time); +} + +void World::ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) +{ + BaseSystemModule::ReceiveSignal(module, signal, data); +} + +void World::ExecuteCommand(int commandID, char *commandLine) +{ + BaseSystemModule::ExecuteCommand(commandID, commandLine); +} + +void World::RegisterListener(ISystemModule *module) +{ + BaseSystemModule::RegisterListener(module); +} + +void World::RemoveListener(ISystemModule *module) +{ + BaseSystemModule::RemoveListener(module); +} + +IBaseSystem *World::GetSystem() +{ + return BaseSystemModule::GetSystem(); +} + +int World::GetSerial() +{ + return BaseSystemModule::GetSerial(); +} + +char *World::GetName() +{ + return BaseSystemModule::GetName(); +} + +int World::GetState() +{ + return BaseSystemModule::GetState(); +} + +int World::GetVersion() +{ + return BaseSystemModule::GetVersion(); +} + +IBaseInterface *CreateWorld() +{ + IWorld *pWorld = new World; + return (IBaseInterface *)pWorld; +} + +#ifndef HOOK_HLTV +bool World::IsDeltaEncoder() const +{ + if (Delta::m_CustomentityDelta + && Delta::m_EntityDelta + && Delta::m_PlayerDelta) { + return true; + } + + return false; +} + +delta_t *World::GetDeltaEncoder(int index, bool custom) +{ + if (custom) { + return Delta::m_CustomentityDelta; + } + else if (IsPlayerIndex(index)) { + return Delta::m_PlayerDelta; + } + + return Delta::m_EntityDelta; +} + +delta_t *World::GetEventDelta() const { + return Delta::m_EventDelta; +} + +delta_t *World::GetClientDelta() const { + return Delta::m_ClientDelta; +} + +delta_t *World::GetEntityDelta() const { + return Delta::m_EntityDelta; +} + +delta_t *World::GetWeaponDelta() const { + return Delta::m_WeaponDelta; +} + +EXPOSE_INTERFACE_FN(CreateWorld, World, WORLD_INTERFACE_VERSION); +#endif // HOOK_HLTV diff --git a/rehlds/HLTV/Core/src/World.h b/rehlds/HLTV/Core/src/World.h new file mode 100644 index 0000000..057c2c8 --- /dev/null +++ b/rehlds/HLTV/Core/src/World.h @@ -0,0 +1,310 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "info.h" // MAX_INFO_STRING +#include "qlimits.h" // MAX_PACKET_ENTITIES + +#include "Delta.h" +#include "ObjectDictionary.h" +#include "BSPModel.h" + +// TODO: move to qlimits.h +#define RESOURCE_INDEX_BITS 12 +#define RESOURCE_MAX_COUNT (1 << RESOURCE_INDEX_BITS) + +class World: public IWorld, public BaseSystemModule { +public: + World() {} + virtual ~World() {} + + bool Init(IBaseSystem *system, int serial, char *name); + void RunFrame(double time); + void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data); + void ExecuteCommand(int commandID, char *commandLine); + void RegisterListener(ISystemModule *module); + void RemoveListener(ISystemModule *module); + IBaseSystem *GetSystem(); + int GetSerial(); + char *GetStatusLine(); + char *GetType(); + char *GetName(); + int GetState(); + int GetVersion(); + void ShutDown(); + + double GetTime(); + NetAddress *GetGameServerAddress(); + char *GetLevelName(); + char *GetGameDir(); + frame_t *GetFrameByTime(double time); + frame_t *GetFrameBySeqNr(unsigned int seqnr); + frame_t *GetLastFrame(); + frame_t *GetFirstFrame(); + int GetServerCount(); + int GetSlotNumber(); + int GetMaxClients(); + int GetNumPlayers(); + IBSPModel *GetWorldModel(); + InfoString *GetServerInfoString(); + bool GetPlayerInfoString(int playerNum, InfoString *infoString); + UserMsg *GetUserMsg(int msgNumber); + char *GetHostName(); + serverinfo_t *GetServerInfo(); + + bool IsPlayerIndex(int index); + bool IsVoiceEnabled(); + bool IsActive(); + bool IsPaused(); + bool IsComplete(); + bool IsHLTV(); + void Reset(); + + void SetServerInfo(int protocol, CRC32_t nserverCRC, unsigned char *nclientdllmd5, int nmaxclients, int nplayernum, int ngametype, char *ngamedir, char *nservername, char *nlevelname); + void SetServerInfoString(char *infostring); + void SetServerInfo(serverinfo_t *serverinfo); + + void UpdateServerInfo(); + void SetPaused(bool state); + void SetTime(double newTime); + void SetBufferSize(float seconds); + void SetVoiceEnabled(bool state); + void SetMoveVars(movevars_t *nmovevars); + void SetCDInfo(int ncdtrack, int nlooptrack); + void SetHLTV(bool state); + void SetExtraInfo(char *nclientfallback, int nallowCheats); + void SetViewEntity(int nviewentity); + void SetGameServerAddress(NetAddress *address); + void SetHostName(char *name); + void NewGame(int newServerCount); + void FinishGame(); + bool SaveAsDemo(char *filename, IDirector *director); + void StopGame(); + int FindUserMsgByName(char *name); + void ParseDeltaDescription(BitBuffer *stream); + void ParseBaseline(BitBuffer *stream); + void ParseEvent(BitBuffer *stream); + void ParseClientData(BitBuffer *stream, unsigned int deltaSeqNr, BitBuffer *to, clientdata_t *clientData); + bool GetUncompressedFrame(unsigned int seqNr, frame_t *frame); + bool UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream); + bool UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream, unsigned int from); + bool GetClientData(unsigned int SeqNr, clientdata_t *clientData); + bool GetClientData(frame_t *frame, clientdata_t *clientData); + int AddFrame(frame_t *newFrame); + bool AddResource(resource_t *resource); + void AddLightStyle(int index, char *style); + bool AddSignonData(unsigned char type, unsigned char *data, int size); + bool AddUserMessage(int msgNumber, int size, char *name); + void AddBaselineEntity(int index, entity_state_t *ent); + void AddInstancedBaselineEntity(int index, entity_state_t *ent); + void UpdatePlayer(int playerNum, int userId, char *infostring, char *hashedcdkey); + + void WriteFrame(frame_t *frame, unsigned int lastFrameSeqnr, BitBuffer *reliableStream, BitBuffer *unreliableStream, unsigned int deltaSeqNr, unsigned int clientDelta, bool addVoice); + void WriteNewData(BitBuffer *stream); + void WriteClientUpdate(BitBuffer *stream, int playerIndex); + void WriteMovevars(BitBuffer *stream); + void WriteSigonData(BitBuffer *stream); + void WriteLightStyles(BitBuffer *stream); + + int RemoveFrames(unsigned int startSeqNr, unsigned int endSeqNr); + int DuplicateFrames(unsigned int startSeqNr, unsigned int endSeqNr); + int MoveFrames(unsigned int startSeqNr, unsigned int endSeqNr, double destSeqnr); + int RevertFrames(unsigned int startSeqNr, unsigned int endSeqNr); + +private: + int CompressFrame(frame_t *from, BitBuffer *stream); + int ParseDeltaHeader(BitBuffer *stream, bool *remove, bool *custom, int *numbase, bool *newbl, int *newblindex, bool full, int *offset); + void SetDirector(IDirector *director); + void SetTimeScale(float scale); + void SetGameGroupAddress(NetAddress *addr); + bool SetMaxClients(int max); + void SetName(char *newName); + IDirector *GetDirector(); + float GetBufferedGameTime(); + void ConnectionComplete(); + + void WriteResources(BitBuffer *stream); + void WriteDeltaDescriptions(BitBuffer *stream); + void WriteRegisteredUserMessages(BitBuffer *stream); + void WriteBaseline(BitBuffer *stream); + void WriteServerinfo(BitBuffer *stream); + void WriteCustomDecals(BitBuffer *stream); + void WritePacketEntities(BitBuffer *stream, frame_t *frame, frame_t *deltaframe); + bool WriteDeltaEntities(BitBuffer *stream, frame_t *fullFrame, unsigned int deltaSeqNr, unsigned int clientDelta); + + enum WorldState { + WORLD_UNDEFINED, + WORLD_INITIALIZING, + WORLD_DISCONNECTED, + WORLD_CONNECTING, + WORLD_RUNNING, + WORLD_COMPLETE + }; + + void SetState(WorldState newState); + void ClearUserMessages(); + void ClearServerInfo(); + void ClearResources(); + void ClearInstancedBaseline(); + void ClearBaseline(); + void ClearLightStyles(); + void ClearPlayers(); + void ClearFrames(); + void ClearEntityCache(); + bool GetFrameFromCache(unsigned int seqNr, entity_state_t **entities); + bool GetUncompressedFrame(frame_t *deltaFrame, frame_t *frame); + bool GetDeltaFromCache(unsigned int seqNr, unsigned int deltaNr, BitBuffer **buffer); + void CheckFrameBufferSize(); + void ReorderFrameTimes(float newLastTime); + int FindBestBaseline(int index, entity_state_t **baseline, entity_state_t *to, int num, bool custom); + void RearrangeFrame(frame_t *frame, int seqNrOffset, float timeOffset); + + delta_t *GetEventDelta() const; + delta_t *GetClientDelta() const; + delta_t *GetEntityDelta() const; + delta_t *GetWeaponDelta() const; + delta_t *GetDeltaEncoder(int index, bool custom); + bool IsDeltaEncoder() const; + +protected: + bool m_IsPaused; + int m_WorldState; + int m_Protocol; + int m_ServerCount; + CRC32_t m_ServerCRC; + unsigned char m_ClientdllMD5[16]; + int m_Maxclients; + int m_PlayerNum; + int m_GameType; + char m_GameDir[MAX_PATH]; + char m_LevelName[40]; + char m_ServerName[255]; + + int m_ViewEntity; + serverinfo_t m_DetailedServerInfo; + + enum { + MAX_ENTITIES = 1380, + MAX_INSTANCED_BASELINES = 64, + MAX_FRAME_CACHE = 32, + MAX_SCOREBOARDNAME = 32, + + MAX_SERVERINFO_STRING = 512, + MAX_BUFFER_SIGNONDATA = 32768 + }; + + // Defined in client.h differently + typedef struct player_info_s + { + int userid; // User id on server + + // User info string + char userinfo[MAX_INFO_STRING]; // User info string + char name[MAX_SCOREBOARDNAME]; // Name + int spectator; // Spectator or not, unused + int ping; + int packet_loss; + + // skin information + char model[MAX_PATH]; + int topcolor; + int bottomcolor; + + bool active; + char hashedcdkey[16]; + + int trackerID; + + } player_info_t; + + player_info_t m_Players[MAX_CLIENTS]; + unsigned char m_EntityBuffer[87040]; + + entity_state_t m_BaseLines[MAX_ENTITIES]; + int m_MaxBaseLines; + entity_state_t m_Instanced_BaseLines[MAX_INSTANCED_BASELINES]; + + int m_MaxInstanced_BaseLine; + char m_Lightstyles[MAX_LIGHTSTYLES][65]; + + movevars_t m_MoveVars; + BSPModel m_WorldModel; + InfoString m_ServerInfo; + UserMsg *m_ClientUserMsgs; + resource_t *m_ResourcesList; + int m_ResourcesNum; + + BitBuffer m_SignonData; + int m_CDTrack; + int m_LoopTrack; + + ObjectDictionary m_Frames; + ObjectDictionary m_FramesByTime; + ObjectDictionary m_CamCommands; + + unsigned int m_SequenceNr; + float m_MaxBufferLength; + + typedef struct frameCache_s { + unsigned int seqNr; + entity_state_t entities[MAX_PACKET_ENTITIES]; + } frameCache_t; + + typedef struct deltaCache_s { + unsigned int seqNr; + unsigned int deltaNr; + BitBuffer buffer; + } deltaCache_t; + + int m_MaxCacheIndex; + frameCache_t *m_FrameCache; + deltaCache_t *m_DeltaCache; + int m_CacheHits; + int m_CacheFaults; + + double m_WorldTime; + double m_StartTime; + + bool m_VoiceEnabled; + char m_ClientFallback[MAX_PATH]; + bool m_AllowCheats; + bool m_IsHLTV; + char m_HostName[255]; + + NetAddress m_GameServerAddress; + +#ifdef HOOK_HLTV + static DeltaWrapper m_Delta; +#else + Delta m_Delta; +#endif // HOOK_HLTV + +}; + +extern char g_DownloadURL[128]; diff --git a/rehlds/HLTV/Core/src/precompiled.cpp b/rehlds/HLTV/Core/src/precompiled.cpp new file mode 100644 index 0000000..5f656a4 --- /dev/null +++ b/rehlds/HLTV/Core/src/precompiled.cpp @@ -0,0 +1 @@ +#include "precompiled.h" diff --git a/rehlds/HLTV/Core/src/precompiled.h b/rehlds/HLTV/Core/src/precompiled.h new file mode 100644 index 0000000..b17cb08 --- /dev/null +++ b/rehlds/HLTV/Core/src/precompiled.h @@ -0,0 +1,44 @@ +#pragma once + +#include "basetypes.h" +#include "archtypes.h" +#include "mathlib.h" +#include "FileSystem.h" + +#include "interface.h" +#include "IBaseSystem.h" + +#include "mem.h" +#include "common.h" + +// Hooks stuff +#include "hookers/HLTV/Core/hooklist.h" + +#include "common/md5.h" +#include "common/random.h" +#include "common/byteorder.h" +#include "common/ServerInfo.h" +#include "common/common_hltv.h" +#include "common/net_internal.h" +#include "common/mathlib_internal.h" + +#include "common/DirectorCmd.h" +#include "common/NetAddress.h" +#include "common/NetChannel.h" +#include "common/BaseClient.h" + +#include "common/DemoFile.h" +#include "common/munge.h" + +#include +#include +#include +#include +#include +#include + +// Core module stuff +#include "World.h" +#include "Network.h" +#include "NetSocket.h" +#include "Server.h" diff --git a/rehlds/HLTV/Core/src/public_amalgamation.cpp b/rehlds/HLTV/Core/src/public_amalgamation.cpp new file mode 100644 index 0000000..1fc308c --- /dev/null +++ b/rehlds/HLTV/Core/src/public_amalgamation.cpp @@ -0,0 +1,3 @@ +#include "precompiled.h" + +#include "interface.cpp" diff --git a/rehlds/HLTV/DemoPlayer/build.gradle b/rehlds/HLTV/DemoPlayer/build.gradle new file mode 100644 index 0000000..11ae425 --- /dev/null +++ b/rehlds/HLTV/DemoPlayer/build.gradle @@ -0,0 +1,139 @@ +import org.doomedsociety.gradlecpp.cfg.ToolchainConfigUtils +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.toolchain.icc.Icc +import org.doomedsociety.gradlecpp.toolchain.icc.IccCompilerPlugin +import org.doomedsociety.gradlecpp.gcc.GccToolchainConfig +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeLibrarySpec +import org.gradle.nativeplatform.toolchain.VisualCpp + +apply plugin: 'cpp' +apply plugin: IccCompilerPlugin +apply plugin: GccCompilerPlugin + +void setupToolchain(NativeBinarySpec b) { + def cfg = rootProject.createToolchainConfig(b); + cfg.projectInclude(project, '/..', '/../..', '/src', '/../common', '/../../common', '/../../engine', '/../../public', '/../../public/rehlds', '/../../pm_shared'); + cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'DEMOPLAYER_MODULE' + + if (cfg instanceof MsvcToolchainConfig) { + cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig( + enabled: true, + pchHeader: 'precompiled.h', + pchSourceSet: 'demoplayer_pch' + ); + + cfg.singleDefines('_CRT_SECURE_NO_WARNINGS') + cfg.compilerOptions.args '/Ob2', '/Oi', '/GF' + cfg.extraLibs "psapi.lib" + } + else if (cfg instanceof GccToolchainConfig) { + cfg.compilerOptions.pchConfig = new GccToolchainConfig.PrecompilerHeaderOptions( + enabled: true, + pchSourceSet: 'demoplayer_pch' + ); + + cfg.compilerOptions.languageStandard = 'c++0x' + cfg.defines([ + '_strdup': 'strdup', + '_stricmp': 'strcasecmp', + '_strnicmp': 'strncasecmp', + '_vsnprintf': 'vsnprintf', + '_snprintf': 'snprintf', + ]); + + cfg.compilerOptions.args '-Qoption,cpp,--treat_func_as_string_literal_cpp', '-fno-exceptions' + } + + ToolchainConfigUtils.apply(project, cfg, b); +} + +model { + buildTypes { + release + } + + platforms { + x86 { + architecture "x86" + } + } + + toolChains { + visualCpp(VisualCpp) { + } + icc(Icc) { + } + } + + components { + demoplayer(NativeLibrarySpec) { + targetPlatform 'x86' + baseName 'demoplayer' + + sources { + demoplayer_main(CppSourceSet) { + source { + srcDir "src" + include "**/*.cpp" + exclude "precompiled.cpp" + } + } + + demoplayer_common(CppSourceSet) { + source { + srcDirs "/../../common", "/../common" + + // common + include "BaseSystemModule.cpp" + include "ObjectDictionary.cpp" + include "ObjectList.cpp" + include "TokenLine.cpp" + + // HLTV common + include "BitBuffer.cpp" + include "byteorder.cpp" + include "common.cpp" + include "DirectorCmd.cpp" + include "mathlib.cpp" + } + } + + demoplayer_engine(CppSourceSet) { + source { + srcDir "../../engine" + include "mem.cpp" + } + } + + demoplayer_pch(CppSourceSet) { + source { + srcDir "src" + include "precompiled.cpp" + } + } + } + + binaries.all { + NativeBinarySpec b -> project.setupToolchain(b) + } + } + } +} + +task buildFixes { + dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} + +task buildRelease { + dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} + +// prevent static lib building +binaries.withType(StaticLibraryBinarySpec) { binary -> + buildable = false +} diff --git a/rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.sln b/rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.sln new file mode 100644 index 0000000..317caa2 --- /dev/null +++ b/rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DemoPlayer", "DemoPlayer.vcxproj", "{05292761-0847-4A68-BA10-9D384DC0D3EE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {05292761-0847-4A68-BA10-9D384DC0D3EE}.Debug|Win32.ActiveCfg = Debug|Win32 + {05292761-0847-4A68-BA10-9D384DC0D3EE}.Debug|Win32.Build.0 = Debug|Win32 + {05292761-0847-4A68-BA10-9D384DC0D3EE}.Release|Win32.ActiveCfg = Release|Win32 + {05292761-0847-4A68-BA10-9D384DC0D3EE}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.vcxproj b/rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.vcxproj new file mode 100644 index 0000000..339ad05 --- /dev/null +++ b/rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.vcxproj @@ -0,0 +1,175 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + true + true + + + true + true + + + + + + + + + Create + Create + + + + + + + + + + + true + true + + + + + + + + + + + + {05292761-0847-4A68-BA10-9D384DC0D3EE} + Win32Proj + DemoPlayer + 8.1 + + + + DynamicLibrary + true + v120_xp + v140_xp + MultiByte + + + DynamicLibrary + false + v120_xp + v140_xp + true + MultiByte + + + + + + + + + + + + + + + true + + + false + + + + Use + Level3 + Disabled + HLTV;WIN32;_DEBUG;_WINDOWS;_USRDLL;DEMOPLAYER_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + precompiled.h + $(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;$(ProjectDir)\..\..\..\game_shared;$(ProjectDir)\..\..\..\..\dep\bzip2\include;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Windows + true + psapi.lib;%(AdditionalDependencies) + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + echo Empty Action + + + Force build to run Pre-Build event + + + git.always.run + + + git.always.run + + + + + Level3 + Use + MaxSpeed + true + true + HOOK_HLTV;HLTV;WIN32;NDEBUG;_WINDOWS;_USRDLL;DEMOPLAYER_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitiHOOons) + precompiled.h + $(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;%(AdditionalIncludeDirectories) + MultiThreaded + true + + + Windows + true + true + true + psapi.lib;%(AdditionalDependencies) + false + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + echo Empty Action + + + Force build to run Pre-Build event + + + git.always.run + + + git.always.run + + + + + + \ No newline at end of file diff --git a/rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.vcxproj.filters b/rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.vcxproj.filters new file mode 100644 index 0000000..9d7f4cd --- /dev/null +++ b/rehlds/HLTV/DemoPlayer/msvc/DemoPlayer.vcxproj.filters @@ -0,0 +1,114 @@ + + + + + {4d99bbd6-4658-4bed-a29e-9322ec16db5a} + + + {c58ccefe-767c-4f0a-b075-c55e24d15263} + + + {ca1c7722-8e65-480d-9e3c-34f7f2524372} + + + {1f62aa80-c3f7-4f97-a93e-5b67b153a751} + + + {8712d29d-6fec-42fb-9f6e-5618302f3203} + + + {fab89dcf-8536-490e-81b3-d9bb29fce8c6} + + + + + src + + + src + + + src + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + src\hookers + + + src\hookers + + + common + + + common + + + common + + + common + + + engine + + + + + src + + + src + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + src\hookers + + + common + + + common + + + common + + + common + + + engine + + + HLTV\common + + + \ No newline at end of file diff --git a/rehlds/HLTV/DemoPlayer/msvc/PostBuild.bat b/rehlds/HLTV/DemoPlayer/msvc/PostBuild.bat new file mode 100644 index 0000000..8583878 --- /dev/null +++ b/rehlds/HLTV/DemoPlayer/msvc/PostBuild.bat @@ -0,0 +1,39 @@ +@echo OFF +:: +:: Post-build auto-deploy script +:: Create and fill PublishPath.txt file with path to deployment folder +:: I.e. PublishPath.txt should contain one line with a folder path +:: Call it so: +:: IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") +:: + +SET targetDir=%~1 +SET targetName=%~2 +SET targetExt=%~3 +SET projectDir=%~4 +SET destination= + +IF NOT EXIST "%projectDir%\PublishPath.txt" ( + ECHO No deployment path specified. Create PublishPath.txt near PostBuild.bat with paths on separate lines for auto deployment. + exit /B 0 +) + +FOR /f "tokens=* delims= usebackq" %%a IN ("%projectDir%\PublishPath.txt") DO ( + ECHO Deploying to: %%a + IF NOT "%%a" == "" ( + copy /Y "%targetDir%%targetName%%targetExt%" "%%a" + IF NOT ERRORLEVEL 1 ( + IF EXIST "%targetDir%%targetName%.pdb" ( + copy /Y "%targetDir%%targetName%.pdb" "%%a" + ) + ) ELSE ( + ECHO PostBuild.bat ^(27^) : warning : Can't copy '%targetName%%targetExt%' to deploy path '%%a' + ) + ) +) + +IF "%%a" == "" ( + ECHO No deployment path specified. +) + +exit /B 0 \ No newline at end of file diff --git a/rehlds/HLTV/DemoPlayer/src/DemoPlayer.cpp b/rehlds/HLTV/DemoPlayer/src/DemoPlayer.cpp new file mode 100644 index 0000000..ff12b72 --- /dev/null +++ b/rehlds/HLTV/DemoPlayer/src/DemoPlayer.cpp @@ -0,0 +1,1060 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +DemoPlayer::DemoPlayer() +{ + m_World = nullptr; + m_System = nullptr; + m_Engine = nullptr; + m_Server = nullptr; +} + +bool DemoPlayer::Init(IBaseSystem *system, int serial, char *name) +{ + if (!BaseSystemModule::Init(system, serial, name)) { + return false; + } + + if (!name) { + SetName(DEMOPLAYER_INTERFACE_VERSION); + } + + m_Engine = (IEngineWrapper *)m_System->GetModule(ENGINEWRAPPER_INTERFACE_VERSION, ""); + if (!m_Engine) { + m_System->Printf("DemoPlayer::Init: couldn't get engine interface.\n"); + return false; + } + + m_Server = (IServer *)m_System->GetModule(SERVER_INTERFACE_VERSION, "core", "DemoServer"); + if (!m_Server) { + m_System->Printf("DemoPlayer::Init: couldn't load server module.\n"); + return false; + } + + m_Server->RegisterListener(this); + m_Server->SetDirector(GetDirector()); + m_Server->SetDelayReconnect(false); + + m_World = (IWorld *)m_System->GetModule(WORLD_INTERFACE_VERSION, "core", "DemoWorld"); + if (!m_World) { + m_System->Printf("DemoPlayer::Init: couldn't load world module.\n"); + return false; + } + + m_System->RegisterCommand("dem_jump", this, CMD_ID_JUMP); + m_System->RegisterCommand("dem_forcehltv", this, CMD_ID_FORCEHLTV); + m_System->RegisterCommand("dem_pause", this, CMD_ID_PAUSE); + m_System->RegisterCommand("dem_speed", this, CMD_ID_SPEED); + m_System->RegisterCommand("dem_start", this, CMD_ID_START); + m_System->RegisterCommand("dem_save", this, CMD_ID_SAVE); + + m_World->RegisterListener(this); + m_DemoStream.Resize(65536); + + SetTimeScale(1); + SetPaused(false); + + m_Outgoing_sequence = 0; + m_DeltaFrameSeqNr = 0; + m_LastFrameSeqNr = 0; + m_LastCmd = nullptr; + + m_LastFrameTime = 0; + m_CommandCounter = 0; + m_PlayerState = DEMOPLAYER_UNDEFINED; + m_EditorMode = false; + m_IsSaving = false; + m_MasterMode = true; + + memset(m_DemoFileName, 0, sizeof(m_DemoFileName)); + + m_State = MODULE_RUNNING; + m_System->DPrintf("DemoPlayer module initialized.\n"); + return true; +} + +void DemoPlayer::RunFrame(double time) +{ + BaseSystemModule::RunFrame(time); + + if (m_PlayerState != DEMOPLAYER_UNDEFINED) { + RunClocks(); + } +} + +void DemoPlayer::ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) +{ + int from = module->GetSerial(); + + // Server module + if (from == m_Server->GetSerial()) + { + if (signal == 6) { + m_System->Printf("Demo file completely loaded.\n"); + return; + } + } + + // World module + if (from == m_World->GetSerial()) + { + BitBuffer buf(32); + switch (signal) + { + case 1: + m_StartTime = 9999; + break; + case 2: + NewGame(m_World); + break; + case 5: + case 6: + buf.WriteByte(svc_setpause); + buf.WriteByte(signal == 5 ? true : false); + break; + } + } +} + +bool DemoPlayer::SaveGame(char *filename) +{ + if (IsLoading()) { + return false; + } + + SetPaused(true); + + m_IsSaving = true; + auto ret = m_World->SaveAsDemo(filename ? filename : m_DemoFileName, this); + m_IsSaving = false; + + return ret; +} + +double DemoPlayer::GetWorldTime() +{ + return m_WorldTime; +} + +double DemoPlayer::GetStartTime() +{ + frame_t *frame = m_World->GetFirstFrame(); + if (!frame) { + return 0; + } + + return frame->time; +} + +double DemoPlayer::GetEndTime() +{ + frame_t *frame = m_World->GetLastFrame(); + if (!frame) { + return 0; + } + + return frame->time; +} + +double DemoPlayer::GetPlayerTime() +{ + return m_PlayerTime; +} + +bool DemoPlayer::IsLoading() +{ + if (!m_Server) { + return false; + } + + return m_Server->IsConnected(); +} + +bool DemoPlayer::IsActive() +{ + return m_PlayerState != 0; +} + +char *DemoPlayer::GetType() +{ + return DEMOPLAYER_INTERFACE_VERSION; +} + +char *DemoPlayer::GetStatusLine() +{ + return "No status available.\n"; +} + +IWorld *DemoPlayer::GetWorld() +{ + return m_World; +} + +IDirector *DemoPlayer::GetDirector() +{ + return this; +} + +void DemoPlayer::ExecuteCommand(int commandID, char *commandLine) +{ + switch (commandID) + { + case CMD_ID_JUMP: + CMD_Jump(commandLine); + break; + case CMD_ID_FORCEHLTV: + CMD_ForceHLTV(commandLine); + break; + case CMD_ID_PAUSE: + CMD_Pause(commandLine); + break; + case CMD_ID_SPEED: + CMD_Speed(commandLine); + break; + case CMD_ID_START: + CMD_Start(commandLine); + break; + case CMD_ID_SAVE: + CMD_Save(commandLine); + break; + default: + m_System->Printf("ERROR! DemoPlayer::ExecuteCommand: unknown command ID %i.\n", commandID); + break; + } +} + +void DemoPlayer::CMD_Jump(char *cmdLine) +{ + if (!IsActive()) { + m_System->Printf("Not viewing a demo.\n"); + return; + } + + TokenLine params(cmdLine); + if (params.CountToken() != 2) { + m_System->Printf("dem_jump \n"); + return; + } + + SetWorldTime(atof(params.GetToken(1)), true); + SetPaused(true); +} + +void DemoPlayer::CMD_ForceHLTV(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) { + m_System->Printf("dem_forcehltv <0|1>\n"); + return; + } + + char *val = params.GetToken(1); + ForceHLTV(atoi(val) ? true : false); +} + +void DemoPlayer::CMD_Save(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) { + m_System->Printf("dem_save \n"); + return; + } + + if (!SaveGame(params.GetToken(1))) { + m_System->Printf("Warning! Could save game as demo file.\n"); + return; + } +} + +void DemoPlayer::CMD_Pause(char *cmdLine) +{ + if (!IsActive()) { + m_System->Printf("Not viewing a demo.\n"); + return; + } + + TokenLine params(cmdLine); + if (params.CountToken() != 2) { + m_System->Printf("dem_pause <0|1>\n"); + return; + } + + char *val = params.GetToken(1); + SetPaused(atoi(val) ? true : false); +} + +void DemoPlayer::CMD_Speed(char *cmdLine) +{ + if (!IsActive()) { + m_System->Printf("Not viewing a demo.\n"); + return; + } + + TokenLine params(cmdLine); + if (params.CountToken() != 2) { + m_System->Printf("dem_speed \n"); + return; + } + + float timescale = (float)atof(params.GetToken(1)); + SetTimeScale(timescale); +} + +void DemoPlayer::CMD_Start(char *cmdLine) +{ + if (!IsActive()) { + m_System->Printf("Not viewing a demo.\n"); + return; + } + + SetWorldTime(GetStartTime(), false); +} + +float DemoPlayer::GetTimeScale() +{ + return m_TimeScale; +} + +char *DemoPlayer::GetModName() +{ + return "valve"; +} + +void DemoPlayer::WriteCommands(BitBuffer *stream, float startTime, float endTime) +{ + DirectorCmd *cmd = (DirectorCmd *)m_Commands.FindClosestKey(startTime); + while (cmd && cmd->GetTime() <= endTime) + { + if (cmd->GetTime() > startTime) + { + if (m_IsSaving) + { + cmd->WriteToStream(stream); + } + else + { + if (cmd->GetType() == DRC_CMD_TIMESCALE) + { + float timescale; + cmd->GetTimeScaleData(timescale); + + stream->WriteByte(svc_timescale); + stream->WriteFloat(timescale); + m_TimeScale = timescale; + } + else if (cmd->GetType() == DRC_CMD_CAMPATH) + { + float fov; + vec3_t v; + int flags; + cmd->GetCamPathData(v, v, fov, flags); + + if (flags & DRC_FLAG_STARTPATH) { + WriteCameraPath(cmd, stream); + } + } + else + { + cmd->WriteToStream(stream); + } + + m_LastCmd = cmd; + BaseSystemModule::FireSignal(2); + m_System->DPrintf("Director Cmd %s, Time %.2f\n", cmd->GetName(), cmd->GetTime()); + } + } + + cmd = (DirectorCmd *)m_Commands.GetNext(); + } +} + +int DemoPlayer::AddCommand(DirectorCmd *cmd) +{ + int type = cmd->GetType(); + if (type == DRC_CMD_WAYPOINTS) { + return 0; + } + + DirectorCmd *newcmd = new DirectorCmd; + newcmd->Copy(cmd); + + if (!m_Commands.Add(newcmd, newcmd->GetTime())) { + delete newcmd; + return 0; + } + + ReindexCommands(); + return newcmd->m_Index; +} + +bool DemoPlayer::RemoveCommand(int index) +{ + DirectorCmd *cmd = (DirectorCmd *)m_Commands.GetFirst(); + while (cmd) + { + if (cmd->m_Index == index) { + break; + } + + cmd = (DirectorCmd *)m_Commands.GetNext(); + } + + if (cmd) + { + m_Commands.Remove(cmd); + if (m_LastCmd == cmd) { + m_LastCmd = nullptr; + } + + delete cmd; + ReindexCommands(); + return true; + } + + return false; +} + +IObjectContainer *DemoPlayer::GetCommands() +{ + return &m_Commands; +} + +void DemoPlayer::SetWorldTime(double time, bool relative) +{ + if (relative) + m_WorldTime += time; + else + m_WorldTime = time; +} + +void DemoPlayer::SetTimeScale(float scale) +{ + m_TimeScale = clamp(scale, 0.05f, 4.0f); + + m_DemoStream.WriteByte(svc_timescale); + m_DemoStream.WriteFloat(m_TimeScale); +} + +void DemoPlayer::SetPaused(bool state) +{ + m_IsPaused = state; +} + +void DemoPlayer::SetEditMode(bool state) +{ + m_EditorMode = state; +} + +bool DemoPlayer::IsEditMode() +{ + return m_EditorMode; +} + +void DemoPlayer::Stop() +{ + m_Server->Disconnect(); + m_World->Reset(); + m_PlayerState = DEMOPLAYER_UNDEFINED; +} + +void DemoPlayer::ForceHLTV(bool state) +{ + m_ForceHLTV = state; +} + +void DemoPlayer::SetMasterMode(bool state) +{ + m_MasterMode = state; +} + +bool DemoPlayer::IsMasterMode() +{ + return m_MasterMode; +} + +bool DemoPlayer::IsPaused() +{ + return m_IsPaused; +} + +void DemoPlayer::GetDemoViewInfo(ref_params_t *rp, float *view, int *viewmodel) +{ + int i; + usercmd_t *oldcmd; + movevars_t *oldmv; + int oldviewport[4]; + + frame_t *frame = m_World->GetFrameBySeqNr(m_LastFrameSeqNr); + frame_t *fromFrame = m_World->GetFrameBySeqNr(m_LastFrameSeqNr - 1); + + if (!frame || !frame->demoInfo) { + return; + } + + oldviewport[0] = rp->viewport[0]; + oldviewport[1] = rp->viewport[1]; + oldviewport[2] = rp->viewport[2]; + oldviewport[3] = rp->viewport[3]; + + oldmv = rp->movevars; + oldcmd = rp->cmd; + + demo_info_t *demoInfo = (demo_info_t *)frame->demoInfo; + memcpy(rp, &demoInfo->rp, sizeof(*rp)); + + rp->viewport[0] = oldviewport[0]; + rp->viewport[1] = oldviewport[1]; + rp->viewport[2] = oldviewport[2]; + rp->viewport[3] = oldviewport[3]; + rp->cmd = oldcmd; + rp->movevars = oldmv; + + view[0] = demoInfo->view[0]; + view[1] = demoInfo->view[1]; + view[2] = demoInfo->view[2]; + + *viewmodel = demoInfo->viewmodel; + + if (fromFrame && fromFrame->demoInfo) + { + demo_info_t *fromDemoInfo = (demo_info_t *)fromFrame->demoInfo; + + if (fromFrame->time < frame->time) + { + float frac = float(m_WorldTime - fromFrame->time) / (frame->time - fromFrame->time); + for (i = 0; i < 3; i++) { + rp->vieworg[i] = (demoInfo->rp.vieworg[i] - fromDemoInfo->rp.vieworg[i]) * frac + fromDemoInfo->rp.vieworg[i]; + } + + for (i = 0; i < 3; i++) + { + float d = demoInfo->rp.viewangles[i] - fromDemoInfo->rp.viewangles[i]; + if (d > 180) { + d -= 360; + } + else if (d < -180) { + d += 360; + } + + rp->viewangles[i] = fromDemoInfo->rp.viewangles[i] + d * frac; + } + + NormalizeAngles(rp->viewangles); + + for (i = 0; i < 3; i++) { + rp->simvel[i] = (demoInfo->rp.simvel[i] - fromDemoInfo->rp.simvel[i]) * frac + fromDemoInfo->rp.simvel[i]; + } + + for (i = 0; i < 3; i++) { + rp->simorg[i] = (demoInfo->rp.simorg[i] - fromDemoInfo->rp.simorg[i]) * frac + fromDemoInfo->rp.simorg[i]; + } + + for (i = 0; i < 3; i++) { + rp->viewheight[i] = (demoInfo->rp.viewheight[i] - fromDemoInfo->rp.viewheight[i]) * frac + fromDemoInfo->rp.viewheight[i]; + } + + for (i = 0; i < 3; i++) { + view[i] = (demoInfo->view[i] - fromDemoInfo->view[i]) * frac + fromDemoInfo->view[i]; + } + } + } +} + +void DemoPlayer::WriteSpawn(BitBuffer *stream) +{ + m_World->WriteSigonData(stream); + + stream->WriteByte(svc_time); + stream->WriteFloat(1); + + for (int i = 0; i < m_World->GetMaxClients(); i++) { + m_World->WriteClientUpdate(stream, i); + } + + m_World->WriteLightStyles(stream); + + stream->WriteByte(svc_signonnum); + stream->WriteByte(1); +} + +void DemoPlayer::WriteCameraPath(DirectorCmd *cmd, BitBuffer *stream) +{ + ObjectList path; + path.Init(); + + float startTime = cmd->GetTime(); + bool firstCmd = true; + + DirectorCmd *command = (DirectorCmd *)m_Commands.FindExactKey(cmd->GetTime()); + while (command && command->GetType() == DRC_CMD_CAMPATH) + { + vec3_t v; + float fov; + int flags; + command->GetCamPathData(v, v, fov, flags); + + if (flags & DRC_FLAG_STARTPATH) + { + if (!firstCmd) { + break; + } + + firstCmd = false; + } + + path.AddTail(command); + command = (DirectorCmd *)m_Commands.GetNext(); + } + + command = (DirectorCmd *)path.GetFirst(); + if (!command) { + m_System->Printf("Warning! No waypoints in camera path!\n"); + return; + } + + int count = path.CountElements(); + int length = count * (command->m_Size + 2) + 2; + if (length > 250) { + m_System->Printf("Warning! Too many waypoints in a camera path!\n"); + return; + } + + // tell director about it + // send director message, that something important happed here + stream->WriteByte(svc_director); + stream->WriteByte(length); // command length in bytes + stream->WriteByte(DRC_CMD_WAYPOINTS); // event waypoints + stream->WriteByte(count); // count waypoints + + while (command) + { + float time = (command->GetTime() - startTime) * 100; + stream->WriteShort((int)time); + stream->WriteBuf(command->m_Data.GetData(), command->m_Size); + + command = (DirectorCmd *)path.GetNext(); + } +} + +void DemoPlayer::ReindexCommands() +{ + int index = 1; + DirectorCmd *cmd = (DirectorCmd *)m_Commands.GetFirst(); + while (cmd) + { + cmd->m_Index = index++; + cmd = (DirectorCmd *)m_Commands.GetNext(); + } + + BaseSystemModule::FireSignal(1); +} + +int DemoPlayer::ReadDemoMessage(unsigned char *buffer, int size) +{ + int lastSeqNr = m_LastFrameSeqNr; + switch (m_PlayerState) + { + case DEMOPLAYER_UNDEFINED: + case DEMOPLAYER_INITIALIZING: + return 0; + case DEMOPLAYER_CONNECTING: + { + m_World->WriteNewData(&m_DemoStream); + m_PlayerState = DEMOPLAYER_CONNECTED; + break; + } + case DEMOPLAYER_CONNECTED: + { + m_LastFrameSeqNr = 0; + m_DeltaFrameSeqNr = 0; + WriteSpawn(&m_DemoStream); + m_Engine->SetCvar("spec_pip", "0"); + + m_WorldTime = 0; + m_StartTime = m_PlayerTime; + + SetTimeScale(1); + SetPaused(false); + m_PlayerState = DEMOPLAYER_RUNNING; + break; + } + case DEMOPLAYER_RUNNING: + { + WriteDatagram(&m_DemoStream); + + int newSeqNr = m_LastFrameSeqNr; + while (lastSeqNr < newSeqNr) + { + frame_t *frame = m_World->GetFrameBySeqNr(++lastSeqNr); + if (frame && frame->demoData && frame->demoDataSize) { + BitBuffer stream(frame->demoData, frame->demoDataSize); + ExecuteDemoFileCommands(&stream); + } + } + break; + } + default: + break; + } + + int msgsize = m_DemoStream.CurrentSize(); + if (msgsize <= 0) { + return 0; + } + + if (msgsize > size) { + m_System->Printf("ERROR! DemoPlayer::ReadDemoMessage: data overflow (%i bytes).\n", msgsize); + return 0; + } + + memcpy(buffer, m_DemoStream.GetData(), msgsize); + m_DemoStream.FastClear(); + return msgsize; +} + +void DemoPlayer::ReadNetchanState(int *incoming_sequence, int *incoming_acknowledged, int *incoming_reliable_acknowledged, int *incoming_reliable_sequence, int *outgoing_sequence, int *reliable_sequence, int *last_reliable_sequence) +{ + *incoming_sequence = m_Outgoing_sequence; + *incoming_acknowledged = m_Outgoing_sequence; + *incoming_reliable_acknowledged = 0; + *incoming_reliable_sequence = 0; + *outgoing_sequence = m_Outgoing_sequence; + *reliable_sequence = 0; + *last_reliable_sequence = 0; +} + +void DemoPlayer::SetName(char *newName) +{ + strcopy(m_Name, newName); +} + +void DemoPlayer::RunClocks() +{ + float realTimeDiff = float(m_SystemTime - m_LastClockUpdateTime); + + m_LastClockUpdateTime = m_SystemTime; + m_PlayerTime = realTimeDiff + m_PlayerTime; + + if (!m_World->IsActive() || m_IsPaused) { + return; + } + + m_WorldTime = realTimeDiff + m_WorldTime; + + frame_t *lastFrame = m_World->GetFrameBySeqNr(m_LastFrameSeqNr); + frame_t *nextFrame = m_World->GetFrameBySeqNr(m_LastFrameSeqNr + 1); + if (nextFrame && lastFrame) + { + if ((nextFrame->time - lastFrame->time) > 2) { + m_WorldTime = nextFrame->time - 0.01f; + } + } + + lastFrame = m_World->GetLastFrame(); + frame_t *firstFrame = m_World->GetFirstFrame(); + if (firstFrame && lastFrame) + { + if (m_WorldTime > lastFrame->time) { + m_WorldTime = lastFrame->time; + } + else if (firstFrame->time > m_WorldTime) { + m_WorldTime = firstFrame->time - 0.01f; + } + } +} + +void DemoPlayer::NewGame(IWorld *world, IProxy *proxy) +{ + m_World = world; + m_PlayerTime = 1; + m_PlayerState = DEMOPLAYER_CONNECTING; + + m_Commands.Clear(true); + m_LastCmd = nullptr; + + BaseSystemModule::FireSignal(1); + + if (m_World->IsHLTV() || m_ForceHLTV) + { + static unsigned char cmd[] = { + 1, // command length in bytes + DRC_CMD_START // tell them for start director + }; + + m_World->AddSignonData(svc_director, cmd, sizeof(cmd)); + } +} + +void DemoPlayer::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) { + return; + } + + if (m_World) { + m_World->ShutDown(); + } + + if (m_Server) { + m_Server->ShutDown(); + } + + m_DemoStream.Free(); + m_Commands.Clear(true); + + BaseSystemModule::ShutDown(); + m_System->DPrintf("DemoPlayer module Shutdown.\n"); +} + +char *DemoPlayer::FormatTime(float time) +{ + static char timeCode[16]; + _snprintf(timeCode, sizeof(timeCode), "%02u:%02u:%02u", (int)time / 60, (int)time % 60, (int)(time * 100) % 100); + return timeCode; +} + +void DemoPlayer::RemoveFrames(double starttime, double endtime) +{ + ; +} + +void DemoPlayer::ExecuteDirectorCmd(DirectorCmd *cmd) +{ + switch (cmd->GetType()) + { + case DRC_CMD_CAMERA: + { + float fov; + int entity; + vec3_t position, angles; + cmd->GetCameraData(position, angles, fov, entity); + cmd->SetCameraData(position, angles, fov, 0); + cmd->WriteToStream(&m_DemoStream); + cmd->SetCameraData(position, angles, fov, entity); + break; + } + case DRC_CMD_TIMESCALE: + float timescale; + cmd->GetTimeScaleData(timescale); + SetTimeScale(timescale); + break; + default: + cmd->WriteToStream(&m_DemoStream); + break; + } +} + +char *DemoPlayer::GetFileName() +{ + return m_DemoFileName; +} + +DirectorCmd *DemoPlayer::GetLastCommand() +{ + return m_LastCmd; +} + +bool DemoPlayer::LoadGame(char *filename) +{ + if (!m_Server->LoadDemo(m_World, filename, m_ForceHLTV, false)) { + return false; + } + + strcopy(m_DemoFileName, filename); + + m_World->SetBufferSize(-1); + m_Outgoing_sequence = 0; + m_LastClockUpdateTime = 0; + m_LastFrameTime = 0; + m_PlayerState = DEMOPLAYER_INITIALIZING; + m_LastFrameTime = 0; + m_MasterMode = true; + + return true; +} + +void DemoPlayer::WriteDatagram(BitBuffer *stream) +{ + frame_t *frame = m_World->GetFrameByTime(m_WorldTime); + if (!frame) { + return; + } + + if (m_LastFrameSeqNr && m_LastFrameSeqNr <= frame->seqnr) + { + if (m_LastFrameSeqNr >= frame->seqnr) { + return; + } + } + else + { + m_LastFrameSeqNr = frame->seqnr - 1; + if (frame->seqnr - 1 >= frame->seqnr) { + return; + } + } + + double time = m_PlayerTime - (m_WorldTime - frame->time); + stream->WriteByte(svc_time); + stream->WriteFloat(float(time)); + + m_World->WriteFrame(frame, m_LastFrameSeqNr, stream, stream, m_DeltaFrameSeqNr, m_Outgoing_sequence, true); + + if (m_MasterMode) { + WriteCommands(stream, float(m_LastFrameTime), float(m_WorldTime)); + } + + m_LastFrameTime = m_WorldTime; + if (stream->IsOverflowed()) + { + m_System->Printf("Demo data stream overflow.\n"); + stream->Clear(); + + m_DeltaFrameSeqNr = 0; + m_LastFrameSeqNr = 0; + } + else + { + m_Outgoing_sequence++; + m_DeltaFrameSeqNr = frame->seqnr; + m_LastFrameSeqNr = frame->seqnr; + } +} + +void DemoPlayer::ExecuteDemoFileCommands(BitBuffer *stream) +{ + unsigned int cmd; + while ((cmd = stream->ReadByte()) != -1) + { + switch (cmd) + { + case DEMO_STRINCMD: + { + char szCmdName[64]; + stream->ReadBuf(sizeof(szCmdName), szCmdName); + m_Engine->Cbuf_AddText(szCmdName); + m_Engine->Cbuf_AddText("\n"); + break; + } + case DEMO_CLIENTDATA: + { + client_data_t cdat; + stream->ReadBuf(sizeof(cdat), &cdat); + m_Engine->DemoUpdateClientData(&cdat); + break; + } + case DEMO_EVENT: + { + int flags = _LittleLong(stream->ReadLong()); + int idx = _LittleLong(stream->ReadLong()); + float delay = _LittleFloat(stream->ReadFloat()); + + event_args_t eargs; + stream->ReadBuf(sizeof(eargs), &eargs); + + m_Engine->CL_QueueEvent(flags, idx, delay, &eargs); + break; + } + case DEMO_WEAPONANIM: + { + int anim = _LittleLong(stream->ReadLong()); + int body = _LittleLong(stream->ReadLong()); + + m_Engine->HudWeaponAnim(anim, body); + break; + } + case DEMO_PLAYSOUND: + { + int channel = stream->ReadLong(); + int sampleSize = stream->ReadLong(); + + char sample[256]; + stream->ReadBuf(sampleSize, sample); + sample[sampleSize] = '\0'; + + float attenuation = _LittleFloat(stream->ReadFloat()); + float volume = _LittleFloat(stream->ReadFloat()); + int flags = _LittleLong(stream->ReadLong()); + int pitch = _LittleLong(stream->ReadLong()); + + m_Engine->CL_DemoPlaySound(channel, sample, attenuation, volume, flags, pitch); + break; + } + case DEMO_DATA: + { + unsigned char data[32768]; + memset(data, 0, sizeof(data)); + + int length = stream->ReadLong(); + stream->ReadBuf(length, data); + m_Engine->ClientDLL_ReadDemoBuffer(length, data); + break; + } + default: + m_System->Printf("WARNING! DemoPlayer::ExecuteDemoFileCommands: unexpected demo file command %i\n", cmd); + return; + } + } +} + +void DemoPlayer::RegisterListener(ISystemModule *module) +{ + BaseSystemModule::RegisterListener(module); +} + +void DemoPlayer::RemoveListener(ISystemModule *module) +{ + BaseSystemModule::RemoveListener(module); +} + +IBaseSystem *DemoPlayer::GetSystem() +{ + return BaseSystemModule::GetSystem(); +} + +int DemoPlayer::GetSerial() +{ + return BaseSystemModule::GetSerial(); +} + +char *DemoPlayer::GetName() +{ + return BaseSystemModule::GetName(); +} + +int DemoPlayer::GetState() +{ + return BaseSystemModule::GetState(); +} + +int DemoPlayer::GetVersion() +{ + return BaseSystemModule::GetVersion(); +} diff --git a/rehlds/HLTV/DemoPlayer/src/DemoPlayer.h b/rehlds/HLTV/DemoPlayer/src/DemoPlayer.h new file mode 100644 index 0000000..4f54f0e --- /dev/null +++ b/rehlds/HLTV/DemoPlayer/src/DemoPlayer.h @@ -0,0 +1,193 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include +#include +#include + +#include "vmodes.h" +#include "cdll_int.h" +#include "IDemoPlayer.h" +#include "IEngineWrapper.h" + +#include "BaseSystemModule.h" +#include "ObjectDictionary.h" + +class IProxy; +class DirectorCmd; +class IBaseSystem; +class IObjectContainer; + +class DemoPlayer: public IDemoPlayer, public BaseSystemModule, public IDirector { +public: + DemoPlayer(); + virtual ~DemoPlayer() {} + + bool Init(IBaseSystem *system, int serial, char *name); + void RunFrame(double time); + void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data); + void ExecuteCommand(int commandID, char *commandLine); + void RegisterListener(ISystemModule *module); + void RemoveListener(ISystemModule *module); + IBaseSystem *GetSystem(); + int GetSerial(); + char *GetStatusLine(); + char *GetType(); + char *GetName(); + int GetState(); + int GetVersion(); + void ShutDown(); + + void NewGame(IWorld *world, IProxy *proxy = nullptr); + char *GetModName(); + void WriteCommands(BitBuffer *stream, float startTime, float endTime); + int AddCommand(DirectorCmd *cmd); + bool RemoveCommand(int index); + DirectorCmd *GetLastCommand(); + IObjectContainer *GetCommands(); + IDirector *GetDirector(); + void SetWorldTime(double time, bool relative); + void SetTimeScale(float scale); + void SetPaused(bool state); + void SetEditMode(bool state); + void SetMasterMode(bool state); + bool IsPaused(); + bool IsLoading(); + bool IsActive(); + bool IsEditMode(); + bool IsMasterMode(); + void RemoveFrames(double starttime, double endtime); + void ExecuteDirectorCmd(DirectorCmd *cmd); + double GetWorldTime(); + double GetStartTime(); + double GetEndTime(); + float GetTimeScale(); + IWorld *GetWorld(); + char *GetFileName(); + bool SaveGame(char *filename); + bool LoadGame(char *filename); + void Stop(); + void ForceHLTV(bool state); + void GetDemoViewInfo(ref_params_t *rp, float *view, int *viewmodel); + int ReadDemoMessage(unsigned char *buffer, int size); + void ReadNetchanState(int *incoming_sequence, int *incoming_acknowledged, int *incoming_reliable_acknowledged, int *incoming_reliable_sequence, int *outgoing_sequence, int *reliable_sequence, int *last_reliable_sequence); + void SetName(char *newName); + +private: + enum LocalCommandIDs { + CMD_ID_JUMP = 1, + CMD_ID_FORCEHLTV, + CMD_ID_PAUSE, + CMD_ID_SPEED, + CMD_ID_START, + CMD_ID_SAVE, + }; + + void CMD_Jump(char *cmdLine); + void CMD_ForceHLTV(char *cmdLine); + void CMD_Pause(char *cmdLine); + void CMD_Speed(char *cmdLine); + void CMD_Start(char *cmdLine); + void CMD_Save(char *cmdLine); + + struct LocalCommandID_s { + char *name; + LocalCommandIDs id; + void (DemoPlayer::*pfnCmd)(char *cmdLine); + }; + static LocalCommandID_s m_LocalCmdReg[]; + +protected: + double GetPlayerTime(); + char *FormatTime(float time); + + void RunClocks(); + void WriteDatagram(BitBuffer *stream); + void WriteSpawn(BitBuffer *stream); + void ReindexCommands(); + void WriteCameraPath(DirectorCmd *, BitBuffer *stream); + + enum DemoCmds { + DEMO_STRINCMD = 3, + DEMO_CLIENTDATA = 4, + DEMO_EVENT = 6, + DEMO_WEAPONANIM = 7, + DEMO_PLAYSOUND = 8, + DEMO_DATA = 9 + }; + + void ExecuteDemoFileCommands(BitBuffer *stream); + +private: + IEngineWrapper *m_Engine; + IWorld *m_World; + IServer *m_Server; + ObjectDictionary m_Commands; + DirectorCmd *m_LastCmd; + unsigned int m_CommandCounter; + char m_DemoFileName[MAX_PATH]; + + enum PlayerState { + DEMOPLAYER_UNDEFINED, + DEMOPLAYER_INITIALIZING, + DEMOPLAYER_CONNECTING, + DEMOPLAYER_CONNECTED, + DEMOPLAYER_RUNNING + }; + + int m_PlayerState; + BitBuffer m_DemoStream; + bool m_EditorMode; + bool m_MasterMode; + bool m_ForceHLTV; + bool m_IsSaving; + float m_TimeScale; + double m_WorldTime; + double m_PlayerTime; + double m_StartTime; + + double m_LastFrameTime; + bool m_IsPaused; + double m_LastClockUpdateTime; + + unsigned int m_LastFrameSeqNr; + unsigned int m_DeltaFrameSeqNr; + unsigned int m_Outgoing_sequence; +}; + +#ifndef HOOK_HLTV +// Use this to expose a singleton interface. This creates the global variable for you automatically. +#define EXPOSE_SINGLE_INTERFACE2(className, interfaceName, versionName) \ + static className __g_##className##_singleton;\ + static IBaseInterface *__Create##className##interfaceName##_interface() {return (IBaseInterface *)((interfaceName *)&__g_##className##_singleton);}\ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); + +EXPOSE_SINGLE_INTERFACE2(DemoPlayer, IDemoPlayer, DEMOPLAYER_INTERFACE_VERSION); +#endif // HOOK_HLTV diff --git a/rehlds/HLTV/DemoPlayer/src/precompiled.cpp b/rehlds/HLTV/DemoPlayer/src/precompiled.cpp new file mode 100644 index 0000000..5f656a4 --- /dev/null +++ b/rehlds/HLTV/DemoPlayer/src/precompiled.cpp @@ -0,0 +1 @@ +#include "precompiled.h" diff --git a/rehlds/HLTV/DemoPlayer/src/precompiled.h b/rehlds/HLTV/DemoPlayer/src/precompiled.h new file mode 100644 index 0000000..7f1d66c --- /dev/null +++ b/rehlds/HLTV/DemoPlayer/src/precompiled.h @@ -0,0 +1,23 @@ +#pragma once + +#include "archtypes.h" +#include "maintypes.h" + +#include "TokenLine.h" +#include "interface.h" + +#include "mem.h" +#include "common.h" + +#include "common/common_hltv.h" +#include "common/net_internal.h" +#include "common/mathlib_internal.h" +#include "common/byteorder.h" +#include "common/BitBuffer.h" +#include "common/DirectorCmd.h" +#include "common/DemoFile.h" + +#include "DemoPlayer.h" + +// Hooks stuff +#include "hookers/HLTV/DemoPlayer/hooklist.h" diff --git a/rehlds/HLTV/DemoPlayer/src/public_amalgamation.cpp b/rehlds/HLTV/DemoPlayer/src/public_amalgamation.cpp new file mode 100644 index 0000000..1fc308c --- /dev/null +++ b/rehlds/HLTV/DemoPlayer/src/public_amalgamation.cpp @@ -0,0 +1,3 @@ +#include "precompiled.h" + +#include "interface.cpp" diff --git a/rehlds/HLTV/Director/build.gradle b/rehlds/HLTV/Director/build.gradle new file mode 100644 index 0000000..23790c3 --- /dev/null +++ b/rehlds/HLTV/Director/build.gradle @@ -0,0 +1,139 @@ +import org.doomedsociety.gradlecpp.cfg.ToolchainConfigUtils +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.toolchain.icc.Icc +import org.doomedsociety.gradlecpp.toolchain.icc.IccCompilerPlugin +import org.doomedsociety.gradlecpp.gcc.GccToolchainConfig +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeLibrarySpec +import org.gradle.nativeplatform.toolchain.VisualCpp + +apply plugin: 'cpp' +apply plugin: IccCompilerPlugin +apply plugin: GccCompilerPlugin + +void setupToolchain(NativeBinarySpec b) { + def cfg = rootProject.createToolchainConfig(b); + cfg.projectInclude(project, '/..', '/../..', '/src', '/../../common', '/../../engine', '/../../public', '/../../public/rehlds', '/../../pm_shared'); + cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'DIRECTOR_MODULE' + + if (cfg instanceof MsvcToolchainConfig) { + cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig( + enabled: true, + pchHeader: 'precompiled.h', + pchSourceSet: 'director_pch' + ); + + cfg.singleDefines('_CRT_SECURE_NO_WARNINGS') + cfg.compilerOptions.args '/Ob2', '/Oi', '/GF' + } + else if (cfg instanceof GccToolchainConfig) { + cfg.compilerOptions.pchConfig = new GccToolchainConfig.PrecompilerHeaderOptions( + enabled: true, + pchSourceSet: 'director_pch' + ); + + cfg.compilerOptions.languageStandard = 'c++0x' + cfg.defines([ + '_strdup': 'strdup', + '_stricmp': 'strcasecmp', + '_strnicmp': 'strncasecmp', + '_vsnprintf': 'vsnprintf', + '_snprintf': 'snprintf', + ]); + + cfg.compilerOptions.args '-Qoption,cpp,--treat_func_as_string_literal_cpp', '-fno-exceptions' + } + + ToolchainConfigUtils.apply(project, cfg, b); +} + +model { + buildTypes { + release + } + + platforms { + x86 { + architecture "x86" + } + } + + toolChains { + visualCpp(VisualCpp) { + } + icc(Icc) { + } + } + + components { + director(NativeLibrarySpec) { + targetPlatform 'x86' + baseName 'director' + + sources { + director_main(CppSourceSet) { + source { + srcDir "src" + include "**/*.cpp" + exclude "precompiled.cpp" + } + } + + director_common(CppSourceSet) { + source { + srcDirs "../../common", "../common" + + // common + include "BaseSystemModule.cpp" + include "ObjectDictionary.cpp" + include "ObjectList.cpp" + include "TokenLine.cpp" + + // HLTV common + include "BitBuffer.cpp" + include "byteorder.cpp" + include "common.cpp" + include "DirectorCmd.cpp" + include "mathlib.cpp" + include "random.cpp" + } + } + + director_engine(CppSourceSet) { + source { + srcDir "../../engine" + include "mem.cpp" + } + } + + director_pch(CppSourceSet) { + source { + srcDir "src" + include "precompiled.cpp" + } + } + } + + binaries.all { + NativeBinarySpec b -> project.setupToolchain(b) + } + } + } +} + +task buildFixes { + dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} + +task buildRelease { + dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} + +// prevent static lib building +binaries.withType(StaticLibraryBinarySpec) { binary -> + buildable = false +} diff --git a/rehlds/HLTV/Director/msvc/Director.sln b/rehlds/HLTV/Director/msvc/Director.sln new file mode 100644 index 0000000..3cc33f7 --- /dev/null +++ b/rehlds/HLTV/Director/msvc/Director.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Director", "Director.vcxproj", "{04D0594C-57F5-4277-AF1B-EAE90AED0C3C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {04D0594C-57F5-4277-AF1B-EAE90AED0C3C}.Debug|Win32.ActiveCfg = Debug|Win32 + {04D0594C-57F5-4277-AF1B-EAE90AED0C3C}.Debug|Win32.Build.0 = Debug|Win32 + {04D0594C-57F5-4277-AF1B-EAE90AED0C3C}.Release|Win32.ActiveCfg = Release|Win32 + {04D0594C-57F5-4277-AF1B-EAE90AED0C3C}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/rehlds/HLTV/Director/msvc/Director.vcxproj b/rehlds/HLTV/Director/msvc/Director.vcxproj new file mode 100644 index 0000000..965c934 --- /dev/null +++ b/rehlds/HLTV/Director/msvc/Director.vcxproj @@ -0,0 +1,157 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {04D0594C-57F5-4277-AF1B-EAE90AED0C3C} + Win32Proj + Director + 8.1 + + + + DynamicLibrary + true + v120_xp + v140_xp + MultiByte + + + DynamicLibrary + false + v120_xp + v140_xp + true + MultiByte + + + + + + + + + + + + + + + true + + + false + + + + Use + Level3 + Disabled + HLTV;WIN32;_DEBUG;_WINDOWS;_USRDLL;DIRECTOR_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)\..\..\;$(ProjectDir)\..\src;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;%(AdditionalIncludeDirectories) + precompiled.h + MultiThreadedDebug + true + + + Windows + true + %(AdditionalDependencies) + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + echo Empty Action + + + Force build to run Pre-Build event + git.always.run + git.always.run + + + + + Level3 + Use + MaxSpeed + true + true + HLTV;WIN32;NDEBUG;_WINDOWS;_USRDLL;DIRECTOR_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)\..\..\;$(ProjectDir)\..\src;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;%(AdditionalIncludeDirectories) + precompiled.h + MultiThreaded + true + + + Windows + true + true + true + %(AdditionalDependencies) + + + echo Empty Action + + + Force build to run Pre-Build event + git.always.run + git.always.run + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + + + + + + + + + + + + + + + Create + Create + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rehlds/HLTV/Director/msvc/Director.vcxproj.filters b/rehlds/HLTV/Director/msvc/Director.vcxproj.filters new file mode 100644 index 0000000..53672cc --- /dev/null +++ b/rehlds/HLTV/Director/msvc/Director.vcxproj.filters @@ -0,0 +1,108 @@ + + + + + {e86d9738-6b9c-4a2d-ba74-454526be3b1c} + + + {b2fdbdd6-d164-4470-97e9-b454d0dc7b0f} + + + {722c9b02-95dc-410f-a5b4-955878646049} + + + {33779299-5f45-402f-a52f-888505614cbe} + + + {188c9b98-4976-4512-9313-8c3ffe3d0249} + + + + + src + + + src + + + src + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + common + + + common + + + common + + + common + + + engine + + + + + src + + + src + + + src + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + common + + + common + + + common + + + common + + + engine + + + \ No newline at end of file diff --git a/rehlds/HLTV/Director/msvc/PostBuild.bat b/rehlds/HLTV/Director/msvc/PostBuild.bat new file mode 100644 index 0000000..8583878 --- /dev/null +++ b/rehlds/HLTV/Director/msvc/PostBuild.bat @@ -0,0 +1,39 @@ +@echo OFF +:: +:: Post-build auto-deploy script +:: Create and fill PublishPath.txt file with path to deployment folder +:: I.e. PublishPath.txt should contain one line with a folder path +:: Call it so: +:: IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") +:: + +SET targetDir=%~1 +SET targetName=%~2 +SET targetExt=%~3 +SET projectDir=%~4 +SET destination= + +IF NOT EXIST "%projectDir%\PublishPath.txt" ( + ECHO No deployment path specified. Create PublishPath.txt near PostBuild.bat with paths on separate lines for auto deployment. + exit /B 0 +) + +FOR /f "tokens=* delims= usebackq" %%a IN ("%projectDir%\PublishPath.txt") DO ( + ECHO Deploying to: %%a + IF NOT "%%a" == "" ( + copy /Y "%targetDir%%targetName%%targetExt%" "%%a" + IF NOT ERRORLEVEL 1 ( + IF EXIST "%targetDir%%targetName%.pdb" ( + copy /Y "%targetDir%%targetName%.pdb" "%%a" + ) + ) ELSE ( + ECHO PostBuild.bat ^(27^) : warning : Can't copy '%targetName%%targetExt%' to deploy path '%%a' + ) + ) +) + +IF "%%a" == "" ( + ECHO No deployment path specified. +) + +exit /B 0 \ No newline at end of file diff --git a/rehlds/HLTV/Director/src/Director.cpp b/rehlds/HLTV/Director/src/Director.cpp new file mode 100644 index 0000000..e44fa5c --- /dev/null +++ b/rehlds/HLTV/Director/src/Director.cpp @@ -0,0 +1,771 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#ifdef DIRECTOR_MODULE +EXPOSE_SINGLE_INTERFACE(Director, IDirector, DIRECTOR_INTERFACE_VERSION); +#endif // DIRECTOR_MODULE + +bool Director::Init(IBaseSystem *system, int serial, char *name) +{ + BaseSystemModule::Init(system, serial, name); + m_System->RegisterCommand("slowmotion", this, CMD_ID_SLOWMOTION); + + m_historyLength = MAX_WORLD_HISTORY; + m_history = (worldHistory_t *)malloc(sizeof(worldHistory_t) * m_historyLength); + if (!m_history) { + m_System->Printf("ERROR!Director::Init: not enough memory for world history.\n"); + return false; + } + + m_LastExecTime = 0; + m_currentTime = 0; + m_slowMotion = 0.5f; + + for (int i = 0; i < MAX_WORLD_HISTORY; i++) { + m_gaussFilter[i] = 1.0f / exp((i * i) / 10000.0f); + } + + m_World = nullptr; + m_Active = false; + m_System->ExecuteFile("director.cfg"); + m_System->Printf("Director module initialized.\n"); + return true; +} + +float WeightedAngle(vec_t *vec1, vec_t *vec2) +{ + float a = AngleBetweenVectors(vec1, vec2); + if (a < 11.25f) { + return 1; + } + else if (a < 22.5f) { + return 0.5f; + } + else if (a < 45.0f) { + return 0.25f; + } + else if (a < 90.0f) { + return 0.125f; + } + + return 0.05f; +} + +void Director::WriteProxyStatus(BitBuffer *stream) +{ + ; +} + +void Director::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) { + return; + } + + if (m_history) { + free(m_history); + } + + if (m_World) { + m_World->RemoveListener(this); + } + + ClearDirectorCommands(); + BaseSystemModule::ShutDown(); + + m_System->Printf("Director module shutdown.\n"); +} + +void Director::RunFrame(double time) +{ + BaseSystemModule::RunFrame(time); + + if (!m_World || !m_World->IsActive()) { + return; + } + + if (m_nextCutTime && m_Active) + { + ExecuteDirectorCommands(); + if ((m_currentTime - m_nextCutTime) > 10) + { + float duration = AddBestMODCut(); + if (!duration) { + duration = AddBestGenericCut(); + } + + m_nextCutTime += duration; + + while (m_nextCutTime > m_history[m_nextCutSeqnr % m_historyLength].time) { + m_nextCutSeqnr++; + } + } + } +} + +void Director::ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) +{ + int from = module->GetSerial(); + if (m_World->GetSerial() != from) { + return; + } + + if (signal != 3) { + return; + } + + if (!m_World) { + m_System->Printf("Director::ReceiveSignal: world == NULL\n"); + return; + } + + frame_t frame; + m_World->GetUncompressedFrame(m_World->GetLastFrame()->seqnr, &frame); + AnalyseFrame(&frame); +} + +char *Director::GetModName() +{ + return "valve"; +} + +void Director::NewGame(IWorld *world, IProxy *proxy) +{ + m_World = world; + m_Proxy = proxy; + + world->RegisterListener(this); + m_WorldModel = m_World->GetWorldModel(); + + memset(m_history, 0, sizeof(*m_history) * m_historyLength); + memset(&m_frameEvent, 0, sizeof(m_frameEvent)); + + ClearDirectorCommands(); + + m_lastCut = nullptr; + m_LastExecTime = 0; + m_nextCutTime = 0; + m_currentTime = 0; + m_nextCutSeqnr = 0; + m_maxRank = 0; + + WriteSignonData(); + m_Active = true; +} + +void Director::AnalyseFrame(frame_t *frame) +{ + unsigned int i; + unsigned int num; + float ranks[MAX_CLIENTS]; + unsigned int maxclients = m_World->GetMaxClients(); + unsigned int seqnr = frame->seqnr; + worldHistory_t *now = &m_history[seqnr % m_historyLength]; + + for (i = 0; i < MAX_CLIENTS; i++) { + ranks[i] = now->players[i].rank; + } + + memset(now, 0, sizeof(*now)); + for (i = 0; i < MAX_CLIENTS; i++) { + now->players[i].rank = ranks[i]; + } + + if (frame->delta || !m_Active) { + m_System->DPrintf("Director::AnalyseFrame: frame must be uncompressed.\n"); + return; + } + + if (m_currentTime) + { + m_nextCutTime = frame->time; + m_nextCutSeqnr = seqnr; + } + + m_currentSeqnr = seqnr; + now->seqNr = seqnr; + + m_currentTime = frame->time; + now->time = frame->time; + + unsigned int count = min(maxclients, frame->entitynum); + for (num = 0; num < count; num++) + { + entity_state_t *ent = &((entity_state_t *)frame->entities)[num]; + unsigned int index = ent->number - 1; + if (index >= maxclients) { + continue; + } + + playerData_t *player = &now->players[i]; + player->active = (ent->solid != SOLID_NOT); + if (player->active) + { + player->origin[0] = ent->origin[0]; + player->origin[1] = ent->origin[1]; + player->origin[2] = ent->origin[2]; + + vec3_t angles; + AngleVectors(ent->angles, angles); + VectorCopy(angles, player->angles); + } + } + + for (i = 0; i < MAX_CLIENTS; i++) { + AnalysePlayer(i); + } + + now->event.entity1 = m_frameEvent.entity1; + now->event.entity2 = m_frameEvent.entity2; + now->event.flags = m_frameEvent.flags; + + memset(&m_frameEvent, 0, sizeof(m_frameEvent)); +} + +void Director::SmoothRank(int playerNum, float rank) +{ + const unsigned int smoothRange = 40; + m_history[(m_currentSeqnr + smoothRange) % m_historyLength].players[playerNum].rank = 0; + + unsigned int steps; + for (unsigned int i = 0; i < smoothRange; i++) + { + float addition = rank * m_gaussFilter[i * (MAX_WORLD_HISTORY / smoothRange)]; + + steps = (m_currentSeqnr - i) % m_historyLength; + m_history[steps].players[playerNum].rank += addition; + + steps = (i + m_currentSeqnr) % m_historyLength; + m_history[steps].players[playerNum].rank += addition; + } +} + +void Director::AnalysePlayer(int playerNum) +{ + int secondTarget = 0; + float rank = RandomFloat(0.0f, 0.01f) + 1; + float targetRank, bestTargetRank = 0; + + worldHistory_t *now = &m_history[m_currentSeqnr % m_historyLength]; + playerData_t *player = &now->players[playerNum]; + + if (player->active) + { + if (m_WorldModel->IsValid()) + { + m_WorldModel->SetPVS(player->origin); + for (int i = 0; i < MAX_CLIENTS; i++) + { + playerData_t *target = &now->players[i]; + if (!target->active || !m_WorldModel->InPVS(target->origin)) { + continue; + } + + vec3_t offset; + VectorSubtract(target->origin, player->origin, offset); + + float distance = Length(offset); + if (distance >= 1.0f) + { + targetRank = WeightedAngle(target->angles, offset) + 1 / distance; + + // inverted + VectorScale(offset, -1.0f, offset); + + targetRank = WeightedAngle(target->angles, offset) * targetRank; + rank += targetRank; + + // remember closest player + if (targetRank > bestTargetRank) + { + bestTargetRank = targetRank; + secondTarget = i + 1; + } + } + } + } + } + else + { + rank = 0; + } + + player->target = secondTarget; + player->rank = player->rank + rank; + SmoothRank(playerNum, rank); +} + +void Director::WriteCommands(BitBuffer *stream, float startTime, float endTime) +{ + DirectorCmd *cmd = (DirectorCmd *)m_Commands.FindClosestKey(startTime); + while (cmd && cmd->GetTime() <= endTime) + { + if (cmd->GetTime() > startTime) + { + if (cmd->GetType() == DRC_CMD_TIMESCALE) + { + float timescale; + cmd->GetTimeScaleData(timescale); + + stream->WriteByte(svc_timescale); + stream->WriteFloat(timescale); + } + + cmd->WriteToStream(stream); + } + + cmd = (DirectorCmd *)m_Commands.GetNext(); + } +} + +void Director::WriteSignonData() +{ + static unsigned char cmd[] = { + 1, // command length in bytes + DRC_CMD_START // tell them for start director + }; + + m_World->AddSignonData(svc_director, cmd, sizeof(cmd)); +} + +void Director::AddEvent(int entity1, int entity2, unsigned int flags) +{ + if ((flags & DRC_FLAG_PRIO_MASK) > (m_frameEvent.flags & DRC_FLAG_PRIO_MASK)) + { + m_frameEvent.flags = flags; + m_frameEvent.entity1 = entity1; + m_frameEvent.entity2 = entity2; + } +} + +float Director::AddBestGenericCut() +{ + int seqNrMod = m_nextCutSeqnr % m_historyLength; + + float sumTarget2Rank[MAX_CLIENTS]; + float bestTarget2Rank, bestRank = 0; + float targetRankSum = 0; + int newTarget, newTarget2; + int bestTarget2; + + for (int i = 0; i < MAX_CLIENTS; i++) + { + memset(sumTarget2Rank, 0, sizeof(sumTarget2Rank)); + + float tillTime = m_nextCutTime + 4; + while (tillTime > m_history[seqNrMod].time) + { + playerData_t *player = &m_history[seqNrMod].players[i]; + + targetRankSum += player->rank; + if (player->target) { + sumTarget2Rank[player->target - 1] += player->rank; + } + + if (++seqNrMod == m_historyLength) { + seqNrMod = 0; + } + } + + bestTarget2 = 0; + bestTarget2Rank = 0; + + for (int j = 0; j < MAX_CLIENTS; j++) + { + if (sumTarget2Rank[j] > bestTarget2Rank) + { + bestTarget2 = j + 1; + bestTarget2Rank = sumTarget2Rank[j]; + } + } + + if (targetRankSum > bestRank) + { + bestRank = targetRankSum; + newTarget = i + 1; + newTarget2 = bestTarget2; + } + } + + if (bestRank > m_maxRank) { + m_maxRank = bestRank; + } + + float duration = 1.0f; + if (newTarget > 0) + { + if (m_lastCut && m_lastCut->GetType() == TYPE_DIRECTOR) + { + int lastTarget1, lastTarget2,flags; + m_lastCut->GetEventData(lastTarget1, lastTarget2, flags); + + if (newTarget == lastTarget1 && newTarget2 == lastTarget2) { + return 1.0f; + } + + if (newTarget == lastTarget1) { + duration = 2.0f; + } + } + + DirectorCmd *cmd = new DirectorCmd; + cmd->SetEventData(newTarget, newTarget2, 0); + cmd->SetTime(m_nextCutTime); + + RandomizeCommand(cmd); + m_Commands.Add(cmd, m_nextCutTime); + m_lastCut = cmd; + } + + return duration; +} + +float Director::AddBestMODCut() +{ + worldHistory_t *timepoint = FindBestEvent(); + if (!timepoint) { + return 0; + } + + DirectorCmd *cmd = new DirectorCmd; + cmd->SetEventData(timepoint->event.entity1, timepoint->event.entity2, timepoint->event.flags); + cmd->SetTime(m_nextCutTime); + + RandomizeCommand(cmd); + m_Commands.Add(cmd, cmd->GetTime()); + m_lastCut = cmd; + + int lastTarget1, lastTarget2, lastFlags; + cmd->GetEventData(lastTarget1, lastTarget2, lastFlags); + + float trailTime = 2.0f; + if ((lastFlags & DRC_FLAG_SLOWMOTION) && m_slowMotion) + { + trailTime = 1.5f; + + cmd = new DirectorCmd; + cmd->SetTimeScaleData(m_slowMotion); + cmd->SetTime(timepoint->time - 0.25f); + m_Commands.Add(cmd, cmd->GetTime()); + + cmd = new DirectorCmd; + cmd->SetTimeScaleData(1.0); + cmd->SetTime(timepoint->time + 1.5f); + m_Commands.Add(cmd, cmd->GetTime()); + } + + return trailTime + timepoint->time - m_nextCutTime; +} + +int Director::GetClosestPlayer(frame_t *frame, int entityIndex) +{ + unsigned int i; + unsigned int bestPlayer = 0; + unsigned int maxclients = m_World->GetMaxClients(); + + if (!m_WorldModel->IsValid()) { + return 0; + } + + vec3_t origin; + for (i = 0; i < frame->entitynum; i++) + { + entity_state_t *ent = &((entity_state_t *)frame->entities)[i]; + if (ent->number == entityIndex) { + VectorCopy(origin, ent->origin); + break; + } + } + + // entityIndex not found + if (i == frame->entitynum) { + return 0; + } + + m_WorldModel->SetPVS(origin); + + float minDistance = 32000.0f; + unsigned int count = min(maxclients, frame->entitynum); + + for (i = 0; i < count; i++) + { + entity_state_t *ent = &((entity_state_t *)frame->entities)[i]; + if ((unsigned)(ent->number - 1) < maxclients && m_WorldModel->InPVS(ent->origin)) + { + vec3_t offset; + VectorSubtract(ent->origin, origin, offset); + + float distance = Length(offset); + if (distance >= 1 && distance < minDistance) + { + minDistance = distance; + bestPlayer = ent->number; + } + } + } + + return bestPlayer; +} + +void Director::ClearDirectorCommands() +{ + DirectorCmd *cmd = (DirectorCmd *)m_Commands.GetFirst(); + while (cmd) + { + delete cmd; + cmd = (DirectorCmd *)m_Commands.GetNext(); + } + + m_Commands.Clear(); +} + +void Director::RandomizeCommand(DirectorCmd *cmd) +{ + if ((cmd->GetType() & DRC_FLAG_NO_RANDOM) || cmd->GetType() != DRC_CMD_EVENT) { + return; + } + + int target1, target2, flags; + cmd->GetEventData(target1, target2, flags); + if ((flags & DRC_FLAG_SLOWMOTION) && RandomFloat(0, 1) > 0.25f) + { + flags &= ~DRC_FLAG_SLOWMOTION; + } + // check DRC_CMD_SOUND, DRC_CMD_STATUS, DRC_CMD_BANNER + else if ((flags & DRC_FLAG_PRIO_MASK) > DRC_CMD_MESSAGE + && (flags & DRC_FLAG_PRIO_MASK) < DRC_CMD_STUFFTEXT && RandomFloat(0, 1) < 0.15f) + { + flags |= DRC_FLAG_SLOWMOTION; + } + + // toggle flag DRC_FLAG_DRAMATIC + if (RandomFloat(0, 1) < 0.33f) { + flags ^= DRC_FLAG_DRAMATIC; + } + + if (target1 && target2 && !(flags & DRC_FLAG_SLOWMOTION) && RandomFloat(0, 1) < 0.33f) + { + int swap = target1; + target1 = target2; + target2 = swap; + } + + worldHistory_t *now = &m_history[m_nextCutSeqnr % m_historyLength]; + + vec3_t v1, v2; + VectorSubtract(now->players[target2 % MAX_CLIENTS].origin, now->players[target1 % MAX_CLIENTS].origin, v1); + + v1[2] = 0; + VectorAngles(v1, v1); + + VectorCopy(now->players[target1 % MAX_CLIENTS].angles, v2); + if (AngleLeftOfOther(v1, v2)) + flags &= ~DRC_FLAG_SIDE; + else + flags |= DRC_FLAG_SIDE; + + if (target1 == target2) { + target2 = 0; + } + + cmd->SetEventData(target1, target2, flags); +} + +void Director::ExecuteCommand(int commandID, char *commandLine) +{ + if (commandID == CMD_ID_SLOWMOTION) { + CMD_SlowMotion(commandLine); + return; + } + + m_System->Printf("ERROR! Director::ExecuteCommand: unknown command ID %i.\n", commandID); +} + +char *Director::GetStatusLine() +{ + return "Default Director"; +} + +char *Director::GetType() +{ + return DIRECTOR_INTERFACE_VERSION; +} + +void Director::ExecuteDirectorCommands() +{ + unsigned char bufferdata[4096]; + BitBuffer buffer(bufferdata, sizeof(bufferdata)); + buffer.Clear(); + + float newTime = (float)m_Proxy->GetSpectatorTime(); + DirectorCmd *cmd = (DirectorCmd *)m_Commands.FindClosestKey(m_LastExecTime); + if (!cmd) { + return; + } + + while (cmd && cmd->GetTime() <= newTime) + { + if (cmd->GetTime() > m_LastExecTime) + { + if (cmd->GetType() == DRC_CMD_TIMESCALE) + { + float timescale; + cmd->GetTimeScaleData(timescale); + m_Proxy->SetClientTimeScale(timescale); + + if (timescale < 1.0) + { + vec3_t pos = { 0.02f, 0.85f, 0.f }; + + DirectorCmd slowmo; + slowmo.SetMessageData(0, COM_PackRGBA(255, 160, 0, 255), pos, 0.3f, 0.1f, 2, 0, "Slow Motion"); + slowmo.WriteToStream(&buffer); + } + } + else + { + cmd->WriteToStream(&buffer); + } + } + + cmd = (DirectorCmd *)m_Commands.GetNext(); + } + + if (buffer.IsOverflowed()) + { + m_System->Printf("Director::ExecuteDirectorCommands: command overflow.\n"); + } + else + { + m_Proxy->Broadcast(buffer.GetData(), buffer.CurrentSize(), GROUP_CLIENT_ALL, true); + } + + m_LastExecTime = newTime; +} + +void Director::CMD_SlowMotion(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) { + m_System->Printf("Syntax: slowmotion \n"); + m_System->Printf("Currently slowmotion factor is %.2f\n", m_slowMotion); + return; + } + + float val = (float)atof(params.GetToken(1)); + m_slowMotion = clamp(val, 0.05f, 4.0f); +} + +Director::worldHistory_t *Director::FindBestEvent() +{ + int i; + int nseqMod = m_nextCutSeqnr % m_historyLength; + int bestEvent[] = { 0, 0, 0, 0 }; + int bestEventPrio[] = { 0, 0, 0, 0 }; + + for (i = 0; i < 4; i++) + { + bestEventPrio[i] = 0; + bestEvent[i] = 0; + + float tillTime = (i + 1) * 2 + m_nextCutTime; + while (tillTime > m_history[nseqMod].time) + { + if ((m_history[nseqMod].event.flags & DRC_FLAG_PRIO_MASK) > (unsigned int)bestEventPrio[i]) { + bestEventPrio[i] = (m_history[nseqMod].event.flags & DRC_FLAG_PRIO_MASK); + bestEvent[i] = nseqMod; + } + + if (++nseqMod == m_historyLength) { + nseqMod = 0; + } + } + } + + if (bestEventPrio[0] || bestEventPrio[1] || bestEventPrio[2]) + { + if (bestEventPrio[1] >= bestEventPrio[0] + && bestEventPrio[1] >= bestEventPrio[2] + && bestEventPrio[1] >= bestEventPrio[3]) { + return &m_history[ bestEvent[1] ]; + } + + else if (bestEventPrio[0] > bestEventPrio[1] + && bestEventPrio[0] > bestEventPrio[2]) { + return &m_history[ bestEvent[0] ]; + } + + else if (bestEventPrio[2] > bestEventPrio[3]) { + return &m_history[ bestEvent[2] ]; + } + + if (bestEventPrio[0]) { + return &m_history[ bestEvent[0] ]; + } + } + + return nullptr; +} + +int Director::AddCommand(DirectorCmd *cmd) +{ + if (cmd->GetType() > DRC_CMD_LAST) { + return 0; + } + + if (cmd->GetType() == DRC_CMD_EVENT) + { + int target1, target2, flags; + cmd->GetEventData(target1, target2, flags); + AddEvent(target1, target2, flags); + return 0; + } + + DirectorCmd *newcmd = new DirectorCmd; + newcmd->Copy(cmd); + + m_Commands.Add(newcmd, newcmd->GetTime()); + return 1; +} + +IObjectContainer *Director::GetCommands() +{ + return &m_Commands; +} + +bool Director::RemoveCommand(int index) +{ + return false; +} + +DirectorCmd *Director::GetLastCommand() +{ + return nullptr; +} diff --git a/rehlds/HLTV/Director/src/Director.h b/rehlds/HLTV/Director/src/Director.h new file mode 100644 index 0000000..63def9e --- /dev/null +++ b/rehlds/HLTV/Director/src/Director.h @@ -0,0 +1,126 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include +#include +#include + +#include "BaseSystemModule.h" +#include "ObjectDictionary.h" + +class Director: public IDirector, public BaseSystemModule { +public: + Director() {} + virtual ~Director() {} + + virtual bool Init(IBaseSystem *system, int serial, char *name); + virtual void RunFrame(double time); + virtual void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data); + virtual void ExecuteCommand(int commandID, char *commandLine); + virtual char *GetStatusLine(); + virtual char *GetType(); + virtual void ShutDown(); + + virtual void NewGame(IWorld *world, IProxy *proxy); + virtual int AddCommand(DirectorCmd *cmd); + virtual void WriteCommands(BitBuffer *stream, float startTime, float endTime); + virtual char *GetModName(); + virtual bool RemoveCommand(int index); + virtual DirectorCmd *GetLastCommand(); + virtual IObjectContainer *GetCommands(); + + typedef struct playerData_s { + vec3_t origin; + vec3_t angles; + int active; + int target; + float rank; + } playerData_t; + + typedef struct worldHistory_s + { + float time; + unsigned int seqNr; + + typedef struct worldEvent_s { + int entity1; + int entity2; + unsigned int flags; + } worldEvent_t; + + worldEvent_t event; + playerData_t players[MAX_CLIENTS]; + + } worldHistory_t; + + worldHistory_t *FindBestEvent(); + + void ExecuteDirectorCommands(); + void RandomizeCommand(DirectorCmd *cmd); + int GetClosestPlayer(frame_t *frame, int entityIndex); + void AddEvent(int entity1, int entity2, unsigned int flags); + void SmoothRank(int playerNum, float rank); + void AnalysePlayer(int playerNum); + void AnalyseFrame(frame_t *frame); + void ClearDirectorCommands(); + float AddBestMODCut(); + float AddBestGenericCut(); + void WriteSignonData(); + void WriteProxyStatus(BitBuffer *stream); + +private: + enum LocalCommandIDs { CMD_ID_SLOWMOTION = 1 }; + void CMD_SlowMotion(char *cmdLine); + +protected: + ObjectDictionary m_Commands; + + worldHistory_t *m_history; + float m_maxRank; + + enum { MAX_WORLD_HISTORY = 200 }; + float m_gaussFilter[MAX_WORLD_HISTORY]; + + int m_historyLength; + unsigned int m_nextCutSeqnr; + unsigned int m_currentSeqnr; + + float m_nextCutTime; + float m_currentTime; + float m_LastExecTime; + float m_slowMotion; + + worldHistory_t::worldEvent_t m_frameEvent; + DirectorCmd *m_lastCut; + IBSPModel *m_WorldModel; + bool m_Active; + IWorld *m_World; + IProxy *m_Proxy; +}; diff --git a/rehlds/HLTV/Director/src/DirectorNull.h b/rehlds/HLTV/Director/src/DirectorNull.h new file mode 100644 index 0000000..9412494 --- /dev/null +++ b/rehlds/HLTV/Director/src/DirectorNull.h @@ -0,0 +1,57 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include +#include +#include "BaseSystemModule.h" + +class IObjectContainer; +class DirectorNull: public IDirector, public BaseSystemModule { +public: + void NewGame(IWorld *world, IProxy *proxy) + { + static unsigned char cmd[] = { + 1, // command length in bytes + DRC_CMD_START // tell them for start director + }; + + world->AddSignonData(svc_director, cmd, sizeof(cmd)); + } + + int AddCommand(DirectorCmd *cmd) { return 0; } + void WriteCommands(BitBuffer *stream, float startTime, float endTime) {} + char *GetModName() { return "NULL"; } + bool RemoveCommand(int index) { return false; } + + DirectorCmd *GetLastCommand() { return nullptr; } + IObjectContainer *GetCommands() { return nullptr; } + + virtual ~DirectorNull() {} +}; diff --git a/rehlds/HLTV/Director/src/precompiled.cpp b/rehlds/HLTV/Director/src/precompiled.cpp new file mode 100644 index 0000000..5f656a4 --- /dev/null +++ b/rehlds/HLTV/Director/src/precompiled.cpp @@ -0,0 +1 @@ +#include "precompiled.h" diff --git a/rehlds/HLTV/Director/src/precompiled.h b/rehlds/HLTV/Director/src/precompiled.h new file mode 100644 index 0000000..d191f95 --- /dev/null +++ b/rehlds/HLTV/Director/src/precompiled.h @@ -0,0 +1,24 @@ +#pragma once + +#include "osconfig.h" +#include "archtypes.h" +#include "mathlib.h" +#include "FileSystem.h" + +#include "TokenLine.h" +#include "interface.h" + +#include "hltv.h" +#include "mem.h" +#include "common.h" + +#include "common/random.h" +#include "common/byteorder.h" +#include "common/BitBuffer.h" +#include "common/DirectorCmd.h" +#include "common/mathlib_internal.h" +#include "common/net_internal.h" +#include "common/common_hltv.h" + +#include "Director.h" +#include "DirectorNull.h" diff --git a/rehlds/HLTV/Director/src/public_amalgamation.cpp b/rehlds/HLTV/Director/src/public_amalgamation.cpp new file mode 100644 index 0000000..1fc308c --- /dev/null +++ b/rehlds/HLTV/Director/src/public_amalgamation.cpp @@ -0,0 +1,3 @@ +#include "precompiled.h" + +#include "interface.cpp" diff --git a/rehlds/HLTV/Proxy/build.gradle b/rehlds/HLTV/Proxy/build.gradle new file mode 100644 index 0000000..53e85cf --- /dev/null +++ b/rehlds/HLTV/Proxy/build.gradle @@ -0,0 +1,165 @@ +import org.doomedsociety.gradlecpp.cfg.ToolchainConfigUtils +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.toolchain.icc.Icc +import org.doomedsociety.gradlecpp.toolchain.icc.IccCompilerPlugin +import org.doomedsociety.gradlecpp.gcc.GccToolchainConfig +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeLibrarySpec +import org.gradle.nativeplatform.toolchain.VisualCpp + +apply plugin: 'cpp' +apply plugin: IccCompilerPlugin +apply plugin: GccCompilerPlugin + +project.ext.dep_bzip2 = project(':dep/bzip2') + +void setupToolchain(NativeBinarySpec b) { + def cfg = rootProject.createToolchainConfig(b); + cfg.projectInclude(project, '/..', '/../..', '/src', '/../Director/src', '/../../common', '/../../engine', '/../../public', '/../../public/rehlds', '/../../pm_shared'); + cfg.projectInclude(dep_bzip2, '/include') + + cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'CORE_MODULE' + + if (cfg instanceof MsvcToolchainConfig) { + cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig( + enabled: true, + pchHeader: 'precompiled.h', + pchSourceSet: 'proxy_pch' + ); + + cfg.singleDefines('_CRT_SECURE_NO_WARNINGS') + cfg.compilerOptions.args '/Ob2', '/Oi', '/GF' + cfg.projectLibpath(project, '/../../lib') + cfg.extraLibs "steam_api.lib", "psapi.lib", "ws2_32.lib" + } + else if (cfg instanceof GccToolchainConfig) { + cfg.compilerOptions.pchConfig = new GccToolchainConfig.PrecompilerHeaderOptions( + enabled: true, + pchSourceSet: 'proxy_pch' + ); + + cfg.compilerOptions.languageStandard = 'c++0x' + cfg.defines([ + '_strdup': 'strdup', + '_stricmp': 'strcasecmp', + '_strnicmp': 'strncasecmp', + '_vsnprintf': 'vsnprintf', + '_snprintf': 'snprintf', + ]); + + cfg.compilerOptions.args '-Qoption,cpp,--treat_func_as_string_literal_cpp', '-fno-exceptions' + cfg.projectLibpath(project, '/../../lib/linux32') + cfg.extraLibs "steam_api" + } + + ToolchainConfigUtils.apply(project, cfg, b); +} + +model { + buildTypes { + release + } + + platforms { + x86 { + architecture "x86" + } + } + + toolChains { + visualCpp(VisualCpp) { + } + icc(Icc) { + } + } + + components { + proxy(NativeLibrarySpec) { + targetPlatform 'x86' + baseName 'proxy' + + sources { + proxy_main(CppSourceSet) { + source { + srcDir "src" + include "**/*.cpp" + exclude "precompiled.cpp" + } + + lib project: ':dep/bzip2', library: 'bzip2', linkage: 'static' + } + + proxy_common(CppSourceSet) { + source { + srcDirs "../../common", "../common" + + // common + include "BaseSystemModule.cpp" + include "ObjectDictionary.cpp" + include "ObjectList.cpp" + include "TokenLine.cpp" + + // HLTV common + include "BaseClient.cpp" + include "BitBuffer.cpp" + include "byteorder.cpp" + include "common.cpp" + include "DemoFile.cpp" + include "DirectorCmd.cpp" + include "InfoString.cpp" + include "mathlib.cpp" + include "md5.cpp" + include "munge.cpp" + include "NetAddress.cpp" + include "NetChannel.cpp" + include "random.cpp" + } + } + + proxy_engine(CppSourceSet) { + source { + srcDir "../../engine" + include "mem.cpp" + } + } + + proxy_director(CppSourceSet) { + source { + srcDir "../Director/src" + include "Director.cpp" + } + } + + proxy_pch(CppSourceSet) { + source { + srcDir "src" + include "precompiled.cpp" + + lib project: ':dep/bzip2', library: 'bzip2', linkage: 'static' + } + } + } + + binaries.all { + NativeBinarySpec b -> project.setupToolchain(b) + } + } + } +} + +task buildFixes { + dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} + +task buildRelease { + dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} + +// prevent static lib building +binaries.withType(StaticLibraryBinarySpec) { binary -> + buildable = false +} diff --git a/rehlds/HLTV/Proxy/msvc/PostBuild.bat b/rehlds/HLTV/Proxy/msvc/PostBuild.bat new file mode 100644 index 0000000..8583878 --- /dev/null +++ b/rehlds/HLTV/Proxy/msvc/PostBuild.bat @@ -0,0 +1,39 @@ +@echo OFF +:: +:: Post-build auto-deploy script +:: Create and fill PublishPath.txt file with path to deployment folder +:: I.e. PublishPath.txt should contain one line with a folder path +:: Call it so: +:: IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") +:: + +SET targetDir=%~1 +SET targetName=%~2 +SET targetExt=%~3 +SET projectDir=%~4 +SET destination= + +IF NOT EXIST "%projectDir%\PublishPath.txt" ( + ECHO No deployment path specified. Create PublishPath.txt near PostBuild.bat with paths on separate lines for auto deployment. + exit /B 0 +) + +FOR /f "tokens=* delims= usebackq" %%a IN ("%projectDir%\PublishPath.txt") DO ( + ECHO Deploying to: %%a + IF NOT "%%a" == "" ( + copy /Y "%targetDir%%targetName%%targetExt%" "%%a" + IF NOT ERRORLEVEL 1 ( + IF EXIST "%targetDir%%targetName%.pdb" ( + copy /Y "%targetDir%%targetName%.pdb" "%%a" + ) + ) ELSE ( + ECHO PostBuild.bat ^(27^) : warning : Can't copy '%targetName%%targetExt%' to deploy path '%%a' + ) + ) +) + +IF "%%a" == "" ( + ECHO No deployment path specified. +) + +exit /B 0 \ No newline at end of file diff --git a/rehlds/HLTV/Proxy/msvc/Proxy.sln b/rehlds/HLTV/Proxy/msvc/Proxy.sln new file mode 100644 index 0000000..099d4da --- /dev/null +++ b/rehlds/HLTV/Proxy/msvc/Proxy.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Proxy", "Proxy.vcxproj", "{ADDFF069-D39D-4A1B-87C9-85A62B980547}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzip2", "..\..\..\..\dep\bzip2\msvc\bzip2.vcxproj", "{792DF067-9904-4579-99B9-46C17277ADE3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ADDFF069-D39D-4A1B-87C9-85A62B980547}.Debug|Win32.ActiveCfg = Debug|Win32 + {ADDFF069-D39D-4A1B-87C9-85A62B980547}.Debug|Win32.Build.0 = Debug|Win32 + {ADDFF069-D39D-4A1B-87C9-85A62B980547}.Release|Win32.ActiveCfg = Release|Win32 + {ADDFF069-D39D-4A1B-87C9-85A62B980547}.Release|Win32.Build.0 = Release|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug|Win32.ActiveCfg = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug|Win32.Build.0 = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Release|Win32.ActiveCfg = Release|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/rehlds/HLTV/Proxy/msvc/Proxy.vcxproj b/rehlds/HLTV/Proxy/msvc/Proxy.vcxproj new file mode 100644 index 0000000..625d946 --- /dev/null +++ b/rehlds/HLTV/Proxy/msvc/Proxy.vcxproj @@ -0,0 +1,377 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + + + true + true + + + Use + Use + + + + + + + Use + Use + + + + + + + + + + + + + + + + + + + Use + Use + + + + + + + Use + Use + + + + + + + Use + Use + + + + + + + Use + Use + + + + + + + Use + Use + + + + + + + Use + Use + + + + + + + Use + Use + + + + + + + Use + Use + + + + + + + + + + + + + + + + + + + Use + Use + + + + + + + Use + Use + + + + + + + + + + + + + Create + Create + + + Use + Use + + + + + + + Use + Use + + + + + + + Use + Use + + + + + + + Use + Use + + + + + + + + + + + + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + {792df067-9904-4579-99b9-46c17277ade3} + + + + {ADDFF069-D39D-4A1B-87C9-85A62B980547} + Win32Proj + Proxy + 8.1 + + + + DynamicLibrary + true + v120_xp + v140_xp + MultiByte + + + DynamicLibrary + false + v120_xp + v140_xp + true + MultiByte + + + + + + + + + + + + + + + true + proxy + + + false + proxy + + + + Use + Level3 + Disabled + HLTV;WIN32;_DEBUG;_WINDOWS;_USRDLL;PROXY_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\Director\src;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;$(ProjectDir)\..\..\..\..\dep\bzip2\include;%(AdditionalIncludeDirectories) + precompiled.h + MultiThreadedDebug + true + EnableFastChecks + false + + + Windows + true + psapi.lib;ws2_32.lib;steam_api.lib;%(AdditionalDependencies) + $(ProjectDir)../../../lib + + + Force build to run Pre-Build event + + + git.always.run + + + git.always.run + echo Empty Action + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + + + Level3 + Use + MaxSpeed + true + true + HLTV;WIN32;NDEBUG;_WINDOWS;_USRDLL;PROXY_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\Director\src;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;$(ProjectDir)\..\..\..\..\dep\bzip2\include;%(AdditionalIncludeDirectories) + precompiled.h + MultiThreaded + true + false + + + Windows + true + true + true + psapi.lib;ws2_32.lib;steam_api.lib;%(AdditionalDependencies) + $(ProjectDir)../../../lib + + + + + + + + + + + echo Empty Action + + + Force build to run Pre-Build event + + + git.always.run + + + git.always.run + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + + + + \ No newline at end of file diff --git a/rehlds/HLTV/Proxy/msvc/Proxy.vcxproj.filters b/rehlds/HLTV/Proxy/msvc/Proxy.vcxproj.filters new file mode 100644 index 0000000..d86b875 --- /dev/null +++ b/rehlds/HLTV/Proxy/msvc/Proxy.vcxproj.filters @@ -0,0 +1,195 @@ + + + + + {e272c141-8f15-473d-9ea7-8c46b9f2db19} + + + {b7066def-60e7-4352-8787-a31a8f9dec0d} + + + {feda00f0-7c09-4c63-b5a1-e4fbcdfc6b69} + + + {199d99ef-8924-48fc-8c8a-2859f8d40c82} + + + {1777708a-8593-40c0-8caa-9154180854dc} + + + {ee194364-02f4-428c-a25f-0a60a7d20263} + + + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + src\hookers + + + src\hookers + + + src + + + common + + + common + + + common + + + common + + + engine + + + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + src + + + src + + + src + + + HLTV\common + + + src + + + src + + + src + + + src + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + HLTV\common + + + src\hookers + + + common + + + common + + + common + + + common + + + engine + + + \ No newline at end of file diff --git a/rehlds/HLTV/Proxy/src/DemoClient.cpp b/rehlds/HLTV/Proxy/src/DemoClient.cpp new file mode 100644 index 0000000..b4cef3d --- /dev/null +++ b/rehlds/HLTV/Proxy/src/DemoClient.cpp @@ -0,0 +1,294 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +bool DemoClient::Init(IBaseSystem *system, int serial, char *name) +{ + BaseSystemModule::Init(system, serial, name); + + m_Proxy = nullptr; + m_LastFrameSeqNr = 0; + m_ClientDelta = 0; + m_IsActive = false; + + memset(m_BaseFileName, 0, sizeof(m_BaseFileName)); + m_DemoInfo.SetMaxSize(MAX_DEMO_INFO); + + m_State = MODULE_RUNNING; + m_System->Printf("Demo client initialized.\n"); + + return true; +} + +char *DemoClient::GetStatusLine() +{ + static char string[256]; + _snprintf(string, sizeof(string), "Recording to %s (%.1f seconds)\n", m_DemoFile.GetFileName(), m_DemoFile.GetDemoTime()); + return string; +} + +bool DemoClient::IsHearingVoices() +{ + return true; +} + +bool DemoClient::HasChatEnabled() +{ + return false; +} + +char *DemoClient::GetType() +{ + return DEMOCLIENT_INTERFACE_VERSION; +} + +int DemoClient::GetClientType() +{ + return TYPE_DEMO; +} + +void DemoClient::Reconnect() +{ + FinishDemo(); +} + +bool DemoClient::Connect(INetSocket *socket, NetAddress *adr, char *userinfo) +{ + if (IsActive()) + { + if (m_DemoFile.IsRecording()) { + m_System->Printf("Already recording to %s.\n", m_DemoFile.GetFileName()); + } else { + m_System->Printf("Already recording initialized for %s.\n", m_BaseFileName); + } + + return false; + } + + m_DemoChannel.Create(m_System); + m_DemoChannel.SetUpdateRate(40); + m_DemoChannel.SetRate(20000); + + m_LastFrameSeqNr = 0; + m_ClientDelta = 0; + + m_DemoChannel.SetKeepAlive(false); + m_DemoFile.Init(m_World, nullptr, &m_DemoChannel); + + m_IsActive = true; + m_System->Printf("Recording initialized.\n"); + + return true; +} + +void DemoClient::RunFrame(double time) +{ + BaseSystemModule::RunFrame(time); + + NetPacket *packet = m_DemoChannel.GetPacket(); + while (packet) + { + m_System->DPrintf("WARNING! Incoming data in demo game channel.Ignored.\n"); + m_DemoChannel.FreePacket(packet); + + packet = m_DemoChannel.GetPacket(); + } + + if (IsActive() && m_World->IsActive() && m_DemoChannel.IsReadyToSend()) { + SendDatagram(); + } +} + +void DemoClient::SendDatagram() +{ + if (m_Proxy->GetDelay() > 0) + { + double worldTime = m_Proxy->GetSpectatorTime(); + double proxyTime = m_Proxy->GetProxyTime(); + + frame_t *frame = m_World->GetFrameByTime(worldTime); + if (!frame) { + return; + } + + if (frame->seqnr > 1) { + WriteDatagram(proxyTime - (worldTime - frame->time), frame); + } + + return; + } + + frame_t *frame = m_World->GetLastFrame(); + if (frame) { + WriteDatagram(frame->time, frame); + } +} + +void DemoClient::WriteDatagram(double time, frame_t *frame) +{ + unsigned int deltaFrameSeqNr = m_LastFrameSeqNr; + if (deltaFrameSeqNr > 0) + { + if (deltaFrameSeqNr == frame->seqnr) + return; + + if (deltaFrameSeqNr > frame->seqnr) + m_LastFrameSeqNr = frame->seqnr - 1; + } + else + { + char mapname[MAX_PATH]; + COM_FileBase(m_World->GetLevelName(), mapname); + + char fileName[MAX_PATH]; + _snprintf(fileName, sizeof(fileName), "%s-%s-%s.dem", m_BaseFileName, COM_TimeString(), mapname); + + m_DemoFile.StartRecording(fileName); + m_Proxy->WriteSignonData(TYPE_DEMO, &m_DemoChannel.m_reliableStream); + } + + m_DemoChannel.m_unreliableStream.WriteByte(svc_time); + m_DemoChannel.m_unreliableStream.WriteFloat((float)time); + + m_World->WriteFrame(frame, m_LastFrameSeqNr, &m_DemoChannel.m_reliableStream, &m_DemoChannel.m_unreliableStream, deltaFrameSeqNr, m_ClientDelta, true); + m_LastFrameSeqNr = frame->seqnr; + m_ClientDelta = (m_DemoChannel.m_outgoing_sequence & 0xFF); + + // reliable stream has overflowed + if (m_DemoChannel.m_reliableStream.IsOverflowed()) + { + m_System->Printf("WARNING! DemoClient::WriteDatagram: reliable data overflow.\n"); + Disconnect("reliable data overflow"); + return; + } + + if (m_DemoChannel.m_unreliableStream.IsOverflowed()) { + m_DemoChannel.m_unreliableStream.Clear(); + } + + m_DemoFile.WriteDemoMessage(&m_DemoChannel.m_unreliableStream, &m_DemoChannel.m_reliableStream); + m_DemoChannel.TransmitOutgoing(); + + client_data_t cdata; + memset(&cdata, 0, sizeof(cdata)); + m_DemoFile.WriteUpdateClientData(&cdata); +} + +bool DemoClient::IsActive() +{ + return m_IsActive; +} + +void DemoClient::Disconnect(const char *reason) +{ + if (!IsActive()) + return; + + if (reason) + { + m_DemoChannel.m_reliableStream.WriteByte(svc_print); + m_DemoChannel.m_reliableStream.WriteString(reason); + } + + FinishDemo(); + m_IsActive = false; +} + +void DemoClient::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) + return; + + FinishDemo(); + m_IsActive = false; + + BaseSystemModule::ShutDown(); + m_System->Printf("Demo module shutdown.\n"); +} + +void DemoClient::FinishDemo() +{ + if (!IsActive()) + return; + + m_DemoChannel.m_reliableStream.WriteByte(svc_print); + m_DemoChannel.m_reliableStream.WriteString("HLTV Demo finished.\n"); + + m_DemoFile.WriteDemoMessage(&m_DemoChannel.m_unreliableStream, &m_DemoChannel.m_reliableStream); + m_DemoFile.CloseFile(); + m_DemoChannel.Clear(); + + m_LastFrameSeqNr = 0; + m_ClientDelta = 0; +} + +NetAddress *DemoClient::GetAddress() +{ + static NetAddress fakeaddress; + fakeaddress.Clear(); + return &fakeaddress; +} + +void DemoClient::Send(unsigned char *data, int length, bool isReliable) +{ + if (isReliable) + m_DemoChannel.m_reliableStream.WriteBuf(data, length); + else + m_DemoChannel.m_unreliableStream.WriteBuf(data, length); +} + +void DemoClient::SetProxy(IProxy *proxy) +{ + m_Proxy = proxy; +} + +InfoString *DemoClient::GetUserInfo() +{ + return &m_DemoInfo; +} + +char *DemoClient::GetClientName() +{ + return m_Name; +} + +void DemoClient::SetWorld(IWorld *world) +{ + m_World = world; +} + +void DemoClient::SetFileName(char *fileName) +{ + strcopy(m_BaseFileName, fileName); +} + +DemoFile *DemoClient::GetDemoFile() +{ + return &m_DemoFile; +} diff --git a/rehlds/HLTV/Proxy/src/DemoClient.h b/rehlds/HLTV/Proxy/src/DemoClient.h new file mode 100644 index 0000000..94cfe26 --- /dev/null +++ b/rehlds/HLTV/Proxy/src/DemoClient.h @@ -0,0 +1,78 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "common/InfoString.h" + +class DemoClient: public IClient, public BaseSystemModule { +public: + DemoClient() {} + virtual ~DemoClient() {} + + bool Init(IBaseSystem *system, int serial, char *name); + void RunFrame(double time); + char *GetStatusLine(); + char *GetType(); + void ShutDown(); + bool Connect(INetSocket *socket = nullptr, NetAddress *adr = nullptr, char *userinfo = ""); + void Disconnect(const char *reason); + void Reconnect(); + void SetWorld(IWorld *world); + bool IsHearingVoices(); + bool HasChatEnabled(); + NetAddress *GetAddress(); + int GetClientType(); + char *GetClientName(); + InfoString *GetUserInfo(); + bool IsActive(); + void Send(unsigned char *data, int length, bool isReliable); + + void SetProxy(IProxy *proxy); + void SetFileName(char *fileName); + DemoFile *GetDemoFile(); + void FinishDemo(); + void SendDatagram(); + void WriteDatagram(double time, frame_t *frame); + +protected: + IProxy *m_Proxy; + IWorld *m_World; + bool m_IsActive; + NetChannel m_DemoChannel; + + enum { MAX_DEMO_INFO = 256 }; + DemoFile m_DemoFile; + char m_BaseFileName[MAX_PATH]; + + InfoString m_DemoInfo; + unsigned int m_LastFrameSeqNr; + unsigned int m_ClientDelta; +}; + +#define DEMOCLIENT_INTERFACE_VERSION "democlient000" diff --git a/rehlds/HLTV/Proxy/src/FakeClient.cpp b/rehlds/HLTV/Proxy/src/FakeClient.cpp new file mode 100644 index 0000000..b014489 --- /dev/null +++ b/rehlds/HLTV/Proxy/src/FakeClient.cpp @@ -0,0 +1,156 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +bool FakeClient::Init(IBaseSystem *system, int serial, char *name) +{ + BaseSystemModule::Init(system, serial, name); + + _snprintf(m_Name, sizeof(m_Name), "fakeclient%i", serial); + + m_Network = dynamic_cast(m_System->GetModule(NETWORK_INTERFACE_VERSION, "core")); + if (!m_Network) + { + m_System->Errorf("FakeClient::Init: couldn't load network module.\n"); + return false; + } + + if (!(m_Socket = m_Network->CreateSocket(serial + 2048))) + { + m_System->Errorf("FakeClient::Init: Could not create port %i.\n", serial + 2048); + return false; + } + + char temp[256]; + sprintf(temp, "fakeserver%i", serial); + + m_Server = dynamic_cast(m_System->GetModule(SERVER_INTERFACE_VERSION, "core", temp)); + if (!m_Server) + { + m_System->Errorf("FakeClient::Init: couldn't load server module.\n"); + return false; + } + + m_Server->RegisterListener(this); + m_Server->SetUserInfo("hspecs", "0"); + m_Server->SetUserInfo("hslots", "0"); + m_Server->SetDelayReconnect(false); + m_Server->SetPlayerName(m_Name); + m_Server->SetAutoRetry(false); + + sprintf(temp, "fakeworld%i", serial); + + m_World = dynamic_cast(m_System->GetModule(WORLD_INTERFACE_VERSION, "core", temp)); + if (!m_World) + { + m_System->Errorf("FakeClient::Init: couldn't load world module.\n"); + return false; + } + + m_World->RegisterListener(this); + + m_State = MODULE_RUNNING; + m_System->Printf("Fake client module initialized (%i).\n", serial); + return true; +} + +void FakeClient::RunFrame(double time) +{ + BaseSystemModule::RunFrame(time); + + NetPacket *packet; + while ((packet = m_Socket->ReceivePacket())) + { + m_System->DPrintf("FakeClient: WARNING! Packet from %s with invalid sequence number.\n", packet->address.ToString()); + m_Socket->FreePacket(packet); + } +} + +void FakeClient::SetRate(int rate) +{ + m_Server->SetRate(rate); +} + +void FakeClient::Connect(NetAddress *adr) +{ + m_Server->Connect(m_World, adr, m_Socket); +} + +void FakeClient::Retry() +{ + m_Server->Retry(); +} + +void FakeClient::Say(char *text) +{ + if (!m_Server->IsConnected()) + return; + + char string[1024]; + _snprintf(string, sizeof(string), "say \"%s\"", text); + m_Server->SendStringCommand(text); +} + +void FakeClient::Disconnect() +{ + m_Server->Disconnect(); +} + +void FakeClient::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) + return; + + if (m_World) { + m_World->RemoveListener(this); + } + + BaseSystemModule::ShutDown(); + m_System->Printf("FakeClient module shutdown.\n"); +} + +void FakeClient::ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) +{ + if (module->GetSerial() != m_World->GetSerial()) + return; + + if (signal == 8 /* signal to shutdown*/) { + ShutDown(); + } +} + +char *FakeClient::GetType() +{ + return FAKECLIENT_INTERFACE_VERSION; +} + +char *FakeClient::GetStatusLine() +{ + return "I am a fake client.\n"; +} diff --git a/rehlds/HLTV/Proxy/src/FakeClient.h b/rehlds/HLTV/Proxy/src/FakeClient.h new file mode 100644 index 0000000..48f0966 --- /dev/null +++ b/rehlds/HLTV/Proxy/src/FakeClient.h @@ -0,0 +1,63 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "BaseSystemModule.h" + +class IWorld; +class IServer; +class INetwork; +class INetSocket; + +class FakeClient: public BaseSystemModule { +public: + FakeClient() {} + virtual ~FakeClient() {} + + bool Init(IBaseSystem *system, int serial, char *name); + void RunFrame(double time); + void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data); + char *GetStatusLine(); + char *GetType(); + void ShutDown(); + + void SetRate(int rate); + void Connect(NetAddress *adr); + void Retry(); + void Say(char *text); + void Disconnect(); + +protected: + INetwork *m_Network; + IWorld *m_World; + IServer *m_Server; + INetSocket *m_Socket; +}; + +#define FAKECLIENT_INTERFACE_VERSION "fakeclient000" diff --git a/rehlds/HLTV/Proxy/src/Master.cpp b/rehlds/HLTV/Proxy/src/Master.cpp new file mode 100644 index 0000000..44aea36 --- /dev/null +++ b/rehlds/HLTV/Proxy/src/Master.cpp @@ -0,0 +1,293 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +Master::GameToAppIDMapItem_t Master::m_GameToAppIDMap[] = +{ + { GAME_APPID_CSTRIKE, "cstrike" }, + { GAME_APPID_TFC, "tfc" }, + { GAME_APPID_DOD, "dod" }, + { GAME_APPID_DMC, "dmc" }, + { GAME_APPID_GEARBOX, "gearbox" }, + { GAME_APPID_RICOCHET, "ricochet" }, + { GAME_APPID_VALVE, "valve" }, + { GAME_APPID_CZERO, "czero" }, + { GAME_APPID_CZEROR, "czeror" }, + { GAME_APPID_BSHIFT, "bshift" }, + { GAME_APPID_CSTRIKE_BETA, "cstrike_beta" } +}; + +Master::Master() : + m_flMasterUpdateTime(0), + m_bSteamInitialized(false) +{ +} + +int Master::GetGameAppID(const char *gamedir) const +{ + for (auto& game : m_GameToAppIDMap) { + if (!_stricmp(game.dir, gamedir)) { + return game.appID; + } + } + + return GAME_APPID_VALVE; +} + +bool Master::Init(IBaseSystem *system, int serial, char *name) +{ + BaseSystemModule::Init(system, serial, name); + + m_MasterSocket = m_Proxy->GetSocket(); + + m_System->RegisterCommand("heartbeat", this, CMD_ID_HEARTBEAT); + m_System->RegisterCommand("nomaster", this, CMD_ID_NOMASTER); + m_System->RegisterCommand("listmaster", this, CMD_ID_LISTMASTER); + + m_State = MODULE_RUNNING; + m_NoMaster = false; + m_bMasterLoaded = false; + + INetwork *network = m_MasterSocket->GetNetwork(); + if (!network->GetLocalAddress()) { + m_System->Printf("Master module failed to initialize (no net).\n"); + return false; + } + + m_bSteamInitialized = false; + m_System->Printf("Master module initialized.\n"); + + return true; +} + +void Master::SetProxy(IProxy *proxy) +{ + m_Proxy = proxy; +} + +void Master::RunFrame(double time) +{ + BaseSystemModule::RunFrame(time); + + static double s_flLastRunCallbacks = 0.0f; + if ((time - s_flLastRunCallbacks) > 0.1) + { + SteamGameServer_RunCallbacks(); + s_flLastRunCallbacks = time; + } + + if (m_NoMaster) + return; + + if (m_Proxy->IsActive()) + { + if (!m_bSteamInitialized) + { + IWorld *world = m_Proxy->GetWorld(); + if (world) + { + int nAppID = GetGameAppID(world->GetGameDir()); + if (nAppID > 0) + { + FILE *f = fopen("steam_appid.txt", "w+"); + if (f) + { + fprintf(f, "%d\n", nAppID); + fclose(f); + } + } + + INetwork *network = m_MasterSocket->GetNetwork(); + NetAddress *netAdr = network->GetLocalAddress(); + + if (SteamGameServer_Init(ntohl(*(u_long *)&netAdr->m_IP[0]), 0, 0, 0xFFFFu, eServerModeNoAuthentication, MASTER_VERSION)) + { + SteamGameServer()->SetProduct("hltv"); + SteamGameServer()->SetGameDescription("hltv"); + SteamGameServer()->SetModDir(world->GetGameDir()); + SteamGameServer()->SetDedicatedServer(true); + SteamGameServer()->SetSpectatorPort(netAdr->m_Port); + SteamGameServer()->LogOnAnonymous(); + + SteamGameServer()->EnableHeartbeats(true); + } + else + { + // NOTE: Actually here call via Printf, but we will be use DPrintf to avoid useless print into console + // or at least make only print once. + m_System->DPrintf("Master module failed to initialize. (init failed)\n"); + } + + m_bSteamInitialized = SteamGameServer() ? true : false; + } + } + + if (m_bSteamInitialized) + { + IWorld *world = m_Proxy->GetWorld(); + if (m_flMasterUpdateTime < m_System->GetTime()) + { + char mapName[MAX_PATH]; + COM_FileBase(world->GetLevelName(), mapName); + + char szHostName[MAX_PATH]; + strcopy(szHostName, world->GetHostName()); + + int slots, proxies, spectators; + m_Proxy->GetStatistics(proxies, slots, spectators); + + SteamGameServer()->SetMaxPlayerCount(min(slots, 127)); // max slots + SteamGameServer()->SetServerName(szHostName); + SteamGameServer()->SetMapName(mapName); + SteamGameServer()->SetPasswordProtected(m_Proxy->IsPasswordProtected()); + SteamGameServer()->SetModDir(world->GetGameDir()); + + m_flMasterUpdateTime = m_System->GetTime() + 5.0f; + } + } + } + + if (m_bSteamInitialized) + { + uint32 ip; + uint16 port; + char szOutBuf[4096]; + + int iLen = SteamGameServer()->GetNextOutgoingPacket(szOutBuf, sizeof(szOutBuf), &ip, &port); + while (iLen > 0) + { + NetAddress netAdr; + *((uint32 *)&netAdr.m_IP[0]) = htonl(ip); + netAdr.m_Port = htons(port); + + m_MasterSocket->SendPacket(&netAdr, szOutBuf, iLen); + + iLen = SteamGameServer()->GetNextOutgoingPacket(szOutBuf, sizeof(szOutBuf), &ip, &port); + } + } +} + +void Master::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) { + return; + } + + if (SteamGameServer()) { + SteamGameServer()->LogOff(); + } + + BaseSystemModule::ShutDown(); + SteamGameServer_Shutdown(); + m_System->Printf("Master module shutdown.\n"); +} + +void Master::CMD_Heartbeat(char *cmdLine) +{ + if (m_State == MODULE_DISCONNECTED) { + return; + } + + if (SteamGameServer()) { + SteamGameServer()->ForceHeartbeat(); + } +} + +void Master::CMD_NoMaster(char *cmdLine) +{ + if (m_State == MODULE_DISCONNECTED || !SteamGameServer()) { + return; + } + + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: nomaster <0|1>\n"); + m_System->Printf("Master server notification is %s.\n", m_NoMaster ? "disabled" : "enabled"); + return; + } + + bool bOldMasterState = m_NoMaster; + m_NoMaster = atoi(params.GetToken(1)) ? true : false; + + if (bOldMasterState != m_NoMaster) { + SteamGameServer()->EnableHeartbeats(m_NoMaster); + } +} + +void Master::CMD_ListMaster(char *pchCmdLine) +{ + if (m_State == MODULE_DISCONNECTED) { + return; + } + + m_System->Printf("No longer used\n"); +} + +void Master::ExecuteCommand(int commandID, char *commandLine) +{ + switch (commandID) + { + case CMD_ID_HEARTBEAT: + CMD_Heartbeat(commandLine); + break; + case CMD_ID_NOMASTER: + CMD_NoMaster(commandLine); + break; + case CMD_ID_LISTMASTER: + CMD_ListMaster(commandLine); + break; + default: + m_System->Printf("ERROR! Master::ExecuteCommand: unknown command ID %i.\n", commandID); + break; + } +} + +char *Master::GetType() +{ + return MASTER_INTERFACE_VERSION; +} + +void Master::SendShutdown() +{ + if (m_State == MODULE_DISCONNECTED) { + return; + } + + if (SteamGameServer()) { + SteamGameServer()->EnableHeartbeats(false); + } +} + +char *Master::GetStatusLine() +{ + static char string[256]; + _snprintf(string, sizeof(string), "Master servers: 0\n"); + return string; +} diff --git a/rehlds/HLTV/Proxy/src/Master.h b/rehlds/HLTV/Proxy/src/Master.h new file mode 100644 index 0000000..a3115ae --- /dev/null +++ b/rehlds/HLTV/Proxy/src/Master.h @@ -0,0 +1,115 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "BaseSystemModule.h" +#include "TokenLine.h" + +#define MASTER_VERSION "1.1.2.6" + +enum GameType_e +{ + GT_CSTRIKE, + GT_TFC, + GT_DOD, + GT_DMC, + GT_GEARBOX, + GT_RICOCHET, + GT_VALVE, + GT_CZERO, + GT_CZEROR, + GT_BSHIFT, + GT_CSTRIKE_BETA, +}; + +class Proxy; +class INetSocket; + +class Master: public BaseSystemModule { +public: + Master(); + virtual ~Master() {} + + bool Init(IBaseSystem *system, int serial, char *name); + void ExecuteCommand(int commandID, char *commandLine); + void RunFrame(double time); + char *GetStatusLine(); + char *GetType(); + void ShutDown(); + + void InitializeSteam(); + void SendShutdown(); + void SetProxy(IProxy *proxy); + +private: + enum LocalCommandIDs { + CMD_ID_HEARTBEAT = 1, + CMD_ID_NOMASTER, + CMD_ID_LISTMASTER, + }; + + void CMD_Heartbeat(char *cmdLine); + void CMD_NoMaster(char *cmdLine); + void CMD_ListMaster(char *cmdLine); + + enum { + GAME_APPID_CSTRIKE = 10, + GAME_APPID_TFC = 20, + GAME_APPID_DOD = 30, + GAME_APPID_DMC = 40, + GAME_APPID_GEARBOX = 50, + GAME_APPID_RICOCHET = 60, + GAME_APPID_VALVE = 70, + GAME_APPID_CZERO = 80, + GAME_APPID_CZEROR = 100, + GAME_APPID_BSHIFT = 130, + GAME_APPID_CSTRIKE_BETA = 150, + }; + + typedef struct GameToAppIDMapItem_s + { + size_t appID; + const char *dir; + } GameToAppIDMapItem_t; + + static GameToAppIDMapItem_t m_GameToAppIDMap[]; + int GetGameAppID(const char *gamedir) const; + +protected: + friend class Proxy; + + bool m_NoMaster; + bool m_bMasterLoaded; + INetSocket *m_MasterSocket; + IProxy *m_Proxy; + double m_flMasterUpdateTime; + bool m_bSteamInitialized; +}; + +#define MASTER_INTERFACE_VERSION "master000" diff --git a/rehlds/HLTV/Proxy/src/Proxy.cpp b/rehlds/HLTV/Proxy/src/Proxy.cpp new file mode 100644 index 0000000..617a104 --- /dev/null +++ b/rehlds/HLTV/Proxy/src/Proxy.cpp @@ -0,0 +1,2770 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +Proxy::LocalCommandID_s Proxy::m_LocalCmdReg[] = { + { "rcon", CMD_ID_RCON, &Proxy::CMD_Rcon }, + { "rconpassword", CMD_ID_RCONPASSWORD, &Proxy::CMD_RconPassword }, + { "rconaddress", CMD_ID_RCONADDRESS, &Proxy::CMD_RconAddress }, + { "say", CMD_ID_SAY, &Proxy::CMD_Say }, + { "msg", CMD_ID_MSG, &Proxy::CMD_Msg }, + { "clients", CMD_ID_CLIENTS, &Proxy::CMD_Clients }, + { "kick", CMD_ID_KICK, &Proxy::CMD_Kick }, + { "chatmode", CMD_ID_CHATMODE, &Proxy::CMD_ChatMode }, + { "publicgame", CMD_ID_PUBLICGAME, &Proxy::CMD_PublicGame }, + { "offlinetext", CMD_ID_OFFLINETEXT, &Proxy::CMD_OffLineText }, + { "adminpassword", CMD_ID_ADMINPASSWORD, &Proxy::CMD_AdminPassword }, + { "signoncommands", CMD_ID_SIGNONCOMMANDS, &Proxy::CMD_SignOnCommands }, + { "spectatorpassword", CMD_ID_SPECTATORPASSWORD, &Proxy::CMD_SpectatorPassword }, + { "dispatchmode", CMD_ID_DISPATCHMODE, &Proxy::CMD_DispatchMode }, + { "cheeringthreshold", CMD_ID_CHEERINGTHRESHOLD, &Proxy::CMD_CheeringThreshold }, +// { "informplayers", CMD_ID_INFORMPLAYERS, nullptr }, + { "ping", CMD_ID_PING, &Proxy::CMD_Ping }, + { "proxypassword", CMD_ID_PROXYPASSWORD, &Proxy::CMD_ProxyPassword }, + { "maxrate", CMD_ID_MAXRATE, &Proxy::CMD_MaxRate }, + { "loopcmd", CMD_ID_LOOPCMD, &Proxy::CMD_LoopCmd }, + { "maxclients", CMD_ID_MAXCLIENTS, &Proxy::CMD_MaxClients }, + { "disconnect", CMD_ID_DISCONNECT, &Proxy::CMD_Disconnect }, + { "localmsg", CMD_ID_LOCALMSG, &Proxy::CMD_LocalMsg }, + { "connect", CMD_ID_CONNECT, &Proxy::CMD_Connect }, + { "playdemo", CMD_ID_PLAYDEMO, &Proxy::CMD_PlayDemo }, + { "delay", CMD_ID_DELAY, &Proxy::CMD_Delay }, + { "stop", CMD_ID_STOP, &Proxy::CMD_Stop }, + { "record", CMD_ID_RECORD, &Proxy::CMD_Record }, + { "stoprecording", CMD_ID_STOPRECORDING, &Proxy::CMD_StopRecording }, + { "servercmd", CMD_ID_SERVERCMD, &Proxy::CMD_ServerCmd }, + { "clientcmd", CMD_ID_CLIENTCMD, &Proxy::CMD_ClientCmd }, + { "blockvoice", CMD_ID_BLOCKVOICE, &Proxy::CMD_BlockVoice }, + { "name", CMD_ID_NAME, &Proxy::CMD_Name }, + { "updaterate", CMD_ID_UPDATERATE, &Proxy::CMD_Updaterate }, + { "rate", CMD_ID_RATE, &Proxy::CMD_Rate }, + { "addresource", CMD_ID_ADDRESOURCE, &Proxy::CMD_AddResource }, + { "resources", CMD_ID_RESOURCES, &Proxy::CMD_Resources }, + { "bannerfile", CMD_ID_BANNERFILE, &Proxy::CMD_BannerFile }, + { "bann", CMD_ID_BANN, &Proxy::CMD_Bann }, + { "addfakeclients", CMD_ID_ADDFAKECLIENTS, &Proxy::CMD_AddFakeClients }, + { "retry", CMD_ID_RETRY, &Proxy::CMD_Retry }, + { "players", CMD_ID_PLAYERS, &Proxy::CMD_Players }, + { "autoretry", CMD_ID_AUTORETRY, &Proxy::CMD_AutoRetry }, + { "serverpassword", CMD_ID_SERVERPASSWORD, &Proxy::CMD_ServerPassword }, + { "status", CMD_ID_STATUS, &Proxy::CMD_Status }, + { "hostname", CMD_ID_HOSTNAME, &Proxy::CMD_HostName }, + { "maxqueries", CMD_ID_MAXQUERIES, &Proxy::CMD_MaxQueries }, + { "clearbanns", CMD_ID_CLEARBANNS, &Proxy::CMD_ClearBanns }, + { "maxloss", CMD_ID_MAXLOSS, &Proxy::CMD_MaxLoss }, + { "protocol", CMD_ID_PROTOCOL, &Proxy::CMD_Protocol }, + { "region", CMD_ID_REGION, &Proxy::CMD_Region }, +}; + +#ifndef HOOK_HLTV +EXPOSE_SINGLE_INTERFACE(Proxy, IProxy, PROXY_INTERFACE_VERSION); +#endif // HOOK_HLTV + +bool Proxy::Init(IBaseSystem *system, int serial, char *name) +{ + BaseSystemModule::Init(system, serial, name); + + if (!name) { + SetName(PROXY_INTERFACE_VERSION); + } + + m_MaxRate = 20000; + m_MaxUpdateRate = 20; + m_IsMaster = false; + + for (auto& cmd : m_LocalCmdReg) { + m_System->RegisterCommand(cmd.name, this, cmd.id); + } + + m_Network = (INetwork *)m_System->GetModule(NETWORK_INTERFACE_VERSION, "core"); + if (!m_Network) + { + m_System->Errorf("Proxy::Init: couldn't load network module.\n"); + return false; + } + + char *portparam = m_System->CheckParam("-port"); + int proxyport = atoi(portparam ? portparam : PROXY_DEFAULT_PORT); + + if (!(m_Socket = (INetSocket *)m_Network->CreateSocket(proxyport))) + { + m_System->Errorf("Proxy::Init: Could not create proxy port %i.\n", proxyport); + return false; + } + + m_Status.SetProxy(this); + if (!m_System->AddModule(&m_Status, "status")) + { + m_System->Errorf("Proxy::Init: add status module.\n"); + return false; + } + + m_Master.SetProxy(this); + if (!m_System->AddModule(&m_Master, "master")) + { + m_System->Errorf("Proxy::Init: add master module.\n"); + return false; + } + + m_Server = (IServer *)m_System->GetModule(SERVER_INTERFACE_VERSION, "core"); + if (!m_Server) + { + m_System->Errorf("Proxy::Init: couldn't load server module.\n"); + return false; + } + + m_Server->RegisterListener(this); + m_Server->SetProxy(this); + m_Server->SetUserInfo("hspecs", "0"); + m_Server->SetUserInfo("hslots", "0"); + m_Server->SetGameDirectory("valve"); + + m_World = (IWorld *)m_System->GetModule(WORLD_INTERFACE_VERSION, "core"); + if (!m_World) + { + m_System->Errorf("Proxy::Init: couldn't load world module.\n"); + return false; + } + + m_World->RegisterListener(this); + + if (!m_System->AddModule(&m_DemoClient, "demo")) { + m_System->Printf("Proxy::Init: Couldn't create demo client.\n"); + } + + m_DemoClient.SetProxy(this); + m_DemoClient.SetWorld(m_World); + + SetDelay(30); + SetClientTimeScale(1); + + m_Director = nullptr; + m_DispatchMode = DISPATCH_BALANCE; + m_ChatMode = CHAT_OFF; + + m_LastClockUpdateTime = 0; + m_NextStatusUpdateTime = 0; + + m_CheeringPlayers = 0; + m_BannerTGA = nullptr; + + m_PublicGame = true; + m_IsReconnectRequested = false; + m_IsFinishingBroadcast = false; + + m_LastCheeringUpdate = 0; + m_CheeringThreshold = 0.25f; + m_MaxLoss = 0.05f; + m_CurrentLoss = 0; + m_FPS = 1; + + m_MaxSeenClients = 0; + m_MaxClients = 128; + m_MaxQueries = 100; + m_Region = 255; + + const int maxRouteAblePacketSize = 1400; + m_InfoInfo.Resize(maxRouteAblePacketSize); + m_InfoRules.Resize(maxRouteAblePacketSize); + m_InfoPlayers.Resize(maxRouteAblePacketSize); + m_InfoDetails.Resize(maxRouteAblePacketSize); + + m_InfoString.Resize(2080); + m_NextInfoMessagesUpdate = 0; + + // Clear buffers + memset(&m_RconAddress, 0, sizeof(m_RconAddress)); + memset(m_RconPassword, 0, sizeof(m_RconPassword)); + memset(m_AdminPassword, 0, sizeof(m_AdminPassword)); + memset(m_ProxyPassword, 0, sizeof(m_ProxyPassword)); + memset(m_SpectatorPassword, 0, sizeof(m_SpectatorPassword)); + memset(m_LastRconCommand, 0, sizeof(m_LastRconCommand)); + memset(m_OffLineText, 0, sizeof(m_OffLineText)); + memset(m_SignonCommands, 0, sizeof(m_SignonCommands)); + memset(m_Challenges, 0, sizeof(m_Challenges)); + + m_LoopCommands.Init(); + m_BannList.Init(); + m_Resources.Init(); + + memset(&m_LocalMessage, 0, sizeof(m_LocalMessage)); + m_LocalMessage = { + 0, // effect + 255, 160, 0, 255, // r1, g1, b1, a1 + 255, 255, 255, 255, // r2, g2, b2, a2 + -1.f, -1.f, // x, y + 0.5f, 2.f, // fadein, fadeout + 5.f, 0.f, // holdtime, fxtime + "" // text + }; + + memset(&m_CommentatorMessage, 0, sizeof(m_CommentatorMessage)); + m_CommentatorMessage = { + 0, // effect + 255, 160, 0, 255, // r1, g1, b1, a1 + 255, 160, 0, 255, // r2, g2, b2, a2 + -1.f, -1.f, // x, y + 0.3f, 1.f, // fadein, fadeout + 5.f, 0.f, // holdtime, fxtime + "" // text + }; + + strcopy(m_OffLineText, "Game is delayed. Please try again later."); + + m_System->SetTitle("HLTV - offline"); + m_System->ExecuteFile("hltv.cfg"); + m_System->Printf("Proxy module initialized.\n"); + m_State = MODULE_RUNNING; + + return true; +} + +void Proxy::ExecuteCommand(int commandID, char *commandLine) +{ + for (auto& cmd : m_LocalCmdReg) + { + if (cmd.pfnCmd && cmd.id == commandID) { + (this->*cmd.pfnCmd)(commandLine); + return; + } + } + + m_System->Printf("ERROR! Proxy::ExecuteCommand: unknown command ID %i.\n", commandID); +} + +void Proxy::RunFrame(double time) +{ + float frameTime = float(time - m_SystemTime); + BaseSystemModule::RunFrame(time); + + if (m_MaxQueries > 0) + { + m_MaxFrameQueries = int(m_MaxQueries * frameTime); + if (m_MaxFrameQueries <= 0) { + m_MaxFrameQueries = 1; + } + } + else + m_MaxFrameQueries = 0; + + if (frameTime > 0) { + m_FPS = 0.99f * m_FPS + 0.01f / frameTime; + } + + if (m_SystemTime > m_NextStatusUpdateTime) { + UpdateStatusLine(); + } + + if (m_SystemTime > m_NextInfoMessagesUpdate) { + UpdateInfoMessages(); + } + + int numPackets = 0; + NetPacket *packet; + while (numPackets < 32 && (packet = m_Socket->ReceivePacket())) + { + if (packet->connectionless && !packet->data.IsOverflowed()) + { + if (ProcessConnectionlessMessage(&packet->address, &packet->data)) { + numPackets++; + } + } + else + { + m_System->DPrintf("WARNING! Packet from %s with invalid sequence number.\n", packet->address.ToString()); + } + + m_Socket->FreePacket(packet); + } + + ExecuteLoopCommands(); + + if (m_World->IsActive()) + { + if (GetDelay() > 0) + { + RunClocks(); + if (m_IsFinishingBroadcast && m_ClientWorldTime > m_World->GetTime() && !m_IsReconnectRequested) + { + if (m_Server->IsConnected()) { + m_Server->Reconnect(); + } + m_IsReconnectRequested = true; + } + } + + float lastTime = m_LastCheeringUpdate + 8; + if (lastTime < m_SystemTime) + { + m_CheeringPlayers /= 2; + m_LastCheeringUpdate = float(m_SystemTime); + } + } +} + +void Proxy::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) { + return; + } + + StopBroadcast("HLTV Shutdown."); + + m_Master.ShutDown(); + m_Status.ShutDown(); + m_DemoClient.ShutDown(); + + // Director module shutdown + if (m_Director) { + m_Director->ShutDown(); + } + + // World module shutdown + if (m_World) { + m_World->ShutDown(); + } + + // Server module shutdown + if (m_Server) { + m_Server->ShutDown(); + } + + // Network module shutdown + if (m_Network) { + m_Network->ShutDown(); + } + + m_LoopCommands.Clear(true); + m_BannList.Clear(true); + + m_InfoRules.Free(); + m_InfoPlayers.Free(); + m_InfoDetails.Free(); + m_InfoInfo.Free(); + m_InfoString.Free(); + + ClearResources(); + BaseSystemModule::ShutDown(); + m_System->Printf("Proxy module shutdown.\n"); +} + +void Proxy::ReplyPing(NetAddress *to) +{ + m_Socket->OutOfBandPrintf(to, "%c", A2A_ACK); +} + +void Proxy::CMD_Ping(char *cmdLine) +{ + NetAddress to; + TokenLine params(cmdLine); + if (!m_Network->ResolveAddress(params.GetToken(1), &to)) { + m_System->Printf("Error! HLTV Proxy::CMD_Ping: IP address not valid.\n"); + return; + } + + if (!to.m_Port) { + to.SetPort_(atoi("27015")); + } + + m_Socket->OutOfBandPrintf(&to, "ping"); +} + +void Proxy::ReplyChallenge(NetAddress *to) +{ + unsigned int challengenr = GetChallengeNumber(to); + + m_Socket->OutOfBandPrintf(to, "%c00000000 %u %i\n", S2C_CHALLENGE, challengenr, 2); + m_System->DPrintf("Received challenge from %s.\n", to->ToString()); +} + +void Proxy::ReplyInfoString(NetAddress *to) +{ + m_System->DPrintf("Info string request from %s.\n", to->ToString()); + m_Socket->SendPacket(to, m_InfoString.GetData(), m_InfoString.CurrentSize()); +} + +void Proxy::ReplyInfo(NetAddress *to, bool detailed) +{ + m_System->DPrintf("General information%srequest from %s.\n", detailed ? " (detail) " : " ", to->ToString()); + + if (m_World->IsActive()) + { + BitBuffer *buf = &(detailed ? m_InfoDetails : m_InfoInfo); + m_Socket->SendPacket(to, buf->GetData(), buf->CurrentSize()); + } +} + +void Proxy::ReplyPlayers(NetAddress *to) +{ + m_System->DPrintf("Player information request from %s.\n", to->ToString()); + + if (m_World->IsActive()) { + m_Socket->SendPacket(to, m_InfoPlayers.GetData(), m_InfoPlayers.CurrentSize()); + } +} + +void Proxy::ReplyRules(NetAddress *to) +{ + m_System->DPrintf("Rules information request from %s.\n", to->ToString()); + + if (m_World->IsActive()) { + m_Socket->SendPacket(to, m_InfoRules.GetData(), m_InfoRules.CurrentSize()); + } +} + +void Proxy::ReplyConnect(NetAddress *to, int protocol, int challenge, char *protinfo, char *userinfo) +{ + InfoString info(userinfo); + NetAddress relayProxy; + + int type = atoi(info.ValueForKey("*hltv")); + char *name = info.ValueForKey("name"); + + if (protocol != PROTOCOL_VERSION) { + RejectConnection(to, false, "This HLTV proxy is using protocol %i which is incompatible with yours (%i).\n", PROTOCOL_VERSION, protocol); + return; + } + + if (!CheckChallenge(to, challenge)) { + RejectConnection(to, false, "Challenge number invalid.\n"); + return; + } + + if (!m_World->IsActive()) { + RejectConnection(to, false, "HLTV not started. %s\n", m_OffLineText); + return; + } + + if (m_MaxClients <= 0) { + RejectConnection(to, false, "HLTV proxy disabled.\n"); + return; + } + + if (type == TYPE_CLIENT && m_DispatchMode != DISPATCH_OFF) + { + float ratio = m_Status.GetBestRelayProxy(&relayProxy); + float myRatio = m_Clients.CountElements() / m_MaxClients * 1.25f; + if (myRatio > 1) { + myRatio = 1; + } + + if (ratio < 0) + { + if (m_DispatchMode == DISPATCH_ALL) { + RejectConnection(to, false, "HLTV network is full.\n"); + return; + } + } + else if (myRatio >= ratio || m_DispatchMode == DISPATCH_ALL) + { + DispatchClient(to, &relayProxy); + return; + } + } + + if (!IsValidPassword(type, info.ValueForKey("password"))) { + RejectConnection(to, true, "Bad password"); + return; + } + + if (IsStressed() && type == TYPE_CLIENT) { + RejectConnection(to, false, "Workload limit exceeded."); + return; + } + + char *clientTypeString[] = { "Spectator", "Relay Proxy", "Director", "Commentator", "Fake Client" }; + IClient *client = (IClient *)m_Clients.GetFirst(); + while (client) + { + if (to->Equal(client->GetAddress())) { + m_System->Printf("%s reconnected (%s at %s).\n", clientTypeString[type], name, to->ToString()); + break; + } + + client = (IClient *)m_Clients.GetNext(); + } + + // Duplicate client IP is not found. + if (!client) + { + if (m_Clients.CountElements() >= m_MaxClients) { + RejectConnection(to, false, (m_MaxClients > 0) ? "HLTV proxy is full.\n" : "HLTV proxy is disabled.\n"); + return; + } + + client = new ProxyClient(this); + + if (!m_System->AddModule(client, to->ToString())) + { + RejectConnection(to, false, "HLTV proxy is overloaded.\n"); + delete client; + return; + } + + client->SetWorld(m_World); + m_Clients.AddHead(client); + m_System->Printf("%s connected (%s at %s).\n", clientTypeString[type], name, to->ToString()); + } + + if (!client->Connect(m_Socket, to, userinfo)) { + RejectConnection(to, false, "Connection rejected.\n"); + m_System->RemoveModule(client); + m_System->Printf("Refused director connection for %s.\n", to->ToString()); + return; + } + + int specs, proxies; + CountLocalClients(specs, proxies); + if (m_MaxSeenClients < specs) { + m_MaxSeenClients = specs; + } +} + +void Proxy::CMD_Clients(char *cmdLine) +{ + int count = 0; + TokenLine params(cmdLine); + IClient *client = (IClient *)m_Clients.GetFirst(); + while (client) + { + count++; + m_System->Printf("%s", client->GetStatusLine()); + client = (IClient *)m_Clients.GetNext(); + } + + m_System->Printf("--- Total %i Clients ---\n", count); +} + +void Proxy::RejectConnection(NetAddress *adr, bool badPassword, const char *fmt, ...) +{ + va_list argptr; + char text[1024] = ""; + + va_start(argptr, fmt); + _vsnprintf(text, sizeof(text), fmt, argptr); + va_end(argptr); + + if (badPassword) { + m_Socket->OutOfBandPrintf(adr, "%cBADPASSWORD", S2C_REJECT_BADPASSWORD); + } + else { + m_Socket->OutOfBandPrintf(adr, "%c%s", S2C_REJECT, text); + } + + m_System->DPrintf("Rejected connection: %s (%s)\n", text, adr->ToString()); +} + +char *Proxy::GetStatusLine() +{ + static char string[256]; + _snprintf(string, sizeof(string), "Proxy name \"%s\", %s, Port %i, Clients %i/%i.\n", m_World->GetName(), m_IsMaster ? "Master" : "Relay", m_Socket->GetPort(), m_Clients.CountElements(), m_MaxClients); + return string; +} + +IObjectContainer *Proxy::GetClients() +{ + return &m_Clients; +} + +IWorld *Proxy::GetWorld() +{ + return m_World; +} + +IServer *Proxy::GetServer() +{ + return m_Server; +} + +IDirector *Proxy::GetDirector() +{ + return m_Director; +} + +INetSocket *Proxy::GetSocket() +{ + return m_Socket; +} + +ChatMode_e Proxy::GetChatMode() +{ + return m_ChatMode; +} + +void Proxy::UpdateStatusLine() +{ + float in, out; + char text[128]; + char activeTime[32]; + + strcopy(activeTime, COM_FormatTime((float)m_World->GetTime())); + + m_Network->GetFlowStats(&in, &out); + m_CurrentLoss = m_Server->GetPacketLoss(); + + _snprintf(text, sizeof(text), "%s, Time %s, Delay %.0f, FPS %.0f, Clients %i, In %.1f, Out %.1f, Loss %.2f", + IsMaster() ? "Master" : "Relay", activeTime, m_ClientDelay, m_FPS, m_Clients.CountElements(), in, out, m_CurrentLoss); + + m_System->SetStatusLine(text); + m_NextStatusUpdateTime = m_SystemTime + 0.25; +} + +void Proxy::CMD_Status(char *cmdLine) +{ + float in, out, loss; + m_Network->GetFlowStats(&in, &out); + loss = m_Server->GetPacketLoss(); + + m_System->Printf("--- HLTV Status ---\n"); + m_System->Printf("Online %s, FPS %.1f, Version %i (%s)\n", COM_FormatTime((float)m_System->GetTime()), m_FPS, COM_BuildNumber(), __isWindows ? "Win32" : "Linux"); + m_System->Printf("Local IP %s, Network In %.1f, Out %.1f, Loss %.2f\n", m_Network->GetLocalAddress()->ToString(), in, out, loss); + + int spectators, proxies; + CountLocalClients(spectators, proxies); + m_System->Printf("Local Slots %i, Spectators %i (max %i), Proxies %i\n", GetMaxClients(), spectators, m_MaxSeenClients, proxies); + + if (m_Server->IsConnected()) + { + int slots, maxspecs; + m_Status.GetGlobalStats(proxies, slots, spectators); + maxspecs = m_Status.GetMaxSpectatorNumber(); + m_System->Printf("Total Slots %i, Spectators %i (max %i), Proxies %i\n", slots, spectators, maxspecs, proxies); + + if (m_Server->IsDemoFile()) + { + m_System->Printf("Playing Demo File \"%s\"\n", m_Server->GetDemoFileName()); + } + else if (m_Server->IsGameServer()) + { + m_System->Printf("Connected to Game Server %s, Delay %.0f\n", m_Server->GetAddress()->ToString(), m_ClientDelay); + m_System->Printf("Server Name \"%s\"\n", m_Server->GetHostName()); + } + else if (m_Server->IsRelayProxy()) + { + m_System->Printf("Connected to HLTV Proxy %s\n", m_Server->GetAddress()->ToString()); + m_System->Printf("Proxy Name \"%s\"\n", m_Server->GetHostName()); + } + else + { + m_System->Printf("Not connected.\n"); + } + } + else + { + m_System->Printf("Not connected.\n"); + } + + if (m_World->IsActive()) + { + char activeTime[32]; + strcopy(activeTime, COM_FormatTime((float)m_World->GetTime())); + + const char *mapname = m_World->GetLevelName() + sizeof("maps/") - 1; // skip 'maps/' + m_System->Printf("Game Time %s, Mod \"%s\", Map \"%s\", Players %i\n", activeTime, m_World->GetGameDir(), mapname, m_World->GetNumPlayers()); + } + + if (m_DemoClient.IsActive()) + { + DemoFile *df = m_DemoClient.GetDemoFile(); + m_System->Printf("Recording to %s, Length %.1f sec.\n", df->GetFileName(), df->GetDemoTime()); + } +} + +void Proxy::CountLocalClients(int &spectators, int &proxies) +{ + spectators = 0; + proxies = 0; + + IClient *client = (IClient *)m_Clients.GetFirst(); + while (client) + { + if (client->GetClientType() == TYPE_PROXY) + proxies++; + else + spectators++; + + client = (IClient *)m_Clients.GetNext(); + } +} + +void Proxy::GetStatistics(int &proxies, int &slots, int &spectators) +{ + m_Status.GetGlobalStats(proxies, slots, spectators); +} + +int Proxy::GetMaxUpdateRate() +{ + return m_MaxUpdateRate; +} + +int Proxy::GetMaxRate() +{ + return m_MaxRate; +} + +bool Proxy::WriteSignonData(int type, BitBuffer *stream) +{ + if (type != TYPE_CLIENT && type != TYPE_DEMO) { + return false; + } + + if (m_SignonCommands[0]) { + stream->WriteByte(svc_stufftext); + stream->WriteString(COM_VarArgs("%s\n", m_SignonCommands)); + } + + float ex_interp = (1 / GetMaxUpdateRate()) + 0.05f; + stream->WriteByte(svc_stufftext); + stream->WriteString(COM_VarArgs("ex_interp %.2f\n", ex_interp)); + + stream->WriteByte(svc_timescale); + stream->WriteFloat(1); + + if (m_BannerTGA) { + DirectorCmd cmd; + cmd.SetBannerData(m_BannerTGA->szFileName); + cmd.WriteToStream(stream); + } + + return true; +} + +bool Proxy::IsPublicGame() +{ + return m_PublicGame; +} + +bool Proxy::IsPasswordProtected() +{ + return m_SpectatorPassword[0] ? true : false; +} + +bool Proxy::IsStressed() +{ + if (m_CurrentLoss > m_MaxLoss || m_FPS < 30) { + return true; + } + + return false; +} + +int Proxy::GetDispatchMode() +{ + return m_DispatchMode; +} + +char *Proxy::GetType() +{ + return PROXY_INTERFACE_VERSION; +} + +bool Proxy::IsLanOnly() +{ + return m_Master.m_NoMaster; +} + +bool Proxy::IsActive() +{ + if (!m_World) { + return false; + } + + return m_World->IsActive(); +} + +unsigned char Proxy::GetRegion() +{ + return m_Region; +} + +void Proxy::ReplyListen(NetAddress *to) +{ + m_Socket->OutOfBandPrintf(to, "%c 0.0.0.0\n", S2A_PROXY_LISTEN); +} + +void Proxy::Reset() +{ + m_Status.Reset(); + + m_MaxSeenClients = 0; + m_LastCheeringUpdate = 0; + m_CheeringPlayers = 0; +} + +void Proxy::ParseStatusMsg(BitBuffer *stream) +{ + m_Status.ParseStatusMsg(stream); +} + +void Proxy::ParseStatusReport(NetAddress *from, BitBuffer *stream) +{ + m_Status.ParseStatusReport(from, stream); +} + +void Proxy::Broadcast(byte *data, int length, int groupType, bool isReliable) +{ + IClient *client = (IClient *)m_Clients.GetFirst(); + while (client) + { + if (((groupType & GROUP_CLIENT) && client->GetClientType() == TYPE_CLIENT) + || ((groupType & GROUP_PROXY) && client->GetClientType() == TYPE_PROXY) + || ((groupType & GROUP_VOICE) && client->IsHearingVoices()) + || ((groupType & GROUP_CHAT) && client->HasChatEnabled())) + { + client->Send(data, length, isReliable); + } + + client = (IClient *)m_Clients.GetNext(); + } + + if (m_DemoClient.IsActive()) + { + if (groupType & GROUP_DEMO) { + m_DemoClient.Send(data, length, isReliable); + } + } +} + +void Proxy::CMD_Say(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 2) + { + m_System->Printf("Syntax: say \n"); + return; + } + + if (m_Server->IsConnected()) + { + char string[1024]; + _snprintf(string, sizeof(string), "say \"%s\"", params.GetRestOfLine(1)); + m_Server->SendStringCommand(string); + } +} + +void Proxy::CMD_MaxClients(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: maxclients \n"); + m_System->Printf("Current number of maximal clients is %i.\n", GetMaxClients()); + return; + } + + if (!SetMaxClients(atoi(params.GetToken(1)))) { + m_System->Printf("Allowed maximum number of local clients is %i.\n", MAX_PROXY_CLIENTS); + return; + } +} + +bool Proxy::SetMaxClients(int number) +{ + if (number < 0) { + m_MaxClients = 0; + return false; + } + + if (number > MAX_PROXY_CLIENTS) { + m_MaxClients = MAX_PROXY_CLIENTS; + return false; + } + + m_MaxClients = number; + return true; +} + +void Proxy::SetMaxLoss(float maxloss) +{ + m_MaxLoss = clamp(maxloss, 0.0f, 1.0f); +} + +int Proxy::GetMaxClients() +{ + return m_MaxClients; +} + +void Proxy::SetRegion(unsigned char region) +{ + m_Region = region; +} + +void Proxy::CMD_Delay(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: delay \n"); + m_System->Printf("Current spectator delay is %.1f seconds.\n", m_ClientDelay); + return; + } + + SetDelay(float(atof(params.GetToken(1)))); +} + +void Proxy::CMD_Stop(char *cmdLine) +{ + TokenLine params(cmdLine); + StopBroadcast(params.CountToken() > 1 ? params.GetRestOfLine(1) : "HLTV stopped."); + m_System->Printf("Disconnected and stoppted.\n"); +} + +void Proxy::CMD_Connect(char *cmdLine) +{ + NetAddress address; + TokenLine params(cmdLine); + if (!m_Network->ResolveAddress(params.GetToken(1), &address)) { + m_System->Printf("Error! HLTV Proxy::ConnectToServer: couldn't resolve server address.\n"); + return; + } + + if (!address.m_Port) { + address.SetPort_(atoi("27015")); + } + + Reset(); + m_Server->Connect(m_World, &address, m_Socket); +} + +void Proxy::CMD_Name(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 2) + { + m_System->Printf("Current name is \"%s\".\n", m_Server->GetPlayerName()); + return; + } + + char name[MAX_NAME]; + int len = strlen(params.GetToken(1)); + if (len > sizeof(name) - 1) { + m_System->Printf("Invalid name length.\n"); + return; + } + + strcopy(name, params.GetToken(1)); + m_Server->SetPlayerName(name); +} + +void Proxy::CMD_Msg(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 2) + { + m_System->Printf("Syntax: msg [ ]\n", m_Server->GetPlayerName()); + return; + } + + strcopy(m_LocalMessage.text, params.GetToken(1)); + + if (params.CountToken() == 6) + { + m_LocalMessage.holdtime = float(atof(params.GetToken(2))); + m_LocalMessage.x = float(atof(params.GetToken(3))); + m_LocalMessage.y = float(atof(params.GetToken(4))); + + sscanf(params.GetToken(5), "%2hhx%2hhx%2hhx%2hhx", &m_LocalMessage.r1, &m_LocalMessage.g1, &m_LocalMessage.b1, &m_LocalMessage.a1); + } + + BitBuffer buffer(144); + WriteHUDMsg(&m_LocalMessage, &buffer); + + Broadcast(buffer.GetData(), buffer.CurrentSize(), GROUP_CLIENT_ALL, false); +} + +void Proxy::CMD_Protocol(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: protocol <46|47>\n"); + m_System->Printf("Current protcol version is %i\n", m_Server->GetProtocol()); + return; + } + + if (!m_Server->SetProtocol(atoi(params.GetToken(1)))) { + m_System->Printf("Protocol version not supported!\n"); + return; + } +} + +void Proxy::CMD_MaxRate(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: maxrate \n"); + m_System->Printf("Current maximal client rate is %i bytes/sec.\n", m_MaxRate); + return; + } + + SetMaxRate(atoi(params.GetToken(1))); +} + +void Proxy::CMD_ServerCmd(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 2) + { + m_System->Printf("Syntax: servercmd \n"); + return; + } + + if (m_Server->IsConnected()) { + m_Server->SendStringCommand(params.GetRestOfLine(1)); + } +} + +void Proxy::CMD_ClientCmd(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 3) + { + m_System->Printf("Syntax: clientcmd \n"); + m_System->Printf("groups: 1 = spectators only, 2 = proxies only, 3 = all\n"); + return; + } + + int group = atoi(params.GetToken(1)); + char *cmdstring = params.GetRestOfLine(2); + if (strlen(cmdstring) > 100) { + m_System->Printf("ERROR! Command string too long.\n"); + return; + } + + switch (group) + { + case 1: // spectators + group = GROUP_CLIENT | GROUP_DEMO | GROUP_UNKNOWN; + break; + case 2: // proxies + group = GROUP_PROXY; + break; + default: // all + group = GROUP_CLIENT_ALL; + break; + } + + BitBuffer cmdbuf(128); + cmdbuf.WriteByte(svc_stufftext); + cmdbuf.WriteString(COM_VarArgs("%s\n", cmdstring)); + + Broadcast(cmdbuf.GetData(), cmdbuf.CurrentSize(), group, true); +} + +void Proxy::CMD_Rate(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: rate \n"); + m_System->Printf("Current maximal server to HLTV proxy rate is %i bytes/sec.\n", m_Server->GetRate()); + return; + } + + m_Server->SetRate(atoi(params.GetToken(1))); +} + +void Proxy::CMD_Players(char *cmdLine) +{ + int count = 0; + InfoString playerInfo(MAX_INFO_STRING); + for (int i = 0; i < m_World->GetMaxClients(); i++) + { + if (m_World->GetPlayerInfoString(i, &playerInfo)) { + m_System->Printf("#%2i \"%s\" %s\n", i + 1, playerInfo.ValueForKey("name"), playerInfo.ValueForKey("model")); + count++; + } + } + + m_System->Printf("--- Total %i Players ---\n", count); +} + +void Proxy::CMD_HostName(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Host name is \"%s\"\n", m_World->GetHostName()); + return; + } + + if (!_stricmp(params.GetToken(1), "none")) { + m_World->SetHostName(nullptr); + return; + } + + m_World->SetHostName(params.GetToken(1)); +} + +void Proxy::CMD_Updaterate(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: updaterate \n"); + m_System->Printf("Current update rate is %i packets/sec.\n", m_Server->GetUpdateRate()); + return; + } + + SetMaxUpdateRate(atoi(params.GetToken(1))); + m_Server->SetUpdateRate(m_MaxUpdateRate); +} + +void Proxy::CMD_BlockVoice(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: blockvoice <0|1>\n"); + m_System->Printf("Currently voice data is %s.\n", m_Server->IsVoiceBlocking() ? "blocked" : "relayed"); + return; + } + + m_Server->SetVoiceBlocking(atoi(params.GetToken(1)) ? true : false); +} + +void Proxy::CMD_Record(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: record \n"); + m_System->Printf("Output format is \"filename-date-map.dem\".\n"); + return; + } + + if (m_DemoClient.Connect()) { + m_DemoClient.SetFileName(params.GetToken(1)); + } +} + +void Proxy::CMD_StopRecording(char *cmdLine) +{ + if (m_DemoClient.IsActive()) { + m_DemoClient.Disconnect("End of Record"); + return; + } + + m_System->Printf("Not recording.\n"); +} + +void Proxy::CMD_LoopCmd(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 4) + { + m_System->Printf("Syntax: loopcmd \n"); + m_System->Printf("Currently %i looping commands in list.\n", m_LoopCommands.CountElements()); + return; + } + + int id = atoi(params.GetToken(1)); + float seconds = float(atof(params.GetToken(2))); + char *cmds = params.GetRestOfLine(3); + + loopcmd_t *lcmd = (loopcmd_t *)m_LoopCommands.GetFirst(); + while (lcmd) + { + if (lcmd->id == id) { + break; + } + + lcmd = (loopcmd_t *)m_LoopCommands.GetNext(); + } + + if (!_stricmp(cmds, "none") || !seconds) + { + if (lcmd) { + m_LoopCommands.Remove(lcmd); + return; + } + + m_System->Printf("Couldn't remove loop command %i\n", id); + return; + } + + if (!lcmd) + { + lcmd = (loopcmd_t *)Mem_ZeroMalloc(sizeof(loopcmd_t)); + lcmd->id = id; + + m_LoopCommands.Add(lcmd); + } + + lcmd->interval = seconds; + lcmd->lastTime = 0; + + strcopy(lcmd->command, cmds); +} + +void Proxy::CMD_RconAddress(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: rconaddress \n"); + m_System->Printf("Current remote console address: %s\n", m_RconAddress.ToString()); + return; + } + + m_Network->ResolveAddress(params.GetToken(1), &m_RconAddress); + if (!m_RconAddress.m_Port) { + m_RconAddress.SetPort_(atoi("27015")); + } +} + +void Proxy::CMD_RconPassword(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: rconpassword \n"); + return; + } + + strcopy(m_RconPassword, params.GetToken(1)); +} + +void Proxy::CMD_Rcon(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 2) + { + m_System->Printf("Syntax: rcon \n"); + return; + } + + if (!m_RconPassword[0]) { + m_System->Printf("Set 'rconpassword' before issuing a rcon command.\n"); + return; + } + + if (!m_RconAddress.IsValid() && m_Server->IsConnected()) { + m_RconAddress.FromNetAddress(m_Server->GetAddress()); + } + + if (!m_RconAddress.IsValid()) { + m_System->Printf("rconaddress not valid.\n"); + return; + } + + strcopy(m_LastRconCommand, params.GetRestOfLine(1)); + m_Socket->OutOfBandPrintf(&m_RconAddress, "challenge rcon\n"); +} + +void Proxy::SendRcon(NetAddress *to, unsigned int challenge) +{ + if (!m_LastRconCommand[0]) { + m_System->Printf("HLTV Proxy::SendRcon: Empty rcon string\n"); + return; + } + + if (!to->Equal(&m_RconAddress)) { + m_System->Printf("Unwanted rcon challenge reply from %s\n", to->ToString()); + return; + } + + m_Socket->OutOfBandPrintf(to, "rcon %u \"%s\" %s", challenge, m_RconPassword, m_LastRconCommand); +} + +unsigned int Proxy::GetChallengeNumber(NetAddress *host) +{ + int i; + int oldest = 0; + float oldestTime = 9.9999997e37f; + const float challengeLife = 40.0f; + + for (i = 0; i < MAX_CHALLENGES; i++) + { + if (m_Challenges[i].adr.Equal(host)) { + break; + } + + if (m_Challenges[i].time < oldestTime) + { + oldestTime = m_Challenges[i].time; + oldest = i; + } + } + + if (i == MAX_CHALLENGES) + { + m_Challenges[oldest].adr.FromNetAddress(host); + + // generate new challenge number + m_Challenges[oldest].challenge = (RandomLong(0, 0xFFFF) | RandomLong(0, 0xFFFF) << 16); + m_Challenges[oldest].time = float(m_SystemTime); + + i = oldest; + } + + if (m_SystemTime > m_Challenges[i].time + PROXY_CHALLENGE_LIFE) + { + // generate new challenge number + m_Challenges[i].challenge = (RandomLong(0, 0xFFFF) | RandomLong(0, 0xFFFF) << 16); + m_Challenges[i].time = float(m_SystemTime); + } + + return m_Challenges[i].challenge; +} + +bool Proxy::CheckChallenge(NetAddress *from, unsigned int challengeNumber) +{ + for (auto& it : m_Challenges) + { + if (it.adr.Equal(from)) { + if (it.challenge == challengeNumber) { + return (m_SystemTime - it.time <= 40); + } + + break; + } + } + + return false; +} + +void Proxy::ReplyServiceChallenge(NetAddress *to, char *type) +{ + unsigned int challengeNumber = GetChallengeNumber(to); + m_Socket->OutOfBandPrintf(to, "challenge %s %u\n", type, challengeNumber); +} + +void Proxy::CMD_ProxyPassword(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: proxypassword \n"); + return; + } + + if (!_stricmp(params.GetToken(1), "none")) { + m_ProxyPassword[0] = '\0'; + return; + } + + strcopy(m_ProxyPassword, params.GetToken(1)); +} + +void Proxy::NewServerConnection() +{ + m_IsMaster = m_Server->IsGameServer(); + + if (m_IsMaster && m_ClientDelay > 0) + { + m_World->SetBufferSize(m_ClientDelay + m_ClientDelay); + m_Server->SetDelayReconnect(true); + } + else + { + m_World->SetBufferSize(10); + m_Server->SetDelayReconnect(false); + } + + resource_t *resource = (resource_t *)m_Resources.GetFirst(); + while (resource) + { + m_World->AddResource(resource); + resource = (resource_t *)m_Resources.GetNext(); + } + + m_IsReconnectRequested = false; +} + +void Proxy::ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) +{ + int from = module->GetSerial(); + + // Server module + if (from == m_Server->GetSerial()) + { + switch (signal) + { + case 4: + NewServerConnection(); + break; + case 5: + case 6: + m_IsFinishingBroadcast = true; + break; + case 7: + BroadcastRetryMessage(); + break; + default: + break; + } + + return; + } + + // World module + if (from == m_World->GetSerial()) + { + switch (signal) + { + case 2: + NewGameStarted(); + ReconnectClients(); + break; + case 5: + case 6: + BroadcastPaused(signal == 5 ? true : false); + break; + case 8: + StopBroadcast("HLTV shutddown."); + break; + default: + break; + } + + return; + } +} + +char *Proxy::GetModVersion(char *gamedir) +{ + static char version[] = PROXY_VERSION; + return version; +} + +void Proxy::BroadcastRetryMessage() +{ + BitBuffer msg(32); + msg.WriteByte(svc_centerprint); + msg.WriteString("Retrying HLTV connection ..."); + + Broadcast(msg.GetData(), msg.CurrentSize(), GROUP_CLIENT | GROUP_PROXY | GROUP_UNKNOWN, false); +} + +void Proxy::StopBroadcast(const char *message) +{ + DisconnectClients(message ? COM_VarArgs("%s\n", message) : "HLTV stopped.\n"); + + m_Server->Disconnect(); + m_Server->StopRetry(); + m_World->StopGame(); + + m_Master.SendShutdown(); + m_System->SetTitle("HLTV - offline"); +} + +void Proxy::ExecuteRcon(NetAddress *from, char *command) +{ + char outputbuf[1024]; + m_System->Printf("Executing rcon \"%s\" from %s.\n", command, from->ToString()); + + m_System->RedirectOutput(outputbuf + 1, sizeof(outputbuf) - 1); + m_System->ExecuteString(command); + m_System->RedirectOutput(); + + if (outputbuf[1]) { + m_Socket->OutOfBandPrintf(from, "%c%s", A2A_PRINT, outputbuf); + } +} + +bool Proxy::ProcessConnectionlessMessage(NetAddress *from, BitBuffer *stream) +{ + if (IsBanned(from)) { + return false; + } + + TokenLine cmdLine; + if (!cmdLine.SetLine(stream->ReadStringLine())) { + m_System->DPrintf("WARNING! HLTV Proxy::ProcessConnectionlessMessage: message too long.\n"); + return false; + } + + if (!cmdLine.CountToken()) { + m_System->DPrintf("WARNING! Invalid packet from %s.\n", from->ToString()); + return false; + } + + if (SteamGameServer()) + { + const int maxBuffer = 4096; + unsigned char data[maxBuffer]; + int maxSize = min(stream->m_MaxSize, maxBuffer); + + memcpy((char *)&data[4], stream->m_Data, maxSize); + *(uint32 *)data = CONNECTIONLESS_HEADER; // connectionless packet + + SteamGameServer()->HandleIncomingPacket(data, maxSize + 4, ntohl(*(u_long *)&from->m_IP[0]), htons(from->m_Port)); + } + + char *c = cmdLine.GetToken(0); + if (c[0] == S2C_CHALLENGE) + { + m_System->DPrintf("Unwanted challenge response from %s.\n", from->ToString()); + return false; + } + + if (!strcmp(c, "challenge")) + { + char *type = cmdLine.GetToken(1); + switch (cmdLine.CountToken()) + { + case 3: + { + if (type && type[0] && !_stricmp(type, "rcon")) + { + unsigned int challengeNr = strtoul(cmdLine.GetToken(2), 0, 10); + SendRcon(from, challengeNr); + break; + } + + m_System->Printf("Invalid challenge type (%s) from: %s\n", type ? type : "NULL", from->ToString()); + return false; + } + case 2: + ReplyServiceChallenge(from, type); + break; + default: + m_System->Printf("Invalid challenge request from: %s\n", from->ToString()); + return false; + } + } + else if (!strcmp(c, "rcon")) + { + if (cmdLine.CountToken() < 4) { + return false; + } + + unsigned int challenge = strtoul(cmdLine.GetToken(1), 0, 10); + char *password = cmdLine.GetToken(2); + char *command = cmdLine.GetRestOfLine(3); + + if (!CheckChallenge(from, challenge)) + { + m_System->Printf("Invalid rcon challenge from: %s\n", from->ToString()); + return false; + } + + if (!m_AdminPassword[0] || strcmp(m_AdminPassword, password) != 0) + { + m_System->Printf("Invalid rcon password from: %s\n", from->ToString()); + return false; + } + + ExecuteRcon(from, command); + } + else if (!strcmp(c, "getchallenge")) + { + ReplyChallenge(from); + } + else if (!strcmp(c, "connect")) + { + if (cmdLine.CountToken() == 5) + { + int protocol = atoi(cmdLine.GetToken(1)); + int challenge = atoi(cmdLine.GetToken(2)); + + char *protinfo = cmdLine.GetToken(3); + char *userinfo = cmdLine.GetToken(4); + + ReplyConnect(from, protocol, challenge, protinfo, userinfo); + } + else + { + RejectConnection(from, false, "Insufficient connection info\n"); + } + } + else if (c[0] == A2A_ACK && (c[1] == 0 || c[1] == '\n')) + { + m_System->DPrintf("Acknowledgment from %s.\n", from->ToString()); + } + else if (c[0] == A2S_INFO) + { + ReplyInfo(from, true); + } + else if (c[0] == A2S_PLAYER) + { + ReplyPlayers(from); + } + else if (c[0] == A2S_RULES) + { + ReplyRules(from); + } + else if (!strcmp(c, "listen")) + { + ReplyListen(from); + } + // guard to frequency queries + else if (m_MaxFrameQueries > 0) + { + if (!strcmp(c, "ping") || (c[0] == A2A_PING && (c[1] == 0 || c[1] == '\n'))) + { + ReplyPing(from); + } + else if (!_stricmp(c, "infostring")) + { + ReplyInfoString(from); + } + else if (!_stricmp(c, "info")) + { + ReplyInfo(from, false); + } + else if (!_stricmp(c, "details")) + { + ReplyInfo(from, true); + } + else if (!_stricmp(c, "players")) + { + ReplyPlayers(from); + } + else if (!_stricmp(c, "rules")) + { + ReplyRules(from); + } + else if (!_stricmp(c, "log")) + { + m_System->Printf("Ignoring log from %s.\n", from->ToString()); + return false; + } + else if (c[0] == A2A_PRINT) + { + stream->Reset(); + stream->SkipBytes(1); + + m_System->Printf(">%s\n", stream->ReadString()); + } + else + { + m_System->DPrintf("Proxy::ProcessConnectionlessMessage: unknown \"%s\" from %s \n", c, from->ToString()); + return false; + } + + m_MaxFrameQueries--; + } + + return true; +} + +void Proxy::CMD_ChatMode(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + static const char *chatModeString[] = { "OFF", "LOCAL", "GLOBAL" }; + + m_System->Printf("Syntax: chatmode <0|1|2>\n"); + m_System->Printf("Currently chat mode is %s.\n", chatModeString[ m_ChatMode ]); + return; + } + + m_ChatMode = clamp((ChatMode_e)atoi(params.GetToken(1)), CHAT_OFF, CHAT_GLOBAL); +} + +void Proxy::CMD_MaxQueries(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: maxqueries \n"); + m_System->Printf("Currently maximum %.0f queries per seconds accepted.\n", m_MaxQueries); + return; + } + + m_MaxQueries = float(atof(params.GetToken(1))); +} + +void Proxy::CMD_Kick(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: kick \n"); + return; + } + + int id = atoi(params.GetToken(1)); + + IClient *client = (IClient *)m_Clients.GetFirst(); + while (client) + { + if (client->GetSerial() == id) { + client->Disconnect("You have been kicked.\n"); + return; + } + + client = (IClient *)m_Clients.GetNext(); + } + + m_System->Printf("%i is not a valid client ID.\n", id); +} + +void Proxy::CMD_Disconnect(char *cmdLine) +{ + m_Server->Disconnect(); +} + +void Proxy::ChatSpectator(char *nick, char *text) +{ + if (!text || m_ChatMode == CHAT_OFF) { + return; + } + + int sayMsgNum = m_World->FindUserMsgByName("SayText"); + if (!sayMsgNum) { + return; + } + + char string[512] = ""; + COM_RemoveEvilChars(text); + + // TODO: too harsh, let more? maxlen: 190 + const int maxLengthOfString = 64; + int len = strlen(text); + if (len <= 0) { + return; + } + + if (len > maxLengthOfString) { + text[maxLengthOfString] = '\0'; + } + + if (m_ChatMode != CHAT_LOCAL && !m_IsMaster) + { + _snprintf(string, sizeof(string), "say \"%s\"", text); + if (m_Server->IsConnected()) { + m_Server->SendStringCommand(string); + } + + return; + } + + const int extraBytesOfEnd = 2; // extra of ends bytes \n + \0 + const int headerBytes = 3; // reserve a header of 3 bytes. + const int maxSizeOfMessage = MAX_USER_MSG_DATA - headerBytes; // user message size limit is 192 bytes + + _snprintf(&string[ headerBytes ], sizeof(string) - headerBytes, "<%s> %s", nick, text); + + int curLen = strlen(&string[ headerBytes ]); + if (curLen > maxSizeOfMessage) { + curLen = maxSizeOfMessage; + } + + // fill up to 3+ remaining bytes + string[0] = sayMsgNum; // unique id usermsg SayText. + string[1] = curLen + headerBytes; // the length of message. + string[2] = '\0'; // terminal null + + string[curLen + 3] = '\n'; + string[curLen + 4] = '\0'; + + int groupType; + if (m_ChatMode == CHAT_LOCAL) { + groupType = GROUP_CHAT; + } else { + groupType = GROUP_CHAT | GROUP_PROXY; + } + + Broadcast((byte *)string, curLen + headerBytes + extraBytesOfEnd, groupType, false); +} + +bool Proxy::IsMaster() +{ + return m_IsMaster; +} + +bool Proxy::CheckDirectorModule() +{ + char szAbsoluteLibFilename[MAX_PATH]; + if (m_Director && !strcmp(m_Director->GetModName(), m_World->GetGameDir())) { + return true; + } + + _snprintf(szAbsoluteLibFilename, sizeof(szAbsoluteLibFilename), "%s/dlls/director", m_World->GetGameDir()); + if (m_Director) { + m_System->RemoveModule(m_Director); + } + + m_Director = dynamic_cast(m_System->GetModule(DIRECTOR_INTERFACE_VERSION, szAbsoluteLibFilename, "director")); + if (m_Director) + { + m_System->Printf("Using extern director module (%s).\n", szAbsoluteLibFilename); + return true; + } + + // If we don't have director module, + // to set up on internal default director. + if (!m_System->AddModule(&m_DefaultDirector, "director")) { + m_System->Errorf("Proxy::CheckDirectorModule: failed to add internal director module.\n"); + return false; + } + + m_Director = &m_DefaultDirector; + m_System->DPrintf("Using internal default director.\n"); + + return true; +} + +void Proxy::ReconnectClients() +{ + IClient *client = (IClient *)m_Clients.GetFirst(); + while (client) + { + client->Reconnect(); + client = (IClient *)m_Clients.GetNext(); + } + + m_DemoClient.Reconnect(); +} + +void Proxy::CMD_OffLineText(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: offlinetext \n"); + m_System->Printf("Offline info text is \"%s\"\n", m_OffLineText); + return; + } + + strcopy(m_OffLineText, params.GetToken(1)); + COM_RemoveEvilChars(m_OffLineText); +} + +void Proxy::CMD_Resources(char *cmdLine) +{ + resource_t *resource = (resource_t *)m_Resources.GetFirst(); + while (resource) + { + m_System->Printf("File: \"%s\", Size: %i bytes.\n", resource->szFileName, resource->nDownloadSize); + resource = (resource_t *)m_Resources.GetNext(); + } + + m_System->Printf("--- Total %i Resources ---\n", m_Resources.CountElements()); +} + +void Proxy::CMD_AddResource(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 3) + { + m_System->Printf("Syntax: addresource []\n"); + return; + } + + if (!AddResource(params.GetToken(1), (resourcetype_t)atoi(params.GetToken(2)), params.GetToken(3))) + { + m_System->Printf("Error! Failed to load resource %s.\n", params.GetToken(1)); + return; + } +} + +void Proxy::CMD_PublicGame(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: publicgame <0|1>\n"); + m_System->Printf("Joingame is %s.\n", m_PublicGame ? "enabled" : "disabled"); + return; + } + + m_PublicGame = atoi(params.GetToken(1)) ? true : false; +} + +void Proxy::WriteHUDMsg(textmessage_t *msg, BitBuffer *stream) +{ + DirectorCmd cmd; + + vec3_t position; + position[0] = msg->x; + position[1] = msg->y; + position[2] = 0; + + cmd.SetMessageData( + msg->effect, + COM_PackRGB(msg->r1, msg->g1, msg->b1), + position, + msg->fadein, + msg->fadeout, + msg->holdtime, + msg->fxtime, + msg->text + ); + + cmd.WriteToStream(stream); +} + +void Proxy::CMD_SpectatorPassword(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: spectatorpassword \n"); + return; + } + + if (!_stricmp(params.GetToken(1), "none")) { + m_SpectatorPassword[0] = '\0'; + return; + } + + strcopy(m_SpectatorPassword, params.GetToken(1)); +} + +void Proxy::CMD_DispatchMode(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + static const char *dispatchModeString[] = { "OFF", "AUTO", "ALWAYS" }; + + m_System->Printf("Syntax: dispatchmode <0|1|2>\n"); + m_System->Printf("Spectator dispatch mode is: %s.\n", dispatchModeString[ m_DispatchMode ]); + return; + } + + m_DispatchMode = clamp((DispatchMode_e)atoi(params.GetToken(1)), DISPATCH_OFF, DISPATCH_ALL); +} + +bool Proxy::IsValidPassword(int type, char *pw) +{ + switch (type) + { + // spec password + case TYPE_CLIENT: + { + if (m_SpectatorPassword[0]) { + return strcmp(m_SpectatorPassword, pw) == 0; + } + + return true; + } + // proxy password + case TYPE_PROXY: + { + if (m_ProxyPassword[0]) { + return strcmp(m_ProxyPassword, pw) == 0; + } + + // password is not set + return true; + } + // admin password + case TYPE_COMMENTATOR: + { + if (m_AdminPassword[0]) { + return strcmp(m_AdminPassword, pw) == 0; + } + + break; + } + default: + break; + } + + return false; +} + +void Proxy::CMD_PlayDemo(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 2) + { + m_System->Printf("Sytax: playdemo \n"); + return; + } + + m_Server->LoadDemo(m_World, params.GetToken(1), true, true); + m_World->SetBufferSize(10); +} + +void Proxy::DispatchClient(NetAddress *client, NetAddress *proxy) +{ + BitBuffer buf(128); + + buf.WriteLong(CONNECTIONLESS_HEADER); // connectionless header + buf.WriteByte(S2A_PROXY_REDIRECT); // data header + buf.WriteString(proxy->ToString()); // ip proxy destination + + m_Socket->SendPacket(client, buf.GetData(), buf.CurrentSize()); + m_System->DPrintf("Dispatched client %s to proxy %s.\n", client->ToString(), proxy->ToString()); +} + +resource_t *Proxy::LoadResourceFromFile(char *fileName, resourcetype_t type) +{ + resource_t *newresource = (resource_t *)Mem_ZeroMalloc(sizeof(resource_t)); + + strcopy(newresource->szFileName, fileName); + + newresource->type = type; + newresource->data = m_System->LoadFile(newresource->szFileName, &newresource->nDownloadSize); + if (newresource->data && newresource->nDownloadSize >= 0) { + MD5_Hash_Mem(newresource->rgucMD5_hash, newresource->data, newresource->nDownloadSize); + return newresource; + } + + m_System->Printf("WARNING! Failed to load resource file %s.\n", fileName); + free(newresource); + return nullptr; +} + +void Proxy::FreeResource(resource_t *resource) +{ + if (!resource) { + return; + } + + if (resource->data) { + m_System->FreeFile(resource->data); + } + + free(resource); +} + +void Proxy::ClearResources() +{ + resource_t *resource; + while ((resource = (resource_t *)m_Resources.RemoveHead())) { + FreeResource(resource); + } +} + +resource_t *Proxy::AddResource(char *fileName, resourcetype_t type, char *asFileName) +{ + resource_t *resource = GetResource(fileName); + if (resource) { + FreeResource(resource); + m_Resources.Remove(resource); + } + + resource = LoadResourceFromFile(fileName, t_generic /* type */); // TODO: why we use only t_generic? + if (resource) + { + if (asFileName) { + strcopy(resource->szFileName, asFileName); + } + + m_Resources.Add(resource); + return resource; + } + + return nullptr; +} + +resource_t *Proxy::GetResource(char *fileName) +{ + resource_t *resource = (resource_t *)m_Resources.GetFirst(); + while (resource) + { + if (!_strnicmp(fileName, resource->szFileName, sizeof(resource->szFileName))) { + return resource; + } + + resource = (resource_t *)m_Resources.GetNext(); + } + + return nullptr; +} + +void Proxy::CMD_SignOnCommands(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: signoncommands \n"); + m_System->Printf("Current sign on commands: \"%s\"\n", m_SignonCommands); + return; + } + + if (strlen(params.GetToken(1)) > 250) + { + m_System->Printf("Error! String too long (>250)!\n"); + return; + } + + strcopy(m_SignonCommands, params.GetToken(1)); +} + +void Proxy::CMD_AdminPassword(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: adminpassword \n"); + return; + } + + if (!_stricmp(params.GetToken(1), "none")) { + m_AdminPassword[0] = '\0'; + return; + } + + strcopy(m_AdminPassword, params.GetToken(1)); +} + +void Proxy::CMD_LocalMsg(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 2) + { + m_System->Printf("Syntax: localmsg [ ]\n"); + return; + } + + strcopy(m_LocalMessage.text, params.GetToken(1)); + + if (params.CountToken() == 6) + { + m_LocalMessage.holdtime = float(atof(params.GetToken(2))); + m_LocalMessage.x = float(atof(params.GetToken(3))); + m_LocalMessage.y = float(atof(params.GetToken(4))); + + sscanf(params.GetToken(5), "%2hhx%2hhx%2hhx%2hhx", &m_LocalMessage.r1, &m_LocalMessage.g1, &m_LocalMessage.b1, &m_LocalMessage.a1); + } + + BitBuffer buffer(144); + WriteHUDMsg(&m_LocalMessage, &buffer); + + Broadcast(buffer.GetData(), buffer.CurrentSize(), GROUP_CLIENT | GROUP_DEMO, false); +} + +void Proxy::ChatCommentator(char *nick, char *text) +{ + BitBuffer buffer(144); + + strcopy(m_CommentatorMessage.text, text); + + COM_RemoveEvilChars(m_CommentatorMessage.text); + WriteHUDMsg(&m_CommentatorMessage, &buffer); + + Broadcast(buffer.GetData(), buffer.CurrentSize(), GROUP_CLIENT_ALL, true); +} + +bool Proxy::IsBanned(NetAddress *adr) +{ + NetAddress *bannedAdr = (NetAddress *)m_BannList.GetFirst(); + while (bannedAdr) + { + if (adr->EqualBase(bannedAdr)) { + return bannedAdr != nullptr; + } + + bannedAdr = (NetAddress *)m_BannList.GetNext(); + } + + return false; +} + +void Proxy::CMD_AddFakeClients(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 5) + { + m_System->Printf("Syntax: addfakeclients \n"); + return; + } + + int number = atoi(params.GetToken(1)); + + NetAddress adr; + m_Network->ResolveAddress(params.GetToken(2), &adr); + + int rate = atoi(params.GetToken(3)); + float activity = float(atof(params.GetToken(4))); + + for (int i = 0; i < number; i++) + { + FakeClient *fakeclient = new FakeClient; + if (!m_System->AddModule(fakeclient, "")) { + m_System->Errorf("AddFakeClients: failed to add module.\n"); + delete fakeclient; + break; + } + + fakeclient->SetRate(rate); + fakeclient->Connect(&adr); + } +} + +void Proxy::CMD_MaxLoss(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: maxloss \n"); + m_System->Printf("Current server packet loss limit is %.2f.\n", m_MaxLoss); + return; + } + + SetMaxLoss(float(atof(params.GetToken(1)))); +} + +void Proxy::CMD_Region(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: region \n"); + m_System->Printf("Current server region is %i.\n", m_Region); + return; + } + + SetRegion(atoi(params.GetToken(1))); +} + +void Proxy::CMD_Bann(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: bann \n"); + m_System->Printf("Currently %i IPs banned\n", m_BannList.CountElements()); + return; + } + + NetAddress *adr = (NetAddress *)Mem_ZeroMalloc(sizeof(NetAddress)); + if (!(m_Network->ResolveAddress(params.GetToken(1), adr))) + { + m_System->Printf("Couldn't resolve IP \x02%s\"\n", params.GetToken(1)); + free(adr); + return; + } + + if (IsBanned(adr)) { + m_System->Printf("IP already banned.\n"); + free(adr); + return; + } + + m_BannList.Add(adr); +} + +void Proxy::CMD_ClearBanns(char *cmdLine) +{ + m_System->Printf("Clearing IP bann list (%i entries).\n", m_BannList.CountElements()); + m_BannList.Clear(true); +} + +void Proxy::CMD_ServerPassword(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() < 2) + { + m_System->Printf("Sytax: serverpassword \n"); + return; + } + + m_Server->SetUserInfo("password", params.GetToken(1)); +} + +void Proxy::CMD_Retry(char *cmdLine) +{ + m_System->Printf("Retrying connection...\n"); + m_Server->Retry(); +} + +void Proxy::CMD_AutoRetry(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: autoretry <0|1>\n"); + m_System->Printf("Automatic connection retry is %s.\n", m_Server->GetAutoRetry() ? "enabled" : "disabled"); + return; + } + + m_Server->SetAutoRetry(atoi(params.GetToken(1)) ? true : false); +} + +void Proxy::CMD_BannerFile(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: bannerfile \n"); + if (m_BannerTGA) { + m_System->Printf("Current HLTV banner file is %s\n", m_BannerTGA->szFileName); + return; + } + + m_System->Printf("No HLTV banner file specified.\n"); + return; + } + + if (!_stricmp(params.GetToken(1), "none")) { + m_BannerTGA = nullptr; + return; + } + + if (!(m_BannerTGA = AddResource(params.GetToken(1), t_generic))) { + m_System->Printf("ERROR! Couldn't load banner file.\n"); + return; + } + + _snprintf(m_BannerTGA->szFileName, sizeof(m_BannerTGA->szFileName), "gfx/temp/%s.tga", COM_BinPrintf(m_BannerTGA->rgucMD5_hash, sizeof(m_BannerTGA->rgucMD5_hash))); +} + +void Proxy::CMD_CheeringThreshold(char *cmdLine) +{ + TokenLine params(cmdLine); + if (params.CountToken() != 2) + { + m_System->Printf("Syntax: cheeringthreshold \n"); + m_System->Printf("Cheering threshold is %.2f.\n", m_CheeringThreshold); + return; + } + + m_CheeringThreshold = float(atof(params.GetToken(1))); +} + +float Proxy::GetDelay() +{ + if (m_IsMaster) { + return m_ClientDelay; + } + + return 0; +} + +double Proxy::GetSpectatorTime() +{ + return m_ClientWorldTime; +} + +double Proxy::GetProxyTime() +{ + return m_ClientProxyTime; +} + +void Proxy::IncreaseCheering(int votes) +{ + m_CheeringPlayers += votes; + float fraction = (float)(m_CheeringPlayers / m_Clients.CountElements()); + if (fraction > 1) { + fraction = 1; + } + + if (fraction > m_CheeringThreshold) + { + DirectorCmd cmd; + BitBuffer buf(64); + + cmd.SetSoundData("ambience/goal_1.wav", fraction); + cmd.WriteToStream(&buf); + + Broadcast(buf.GetData(), buf.CurrentSize(), GROUP_CLIENT | GROUP_DEMO, true); + m_CheeringPlayers = 0; + } +} + +void Proxy::ExecuteLoopCommands() +{ + static float nextCheck = 0.0f; + if (nextCheck > m_SystemTime) { + return; + } + + loopcmd_t *lcmd = (loopcmd_t *)m_LoopCommands.GetFirst(); + while (lcmd) + { + if (m_SystemTime > (lcmd->lastTime + lcmd->interval)) { + m_System->ExecuteString(lcmd->command); + lcmd->lastTime = float(m_SystemTime); + } + + lcmd = (loopcmd_t *)m_LoopCommands.GetNext(); + } + + nextCheck = float(m_SystemTime + 0.5f); +} + +void Proxy::CreateServerInfoString(InfoString *info) +{ + int proxies, slots, spectators; + m_Status.GetLocalStats(proxies, slots, spectators); + + char address[256]; + _snprintf(address, sizeof(address), "%s", m_Network->GetLocalAddress()->ToString()); + + info->SetValueForKey("protocol", COM_VarArgs("%i", PROTOCOL_VERSION)); + info->SetValueForKey("address", address); + info->SetValueForKey("players", COM_VarArgs("%i", spectators)); + info->SetValueForKey("proxy", COM_VarArgs("%i", IsMaster() ? 1 : 2)); + + if (IsPublicGame()) { + info->SetValueForKey("proxyaddress", m_World->GetGameServerAddress()->ToString()); + } + + info->SetValueForKey("lan", COM_VarArgs("%i", IsLanOnly())); + info->SetValueForKey("max", COM_VarArgs("%i", slots)); + if (m_World->IsActive()) + { + char gameDir[MAX_PATH], mapName[MAX_PATH]; + COM_FileBase(m_World->GetLevelName(), mapName); + COM_FileBase(m_World->GetGameDir(), gameDir); + + serverinfo_t *serverInfo = m_World->GetServerInfo(); + info->SetValueForKey("gamedir", gameDir); + info->SetValueForKey("description", serverInfo->description); + info->SetValueForKey("hostname", m_World->GetHostName()); + info->SetValueForKey("map", mapName); + + if (serverInfo->mod) + { + info->SetValueForKey("mod", "1"); + info->SetValueForKey("modversion", COM_VarArgs("%i", serverInfo->ver)); + } + } + else + { + info->SetValueForKey("gamedir", "valve"); + info->SetValueForKey("description", "HLTV"); + info->SetValueForKey("hostname", m_OffLineText); + info->SetValueForKey("map", "none"); + } + + info->SetValueForKey("type", GetServerType(HLST_TV)); + info->SetValueForKey("password", COM_VarArgs("%i", IsPasswordProtected())); + info->SetValueForKey("os", GetServerOS()); + info->SetValueForKey("secure", "0"); +} + +void Proxy::SetMaxRate(int rate) +{ + // maxrate: 1.000 - 20.000 + m_MaxRate = clamp(rate, 1000, MAX_PROXY_RATE); +} + +void Proxy::SetMaxUpdateRate(int updaterate) +{ + // maxupdaterate: 1.0 - 40.0 + m_MaxUpdateRate = clamp(updaterate, 1, MAX_PROXY_UPDATERATE); +} + +void Proxy::SetDelay(float seconds) +{ + m_ClientDelay = seconds; + + if (seconds < 10) + { + m_ClientDelay = 0; + m_World->SetBufferSize(10); + } + else + { + m_World->SetBufferSize(seconds + seconds); + m_ClientWorldTime = m_World->GetTime() - m_ClientDelay; + } + + m_Server->SetUserInfo("hdelay", COM_VarArgs("%u", (int)m_ClientDelay)); +} + +void Proxy::SetClientTime(double time, bool relative) +{ + if (relative) { + m_ClientWorldTime += time; + return; + } + + m_ClientWorldTime = time; +} + +void Proxy::SetClientTimeScale(float scale) +{ + BitBuffer buf(32); + m_ClientTimeScale = clamp(scale, 4.0f, 0.5f); + + buf.WriteByte(svc_timescale); + buf.WriteFloat(m_ClientTimeScale); + + Broadcast(buf.GetData(), buf.CurrentSize(), GROUP_CLIENT_ALL, true); +} + +void Proxy::BroadcastPaused(bool paused) +{ + BitBuffer buf(32); + buf.WriteByte(svc_centerprint); + buf.WriteString(paused ? "Game was paused" : "Game was unpaused"); + + buf.WriteByte(svc_setpause); + buf.WriteByte(paused ? 1 : 0); + + Broadcast(buf.GetData(), buf.CurrentSize(), GROUP_CLIENT_ALL, true); +} + +void Proxy::NewGameStarted() +{ + m_LastClockUpdateTime = m_SystemTime; + m_IsFinishingBroadcast = false; + + m_ClientWorldTime = 0; + m_ClientProxyTime = 0; + m_ClientTimeScale = 1; + + m_CurrentLoss = 0; + + if (m_Server->IsDemoFile()) + { + if (m_Director) { + m_System->RemoveModule(m_Director); + m_Director = nullptr; + } + } + else if (GetDelay() > 0) + { + if (CheckDirectorModule()) { + m_Director->NewGame(m_World, this); + } + + m_ClientWorldTime = m_World->GetTime() - m_ClientDelay; + } + else + { + if (m_Director) { + m_System->RemoveModule(m_Director); + m_Director = nullptr; + } + + if (m_IsMaster) + { + if (m_System->AddModule(&m_NullDirector, "nulldirector")) { + m_Director = &m_NullDirector; + m_NullDirector.NewGame(m_World, this); + m_System->DPrintf("Using zero delay director.\n"); + } + else { + m_System->Errorf("Proxy::NewGameStarted: failed to add null director module.\n"); + } + } + } + + m_Server->SetDirector(m_Director); + + char newTitle[4096]; + _snprintf(newTitle, sizeof(newTitle), "HLTV - %s %s", + m_Server->IsDemoFile() ? m_Server->GetDemoFileName() : m_Server->GetAddress()->ToString(), + m_World->GetLevelName()); + + m_System->SetTitle(newTitle); +} + +void Proxy::RunClocks() +{ + double lastClockTime = m_LastClockUpdateTime; + m_LastClockUpdateTime = m_SystemTime; + + if (m_World->IsPaused()) { + return; + } + + double realTimeDiff = (m_SystemTime - lastClockTime) * m_ClientTimeScale; + m_ClientProxyTime += realTimeDiff; + m_ClientWorldTime += realTimeDiff; + + if (!m_IsFinishingBroadcast) + { + frame_t *start = m_World->GetFirstFrame(); + if (m_ClientWorldTime > m_World->GetTime()) { + m_ClientWorldTime = m_World->GetTime() - m_ClientDelay; + return; + } + + if (start->time > (m_ClientWorldTime + m_ClientDelay)) + { + m_System->DPrintf("Proxy::RunClocks: forcing client delay (1).\n"); + m_ClientWorldTime = start->time - m_ClientDelay; + return; + } + + if (m_World->GetTime() - m_ClientDelay > (m_ClientWorldTime + 10)) { + m_System->DPrintf("Proxy::RunClocks: forcing client delay (2).\n"); + m_ClientWorldTime = m_World->GetTime() - m_ClientDelay; + return; + } + } +} + +void Proxy::DisconnectClients(const char *reason) +{ + IClient *client = (IClient *)m_Clients.GetFirst(); + while (client) + { + client->Disconnect(reason); + client = (IClient *)m_Clients.GetNext(); + } + + m_DemoClient.Disconnect(reason); +} + +void Proxy::UpdateInfoMessages() +{ + char ipport[32]; + int proxies, slots, spectators; + serverinfo_t *serverInfo = m_World->GetServerInfo(); + + m_Status.GetLocalStats(proxies, slots, spectators); + _snprintf(ipport, sizeof(ipport), "%s:%i", m_Network->GetLocalAddress()->ToBaseString(), m_Socket->GetPort()); + + m_InfoInfo.Clear(); + if (m_World->IsActive()) + { + // deprecated goldsrc response + m_InfoInfo.WriteLong(CONNECTIONLESS_HEADER); // connectionless header + m_InfoInfo.WriteByte(S2A_INFO); // data header + m_InfoInfo.WriteString(ipport); // server address + m_InfoInfo.WriteString(m_World->GetHostName()); // hostname + m_InfoInfo.WriteString(serverInfo->map); // mapname + m_InfoInfo.WriteString(serverInfo->gamedir); // gamedir + m_InfoInfo.WriteString(serverInfo->description); // gamename + m_InfoInfo.WriteByte(min(spectators, MAX_PROXY_CLIENTS)); // players + m_InfoInfo.WriteByte(min(slots, MAX_PROXY_CLIENTS)); // maxplayers + m_InfoInfo.WriteByte(PROTOCOL_VERSION); // protocol + + if (spectators >= MAX_PROXY_CLIENTS || slots >= MAX_PROXY_CLIENTS) + { + m_InfoInfo.WriteLong(spectators); + m_InfoInfo.WriteLong(slots); + } + } + + m_InfoDetails.Clear(); + if (m_World->IsActive()) + { + m_InfoDetails.WriteLong(CONNECTIONLESS_HEADER); // connectionless header + m_InfoDetails.WriteByte(S2A_INFO_DETAILED); // data header (detailed mode) + m_InfoDetails.WriteString(ipport); // server address + m_InfoDetails.WriteString(m_World->GetHostName()); // hostname + m_InfoDetails.WriteString(serverInfo->map); // mapname + m_InfoDetails.WriteString(serverInfo->gamedir); // gamedir + m_InfoDetails.WriteString(serverInfo->description); // gamename + m_InfoDetails.WriteByte(min(spectators, MAX_PROXY_CLIENTS)); // players + m_InfoDetails.WriteByte(min(slots, MAX_PROXY_CLIENTS)); // maxplayers + m_InfoDetails.WriteByte(PROTOCOL_VERSION); // protocol + + m_InfoDetails.WriteByte(GetServerType(HLST_TV)[0]); // server type (Indicates the type of server: HLTV Server) + m_InfoDetails.WriteByte(GetServerOS()[0]); // server os (Indicates the operating system of the server) + m_InfoDetails.WriteByte(IsPasswordProtected()); // password + + // whether the game is a mod + // 0: Half-Life + // 1: Half-Life mod + m_InfoDetails.WriteByte(serverInfo->mod); // game is mod + + if (serverInfo->mod) + { + m_InfoDetails.WriteString(serverInfo->url_info); // url to mod website + m_InfoDetails.WriteString(serverInfo->url_dl); // url to download the mod + m_InfoDetails.WriteString(serverInfo->hlversion); + m_InfoDetails.WriteLong(serverInfo->ver); // version of mod installed on server + m_InfoDetails.WriteLong(serverInfo->size); // space (in bytes) the mod takes up + m_InfoDetails.WriteByte(serverInfo->svonly); // the type of mod + m_InfoDetails.WriteByte(serverInfo->cldll); // whether mod uses its own DLL + } + + m_InfoDetails.WriteByte(0); // specifies whether the server uses VAC + + if (spectators >= MAX_PROXY_CLIENTS || slots >= MAX_PROXY_CLIENTS) + { + m_InfoDetails.WriteLong(spectators); + m_InfoDetails.WriteLong(slots); + } + } + + m_InfoRules.Clear(); + if (m_World->IsActive()) + { + m_InfoRules.WriteLong(CONNECTIONLESS_HEADER); // connectionless header + m_InfoRules.WriteByte(S2A_RULES); // rules query are multi-packeted + m_InfoRules.WriteShort(5); // number of rules in the response + + // HLTV Rules + m_InfoRules.WriteString("GameServer"); + m_InfoRules.WriteString(GetDescription()); + + m_InfoRules.WriteString("HLTVProxy"); + m_InfoRules.WriteString(COM_VarArgs("%i", m_IsMaster ? 1 : 2)); + + m_InfoRules.WriteString("HLTVDelay"); + m_InfoRules.WriteString(COM_VarArgs("%.1f", m_ClientDelay)); + + m_InfoRules.WriteString("HLTVChat"); + m_InfoRules.WriteString(COM_VarArgs("%i", m_ChatMode)); + + m_InfoRules.WriteString("HLTVDemo"); + m_InfoRules.WriteString(m_DemoClient.IsActive() ? m_DemoClient.GetDemoFile()->GetFileName() : "none"); + } + + m_InfoPlayers.Clear(); + + InfoString info(2048); + if (m_World->GetNumPlayers() > 0) + { + m_InfoPlayers.WriteLong(CONNECTIONLESS_HEADER); // connectionless header + m_InfoPlayers.WriteByte(S2A_PLAYERS); // data header (players info) + m_InfoPlayers.WriteByte(0); // number of players whose information was gathered + + int count = 0; + for (int i = 0; i < m_World->GetMaxClients(); i++) + { + if (!m_World->GetPlayerInfoString(i, &info)) { + continue; + } + + m_InfoPlayers.WriteByte(++count); // index of player chunk starting from 0 + m_InfoPlayers.WriteString(info.ValueForKey("name")); // name of the player. + m_InfoPlayers.WriteLong(0); // player's score (usually "frags" or "kills") + m_InfoPlayers.WriteFloat(1); // time (in seconds) player has been connected to the server + } + + m_InfoPlayers.m_Data[5] = count; + } + + CreateServerInfoString(&info); + + m_InfoString.Clear(); + m_InfoString.WriteLong(CONNECTIONLESS_HEADER); // connectionless header + m_InfoString.WriteString("infostringresponse"); // data header (response on infostring) + m_InfoString.WriteString(info.GetString()); // info + + m_NextInfoMessagesUpdate = m_SystemTime + 1; +} + +void Proxy::SetName(char *newName) +{ + strcopy(m_Name, newName); +} + +const char *Proxy::GetDescription() +{ + if (m_Server->IsDemoFile()) { + return m_Server->GetDemoFileName(); + } + + if (IsPublicGame()) { + return m_World->GetGameServerAddress()->ToString(); + } + + return "Private Server"; +} diff --git a/rehlds/HLTV/Proxy/src/Proxy.h b/rehlds/HLTV/Proxy/src/Proxy.h new file mode 100644 index 0000000..2471bec --- /dev/null +++ b/rehlds/HLTV/Proxy/src/Proxy.h @@ -0,0 +1,377 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "BaseSystemModule.h" +#include "common/NetAddress.h" + +#include "ObjectList.h" +#include "DemoClient.h" +#include "Status.h" +#include "Master.h" +#include "Director.h" +#include "DirectorNull.h" + +class IWorld; +class IServer; +class INetwork; +class IDirector; +class IBaseSystem; + +#define MAX_NAME 32 +#define MAX_PROXY_RATE 20000 +#define MAX_PROXY_UPDATERATE 40 + +#define PROXY_CHALLENGE_LIFE 40.0f +#define PROXY_PRIVATE 0x8000 +#define PROXY_VERSION "1.1.2.0" +#define PROXY_DEFAULT_PORT "27020" + +// TODO: it is necessary to unify with rehlsdk +typedef struct textmessage_s { + int effect; + byte r1, g1, b1, a1; // 2 colors for effects + byte r2, g2, b2, a2; + float x; + float y; + float fadein; + float fadeout; + float holdtime; + float fxtime; + char text[80]; +} textmessage_t; + +class Proxy: public IProxy, public BaseSystemModule { +public: + Proxy() {} + virtual ~Proxy() {} + + bool Init(IBaseSystem *system, int serial, char *name); + void RunFrame(double time); + void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data); + void ExecuteCommand(int commandID, char *commandLine); + char *GetStatusLine(); + char *GetType(); + void ShutDown(); + + void Reset(); + void Broadcast(byte *data, int length, int groupType, bool isReliable); + void IncreaseCheering(int votes); + void ChatCommentator(char *nick, char *text); + void ChatSpectator(char *nick, char *text); + void CountLocalClients(int &spectators, int &proxies); + void ParseStatusMsg(BitBuffer *stream); + void ParseStatusReport(NetAddress *from, BitBuffer *stream); + bool ProcessConnectionlessMessage(NetAddress *from, BitBuffer *stream); + resource_t *AddResource(char *fileName, resourcetype_t type, char *asFileName = nullptr); + bool IsMaster(); + bool IsLanOnly(); + bool IsActive(); + bool IsPublicGame(); + bool IsPasswordProtected(); + bool IsStressed(); + void SetDelay(float seconds); + void SetClientTime(double time, bool relative); + void SetClientTimeScale(float scale); + void SetMaxRate(int rate); + void SetMaxLoss(float maxloss); + void SetMaxUpdateRate(int updaterate); + bool SetMaxClients(int number); + void SetRegion(unsigned char region); + float GetDelay(); + double GetSpectatorTime(); + double GetProxyTime(); + IObjectContainer *GetClients(); + IWorld *GetWorld(); + IServer *GetServer(); + IDirector *GetDirector(); + INetSocket *GetSocket(); + ChatMode_e GetChatMode(); + void GetStatistics(int &proxies, int &slots, int &spectators); + int GetMaxRate(); + int GetMaxClients(); + int GetMaxUpdateRate(); + resource_t *GetResource(char *fileName); + int GetDispatchMode(); + unsigned char GetRegion(); + bool WriteSignonData(int type, BitBuffer *stream); + + void ReconnectClients(); + void ExecuteRcon(NetAddress *from, char *command); + void SendRcon(NetAddress *to, unsigned int challenge); + void ReplyServiceChallenge(NetAddress *to, char *type); + void ReplyListen(NetAddress *to); + void RejectConnection(NetAddress *adr, bool badPassword, const char *fmt, ...); + void ReplyConnect(NetAddress *to, int protocol, int challenge, char *protinfo, char *userinfo); + void ReplyRules(NetAddress *to); + void ReplyPlayers(NetAddress *to); + void ReplyInfo(NetAddress *to, bool detailed); + void ReplyInfoString(NetAddress *to); + void ReplyChallenge(NetAddress *to); + void ReplyPing(NetAddress *to); + + void UpdateStatusLine(); + void DispatchClient(NetAddress *client, NetAddress *proxy); + bool IsValidPassword(int type, char *pw); + void WriteHUDMsg(textmessage_t *msg, BitBuffer *stream); + + typedef struct loopcmd_s { + int id; + float interval; + float lastTime; + char command[255]; + } loopcmd_t; + + void ExecuteLoopCommands(); + unsigned int GetChallengeNumber(NetAddress *host); + bool CheckChallenge(NetAddress *from, unsigned int challengeNumber); + void CreateServerInfoString(InfoString *info); + bool CheckDirectorModule(); + void RunClocks(); + void NewGameStarted(); + void NewServerConnection(); + void BroadcastPaused(bool paused); + void BroadcastRetryMessage(); + void StopBroadcast(const char *message); + char *GetModVersion(char *gamedir); + void DisconnectClients(const char *reason); + void FreeResource(resource_t *resource); + void ClearResources(); + resource_t *LoadResourceFromFile(char *fileName, resourcetype_t type); + bool IsBanned(NetAddress *adr); + void UpdateInfoMessages(); + void SetName(char *newName); + +private: + enum LocalCommandIDs { + CMD_ID_RCON = 1, + CMD_ID_RCONPASSWORD, + CMD_ID_RCONADDRESS, + CMD_ID_SAY, + CMD_ID_MSG, + CMD_ID_CLIENTS, + CMD_ID_KICK, + CMD_ID_CHATMODE, + CMD_ID_PUBLICGAME, + CMD_ID_OFFLINETEXT, + CMD_ID_ADMINPASSWORD, + CMD_ID_SIGNONCOMMANDS, + CMD_ID_SPECTATORPASSWORD, + CMD_ID_DISPATCHMODE, + CMD_ID_CHEERINGTHRESHOLD, + CMD_ID_INFORMPLAYERS, + CMD_ID_PING, + CMD_ID_PROXYPASSWORD, + CMD_ID_MAXRATE, + CMD_ID_LOOPCMD, + CMD_ID_MAXCLIENTS, + CMD_ID_DISCONNECT, + CMD_ID_LOCALMSG, + CMD_ID_CONNECT, + CMD_ID_PLAYDEMO, + CMD_ID_DELAY, + CMD_ID_STOP, + CMD_ID_RECORD, + CMD_ID_STOPRECORDING, + CMD_ID_SERVERCMD, + CMD_ID_CLIENTCMD, + CMD_ID_BLOCKVOICE, + CMD_ID_NAME, + CMD_ID_UPDATERATE, + CMD_ID_RATE, + CMD_ID_ADDRESOURCE, + CMD_ID_RESOURCES, + CMD_ID_BANNERFILE, + CMD_ID_BANN, + CMD_ID_ADDFAKECLIENTS, + CMD_ID_RETRY, + CMD_ID_PLAYERS, + CMD_ID_AUTORETRY, + CMD_ID_SERVERPASSWORD, + CMD_ID_STATUS, + CMD_ID_HOSTNAME, + CMD_ID_MAXQUERIES, + CMD_ID_CLEARBANNS, + CMD_ID_MAXLOSS, + CMD_ID_PROTOCOL, + CMD_ID_REGION + }; + + void CMD_Rcon(char *cmdLine); + void CMD_ServerCmd(char *cmdLine); + void CMD_ClientCmd(char *cmdLine); + void CMD_RconPassword(char *cmdLine); + void CMD_RconAddress(char *cmdLine); + void CMD_Say(char *cmdLine); + void CMD_Msg(char *cmdLine); + void CMD_Clients(char *cmdLine); + void CMD_Kick(char *cmdLine); + void CMD_ChatMode(char *cmdLine); + void CMD_PublicGame(char *cmdLine); + void CMD_OffLineText(char *cmdLine); + void CMD_AdminPassword(char *cmdLine); + void CMD_SignOnCommands(char *cmdLine); + void CMD_SpectatorPassword(char *cmdLine); + void CMD_DispatchMode(char *cmdLine); + void CMD_CheeringThreshold(char *cmdLine); + void CMD_InformPlayers(char *cmdLine); + void CMD_Ping(char *cmdLine); + void CMD_ProxyPassword(char *cmdLine); + void CMD_MaxRate(char *cmdLine); + void CMD_MaxUpdateRate(char *cmdLine); + void CMD_LoopCmd(char *cmdLine); + void CMD_MaxClients(char *cmdLine); + void CMD_LocalMsg(char *cmdLine); + void CMD_Connect(char *cmdLine); + void CMD_Disconnect(char *cmdLine); + void CMD_PlayDemo(char *cmdLine); + void CMD_Delay(char *cmdLine); + void CMD_Stop(char *cmdLine); + void CMD_Record(char *cmdLine); + void CMD_StopRecording(char *cmdLine); + void CMD_BlockVoice(char *cmdLine); + void CMD_Name(char *cmdLine); + void CMD_Rate(char *cmdLine); + void CMD_Updaterate(char *cmdLine); + void CMD_HostName(char *cmdLine); + void CMD_AddResource(char *cmdLine); + void CMD_Resources(char *cmdLine); + void CMD_BannerFile(char *cmdLine); + void CMD_Bann(char *cmdLine); + void CMD_AddFakeClients(char *cmdLine); + void CMD_Retry(char *cmdLine); + void CMD_AutoRetry(char *cmdLine); + void CMD_ServerPassword(char *cmdLine); + void CMD_Status(char *cmdLine); + void CMD_MaxQueries(char *cmdLine); + void CMD_Players(char *cmdLine); + void CMD_ClearBanns(char *cmdLine); + void CMD_MaxLoss(char *cmdLine); + void CMD_Protocol(char *cmdLine); + void CMD_Region(char *cmdLine); + + struct LocalCommandID_s { + char *name; + LocalCommandIDs id; + void (Proxy::*pfnCmd)(char *cmdLine); + }; + static LocalCommandID_s m_LocalCmdReg[]; + const char *GetDescription(); + +protected: + friend class DemoClient; + friend class Status; + friend class Master; + friend class Director; + + INetwork *m_Network; + IWorld *m_World; + IDirector *m_Director; + IServer *m_Server; + ObjectList m_Clients; + + DemoClient m_DemoClient; + Status m_Status; + Master m_Master; + Director m_DefaultDirector; + DirectorNull m_NullDirector; + INetSocket *m_Socket; + + typedef struct challenge_s { + NetAddress adr; + unsigned int challenge; + float time; + } challenge_t; + + // MAX_CHALLENGES is made large to prevent a denial + // of service attack that could cycle all of them + // out before legitimate users connected + enum { MAX_CHALLENGES = 1024 }; + challenge_t m_Challenges[MAX_CHALLENGES]; + + bool m_IsMaster; + bool m_IsFinishingBroadcast; + bool m_IsReconnectRequested; + + int m_MaxRate; + int m_MaxUpdateRate; + + ChatMode_e m_ChatMode; + int m_MaxClients; + float m_MaxQueries; + int m_MaxFrameQueries; + int m_MaxSeenClients; + + NetAddress m_RconAddress; + char m_RconPassword[128]; + char m_AdminPassword[128]; + char m_ProxyPassword[128]; + char m_SpectatorPassword[128]; + char m_LastRconCommand[1024]; + char m_OffLineText[128]; + char m_SignonCommands[256]; + + ObjectList m_LoopCommands; + bool m_PublicGame; + + enum DispatchMode_e : int { + DISPATCH_OFF, // Won't redirect any clients. + DISPATCH_BALANCE, // Will redirect connecting clients to other proxies balancing work load between all proxies. + DISPATCH_ALL, // Any spectator clients will be redirected, so this proxy serves only as dispatcher. + }; + DispatchMode_e m_DispatchMode; + + float m_ClientDelay; + float m_ClientTimeScale; + double m_ClientWorldTime; + double m_ClientProxyTime; + + double m_LastClockUpdateTime; + float m_CheeringThreshold; + float m_LastCheeringUpdate; + int m_CheeringPlayers; + resource_t *m_BannerTGA; + ObjectList m_Resources; + double m_NextStatusUpdateTime; + float m_FPS; + float m_MaxLoss; + float m_CurrentLoss; + ObjectList m_BannList; + unsigned char m_Region; + + textmessage_t m_LocalMessage; + textmessage_t m_CommentatorMessage; + + double m_NextInfoMessagesUpdate; + BitBuffer m_InfoRules; + BitBuffer m_InfoPlayers; + BitBuffer m_InfoDetails; + BitBuffer m_InfoInfo; + BitBuffer m_InfoString; +}; diff --git a/rehlds/HLTV/Proxy/src/ProxyClient.cpp b/rehlds/HLTV/Proxy/src/ProxyClient.cpp new file mode 100644 index 0000000..da20dd7 --- /dev/null +++ b/rehlds/HLTV/Proxy/src/ProxyClient.cpp @@ -0,0 +1,317 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +void ProxyClient::ShutDown() +{ + char *clientTypeString[] = { "Spectator", "Relay Proxy", "Director", "Commentator", "Fake Client" }; + if (m_State == MODULE_DISCONNECTED) { + return; + } + + m_System->Printf("%s disconnected (%s)\n", clientTypeString[m_ClientType], m_ClientChannel.m_remote_address.ToString()); + m_Proxy->GetClients()->Remove(this); + + BaseClient::ShutDown(); + delete this; +} + +bool ProxyClient::Init(IBaseSystem *system, int serial, char *name) +{ + BaseClient::Init(system, serial, name); + + m_ClientType = TYPE_CLIENT; + m_ChatEnabled = true; + + m_LastChatTime = 0; + m_LastCheerTime = 0; + m_NextDecalTime = 0; + + return true; +} + +ProxyClient::LocalCommandID_s ProxyClient::m_LocalCmdReg[] = { + { "cheer", CMD_ID_CHEER, &ProxyClient::CMD_Cheer }, + { "say", CMD_ID_SAY, &ProxyClient::CMD_Say }, + { "joingame", CMD_ID_JOINGAME, &ProxyClient::CMD_JoinGame }, + { "status", CMD_ID_STATUS, &ProxyClient::CMD_Status }, + { "ignoremsg", CMD_ID_IGNOREMSG, &ProxyClient::CMD_IgnoreMsg }, +}; + +bool ProxyClient::ProcessStringCmd(char *string) +{ + if (BaseClient::ProcessStringCmd(string)) { + return true; + } + + TokenLine cmdLine; + if (!cmdLine.SetLine(string)) { + m_System->Printf("WARNING! ProxyClient::ProcessStringCmd: string command too long.\n"); + return true; + } + + char *cmd = cmdLine.GetToken(0); + for (auto& local_cmd : m_LocalCmdReg) + { + if (!_stricmp(local_cmd.name, cmd)) { + (this->*local_cmd.pfnCmd)(&cmdLine); + return true; + } + } + + if (m_ClientType < TYPE_COMMENTATOR) { + m_System->DPrintf("Unkown client command: \"%s\"\n", cmd); + } + + m_System->DPrintf("Unkown director command: \"%s\"\n", cmd); + return false; +} + +void ProxyClient::CMD_Cheer(TokenLine *cmd) +{ + if (m_SystemTime <= m_LastCheerTime + 6) { + return; + } + + m_LastCheerTime = float(m_SystemTime); + m_Proxy->IncreaseCheering(1); +} + +void ProxyClient::CMD_Say(TokenLine *cmd) +{ + char *chatText = (cmd->CountToken() > 2) ? cmd->GetRestOfLine(1) : cmd->GetToken(1); + if (m_ClientType == TYPE_COMMENTATOR) { + m_Proxy->ChatCommentator(nullptr, chatText); + return; + } + + if (m_ClientType == TYPE_PROXY && m_Proxy->GetChatMode() == CHAT_GLOBAL) { + m_Proxy->ChatSpectator("Unknown", chatText); + return; + } + + if (m_SystemTime >= m_LastChatTime + 6) { + m_Proxy->ChatSpectator(m_ClientName, chatText); + m_LastChatTime = float(m_SystemTime); + return; + } +} + +void ProxyClient::CMD_JoinGame(TokenLine *cmd) +{ + if (m_Proxy->GetServer()->IsDemoFile()) { + PrintfToClient("Proxy is replaying demo.\n"); + return; + } + + if (m_Proxy->IsPublicGame()) + { + char string[64]; + _snprintf(string, sizeof(string), "connect %s\n", m_World->GetGameServerAddress()->ToString()); + + m_ClientChannel.m_reliableStream.WriteByte(svc_stufftext); + m_ClientChannel.m_reliableStream.WriteString(string); + } + + PrintfToClient("Joining game is not allowed.\n"); +} + +void ProxyClient::CMD_Status(TokenLine *cmd) +{ + PrintfToClient("--- HLTV Status ---\n"); + + if (m_Proxy->GetServer()->IsDemoFile()) { + PrintfToClient("Replay demo file %s\n", m_Proxy->GetServer()->GetDemoFileName()); + } + else if (m_Proxy->IsPublicGame()) { + PrintfToClient("Game Server: %s\n", m_World->GetGameServerAddress()->ToString()); + } + else { + PrintfToClient("Private game server\n"); + } + + int proxies, spectators, slots; + m_Proxy->GetStatistics(proxies, slots, spectators); + PrintfToClient("Global HLTV stats: spectators %i, slots %i, proxies %i\n", spectators, slots, proxies); +} + +void ProxyClient::CMD_IgnoreMsg(TokenLine *cmd) +{ + if (cmd->CountToken() != 2) { + return; + } + + m_ChatEnabled = !atoi(cmd->GetToken(1)); + PrintfToClient("Global HLTV stats: spectators %i, slots %i, proxies %i\n", m_ChatEnabled ? "Spectator chat enabled.\n" : "Spectator chat disabled.\n"); +} + +void ProxyClient::UpdateUserInfo(char *userinfostring) +{ + BaseClient::UpdateUserInfo(userinfostring); + + if (m_ClientType > TYPE_DEMO) { + m_System->DPrintf("WARNING! Client::UpdateUserInfo: invalid client ype %i\n", m_ClientType); + m_ClientType = TYPE_CLIENT; + } + + if (m_ClientType) { + return; + } + + // clamp rate + if (m_ClientChannel.GetRate() > m_Proxy->GetMaxRate()) { + m_ClientChannel.SetRate(m_Proxy->GetMaxRate()); + } + + if (m_ClientType == TYPE_CLIENT) + { + if (m_ClientChannel.GetUpdateRate() > m_Proxy->GetMaxUpdateRate()) { + m_ClientChannel.SetUpdateRate(m_Proxy->GetMaxUpdateRate()); + } + } +} + +void ProxyClient::ParseHLTV(NetPacket *packet) +{ + unsigned char cmd = packet->data.ReadByte(); + if (cmd != HLTV_STATUS) { + m_System->Printf("WARNING! unknown HLTV client msg %i\n", cmd); + return; + } + + if (m_ClientType != TYPE_PROXY) { + m_System->DPrintf("WARNING! HLTV status data from spectator client\n"); + packet->data.SkipBytes(12); + return; + } + + m_Proxy->ParseStatusReport(GetAddress(), &packet->data); +} + +void ProxyClient::ReplySpawn(int spawncount, int crcMap) +{ + BaseClient::ReplySpawn(spawncount, crcMap); + + if (m_ClientType == TYPE_PROXY) { + m_VoiceQuery = false; + } + + m_Proxy->WriteSignonData(m_ClientType, &m_ClientChannel.m_reliableStream); +} + +void ProxyClient::SendDatagram() +{ + if (m_Proxy->GetDelay() > 0) + { + double worldTime = m_Proxy->GetSpectatorTime(); + double proxyTime = m_Proxy->GetProxyTime(); + + frame_t *frame = m_World->GetFrameByTime(worldTime); + if (!frame) { + return; + } + + if (m_ClientChannel.GetIdleTime() > 2) { + m_ClientChannel.m_unreliableStream.WriteByte(svc_centerprint); + m_ClientChannel.m_unreliableStream.WriteString((frame->seqnr > 1) ? "Game pending..." : "Buffering game..."); + } + + double time = proxyTime - (worldTime - frame->time); + WriteDatagram(time, frame); + return; + } + + frame_t *frame = m_World->GetLastFrame(); + if (frame) + { + if (m_ClientChannel.GetIdleTime() > 2) { + m_ClientChannel.m_unreliableStream.WriteByte(svc_centerprint); + m_ClientChannel.m_unreliableStream.WriteString("Game pending..."); + } + + WriteDatagram(frame->time, frame); + } +} + +bool ProxyClient::HasChatEnabled() +{ + return m_ChatEnabled; +} + +void ProxyClient::ParseVoiceData(NetPacket *packet) +{ + int nDataLength = packet->data.ReadShort(); + BitBuffer voiceMsg(nDataLength + 8); + + if (m_ClientType != TYPE_COMMENTATOR) { + packet->data.SkipBytes(nDataLength); + return; + } + + if (nDataLength > MAX_VOICEDATA_LEN) { + Disconnect("Invalid voice message.\n"); + return; + } + + voiceMsg.WriteByte(svc_voicedata); + voiceMsg.WriteByte(m_World->GetSlotNumber()); + voiceMsg.WriteShort(nDataLength); + voiceMsg.WriteBuf(packet->data.CurrentByte(), nDataLength); + + m_Proxy->Broadcast(voiceMsg.GetData(), voiceMsg.CurrentSize(), GROUP_PROXY | GROUP_DEMO | GROUP_UNKNOWN | GROUP_VOICE, false); + packet->data.SkipBytes(nDataLength); +} + +void ProxyClient::DownloadFile(char *fileName) +{ + if (!fileName || !fileName[0]) + return; + + const char szMD5[] = "!MD5"; + if (strstr(fileName, "..") || + // ignore customization's + (strlen(fileName) == 36 && !_strnicmp(fileName, szMD5, sizeof(szMD5) - 1))) + { + DownloadFailed(fileName); + return; + } + + resource_t *resource = m_Proxy->GetResource(fileName); + if (resource) { + m_ClientChannel.CreateFragmentsFromBuffer(resource->data, resource->nDownloadSize, FRAG_FILE_STREAM, fileName); + return; + } + + if (m_ClientChannel.CreateFragmentsFromFile(fileName)) { + m_ClientChannel.FragSend(); + return; + } + + DownloadFailed(fileName); +} diff --git a/rehlds/HLTV/Proxy/src/ProxyClient.h b/rehlds/HLTV/Proxy/src/ProxyClient.h new file mode 100644 index 0000000..7f1bfcf --- /dev/null +++ b/rehlds/HLTV/Proxy/src/ProxyClient.h @@ -0,0 +1,82 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "common/BaseClient.h" + +class IProxy; +class NetPacket; +class IBaseSystem; + +class ProxyClient: public BaseClient { +public: + ProxyClient(IProxy *proxy) : m_Proxy(proxy) {} + virtual ~ProxyClient() {} + + bool Init(IBaseSystem *system, int serial, char *name); + void ShutDown(); + bool HasChatEnabled(); + bool ProcessStringCmd(char *string); + void ReplySpawn(int spawncount, int crcMap); + void UpdateUserInfo(char *userinfostring = nullptr); + void ParseVoiceData(NetPacket *packet); + void DownloadFile(char *fileName); + void SendDatagram(); + void ParseHLTV(NetPacket *packet); + +private: + enum LocalCommandIDs { + CMD_ID_CHEER = 1, + CMD_ID_SAY, + CMD_ID_JOINGAME, + CMD_ID_STATUS, + CMD_ID_IGNOREMSG + }; + + void CMD_Cheer(TokenLine *cmd); + void CMD_Say(TokenLine *cmd); + void CMD_JoinGame(TokenLine *cmd); + void CMD_Status(TokenLine *cmd); + void CMD_IgnoreMsg(TokenLine *cmd); + + struct LocalCommandID_s { + char *name; + LocalCommandIDs id; + void (ProxyClient::*pfnCmd)(TokenLine *cmd); + }; + static LocalCommandID_s m_LocalCmdReg[]; + +protected: + IProxy *m_Proxy; + + float m_LastChatTime; + float m_LastCheerTime; + float m_NextDecalTime; + bool m_ChatEnabled; +}; diff --git a/rehlds/HLTV/Proxy/src/Status.cpp b/rehlds/HLTV/Proxy/src/Status.cpp new file mode 100644 index 0000000..0336c0b --- /dev/null +++ b/rehlds/HLTV/Proxy/src/Status.cpp @@ -0,0 +1,318 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +bool Status::Init(IBaseSystem *system, int serial, char *name) +{ + BaseSystemModule::Init(system, serial, name); + + SetName("status"); + + m_Proxies.Init(); + m_System->RegisterCommand("proxies", this, CMD_ID_PROXIES); + + Reset(); + + m_State = MODULE_RUNNING; + m_System->DPrintf("Status module initialized.\n"); + + return true; +} + +void Status::RunFrame(double time) +{ + BaseSystemModule::RunFrame(time); + + if (m_MaxNumberOfSpectators < m_NumberOfSpectators) { + m_MaxNumberOfSpectators = m_NumberOfSpectators; + } + + if (!m_Proxy->IsMaster() || !m_Proxy->IsActive()) + return; + + if (m_SystemTime > m_NextUpdateTime) + { + GetLocalStats(m_NumberOfProxies, m_NumberOfSlots, m_NumberOfSpectators); + SendStatusUpdate(); + + m_Proxy->GetServer()->SetUserInfo("hspecs", COM_VarArgs("%u", m_NumberOfSpectators)); + m_Proxy->GetServer()->SetUserInfo("hslots", COM_VarArgs("%u", m_NumberOfSlots)); + + m_NextUpdateTime = float(m_SystemTime) + 16.f; + } +} + +void Status::ExecuteCommand(int commandID, char *commandLine) +{ + if (commandID == CMD_ID_PROXIES) { + CMD_Proxies(commandLine); + return; + } + + m_System->Printf("ERROR! Status::ExecuteCommand: unknown command ID %i.\n", commandID); +} + +void Status::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) + return; + + m_Proxies.Clear(true); + m_System->Printf("Status module shutdown.\n"); + + BaseSystemModule::ShutDown(); +} + +void Status::GetGlobalStats(int &proxies, int &slots, int &spectators) +{ + proxies = m_NumberOfProxies; + slots = m_NumberOfSlots; + spectators = m_NumberOfSpectators; +} + +void Status::SetProxy(IProxy *proxy) +{ + m_Proxy = proxy; +} + +void Status::SendStatusUpdate() +{ + BitBuffer buffer(128); + + buffer.WriteByte(svc_hltv); + buffer.WriteByte(HLTV_STATUS); + + buffer.WriteWord(m_NumberOfProxies); + buffer.WriteLong(m_NumberOfSlots); + buffer.WriteLong(m_NumberOfSpectators); + + m_Proxy->Broadcast(buffer.GetData(), buffer.CurrentSize(), GROUP_PROXY, true); + buffer.FastClear(); + + DirectorCmd cmd; + cmd.SetStatusData(m_NumberOfSlots, m_NumberOfSpectators, m_NumberOfProxies); + cmd.WriteToStream(&buffer); + + // group spectators + m_Proxy->Broadcast(buffer.GetData(), buffer.CurrentSize(), GROUP_CLIENT | GROUP_DEMO | GROUP_UNKNOWN, false); + buffer.FastClear(); +} + +void Status::SetName(char *newName) +{ + strcopy(m_Name, newName); +} + +char *Status::GetType() +{ + return STATUS_INTERFACE_VERSION; +} + +char *Status::GetStatusLine() +{ + static char string[256]; + _snprintf(string, sizeof(string), "Global Status: Proxies %i, Slots %i, Spectators %i (max %i)\n", + m_NumberOfProxies, m_NumberOfSlots, + m_NumberOfSpectators, m_MaxNumberOfSpectators); + + return string; +} + +void Status::Reset() +{ + m_Proxies.Clear(true); + + m_NumberOfProxies = 0; + m_NumberOfSlots = 0; + m_NumberOfSpectators = 0; + m_MaxNumberOfSpectators = 0; + m_NextUpdateTime = 0; +} + +void Status::ParseStatusMsg(BitBuffer *stream) +{ + if (m_Proxy->IsMaster()) { + m_System->Printf("WARNING! Status::ParseStatusMsg: unexpected HLTV_STATUS message as Master.\n"); + stream->SkipBytes(10); + return; + } + + m_NumberOfProxies = stream->ReadWord(); + m_NumberOfSlots = stream->ReadLong(); + m_NumberOfSpectators = stream->ReadLong(); + + ReplyStatusReport(); + SendStatusUpdate(); +} + +void Status::ReplyStatusReport() +{ + BitBuffer buf(128); + + int slots, proxies, spectators; + GetLocalStats(proxies, slots, spectators); + + if (!m_Proxy->IsPasswordProtected()) + { + if (!m_Proxy->GetDispatchMode()) { + slots = m_Proxy->GetMaxClients(); + } + else if (m_Proxy->IsStressed()) { + proxies |= PROXY_PRIVATE; + } + } + + buf.WriteByte(1); + buf.WriteWord(proxies); + buf.WriteLong(slots); + buf.WriteLong(spectators); + + m_Proxy->GetServer()->SendHLTVCommand(&buf); +} + +int Status::GetMaxSpectatorNumber() +{ + return m_MaxNumberOfSpectators; +} + +void Status::ParseStatusReport(NetAddress *from, BitBuffer *stream) +{ + int proxies = stream->ReadWord(); + int slots = stream->ReadLong(); + int spectators = stream->ReadLong(); + + bool isPrivate = false; + if (proxies & PROXY_PRIVATE) { + proxies &= ~PROXY_PRIVATE; + isPrivate = true; + } + + proxyInfo_t *proxy = (proxyInfo_t *)m_Proxies.GetFirst(); + while (proxy) + { + if (from->Equal(&proxy->address)) { + break; + } + + proxy = (proxyInfo_t *)m_Proxies.GetNext(); + } + + // couldn't find it? + // allocate for + if (!proxy) + { + proxy = (proxyInfo_t *)Mem_ZeroMalloc(sizeof(proxyInfo_t)); + if (!proxy) { + m_System->Printf("WARNING! Status::ParseStatusReport: not enough memory to increase proxy list.\n"); + return; + } + + proxy->address.FromNetAddress(from); + m_Proxies.Add(proxy); + } + + proxy->slots = slots; + proxy->spectators = spectators; + proxy->proxies = proxies; + proxy->time = float(m_SystemTime); + proxy->isPrivate = isPrivate; + + float ratio = (slots > 0 && !isPrivate) ? float(spectators / slots) : 1; + m_Proxies.ChangeKey(proxy, ratio); +} + +void Status::GetLocalStats(int &proxies, int &slots, int &spectators) +{ + slots = 0; + spectators = 0; + proxies = 0; + + proxyInfo_t *proxy = (proxyInfo_t *)m_Proxies.GetFirst(); + while (proxy) + { + if (m_SystemTime > proxy->time + 64) + { + m_Proxies.Remove(proxy); + free(proxy); + } + else + { + proxies += proxy->proxies; + slots += proxy->slots; + spectators += proxy->spectators; + } + + proxy = (proxyInfo_t *)m_Proxies.GetNext(); + } + + int mySpecs, myProxies; + m_Proxy->CountLocalClients(mySpecs, myProxies); + + spectators += mySpecs; + slots += m_Proxy->GetMaxClients(); + + proxies++; +} + +void Status::CMD_Proxies(char *cmdLine) +{ + int nCount = 0; + proxyInfo_t *proxy = (proxyInfo_t *)m_Proxies.GetFirst(); + while (proxy) + { + nCount++; + m_System->Printf("IP %s, Clients %i, MaxClients %i%s\n", proxy->address.ToString(), proxy->spectators, proxy->slots, proxy->isPrivate ? " (excluded)" : ""); + + proxy = (proxyInfo_t *)m_Proxies.GetNext(); + } + + m_System->Printf("--- Total %i relay proxies ---\n", nCount); +} + +float Status::GetBestRelayProxy(NetAddress *addr) +{ + proxyInfo_t *proxy = (proxyInfo_t *)m_Proxies.GetFirst(); + while (proxy) + { + if (proxy->slots > 0 && proxy->slots >= proxy->spectators && !proxy->isPrivate) + { + float ratio = float(++proxy->spectators / proxy->slots); + + m_Proxies.ChangeKey(proxy, ratio); + addr->FromNetAddress(&proxy->address); + return ratio; + } + + m_Proxies.ChangeKey(proxy, 1); + proxy = (proxyInfo_t *)m_Proxies.GetNext(); + } + + addr->Clear(); + return -1; +} diff --git a/rehlds/HLTV/Proxy/src/Status.h b/rehlds/HLTV/Proxy/src/Status.h new file mode 100644 index 0000000..6edd6d5 --- /dev/null +++ b/rehlds/HLTV/Proxy/src/Status.h @@ -0,0 +1,85 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "common/NetAddress.h" +#include "ObjectDictionary.h" +#include "hltv.h" + +typedef struct proxyInfo_s { + NetAddress address; + int slots; + int proxies; + int spectators; + int isPrivate; + float time; +} proxyInfo_t; + +class IProxy; +class Status: public BaseSystemModule { +public: + Status() {} + virtual ~Status() {} + + bool Init(IBaseSystem *system, int serial, char *name); + void ExecuteCommand(int commandID, char *commandLine); + void RunFrame(double time); + char *GetStatusLine(); + char *GetType(); + void ShutDown(); + + void GetGlobalStats(int &proxies, int &slots, int &spectators); + void GetLocalStats(int &proxies, int &slots, int &spectators); + void SetProxy(IProxy *proxy); + float GetBestRelayProxy(NetAddress *addr); + void ParseStatusMsg(BitBuffer *stream); + void ParseStatusReport(NetAddress *from, BitBuffer *stream); + void Reset(); + int GetMaxSpectatorNumber(); + void RemoveProxy(NetAddress *addr); + void ClearProxyList(); + void ReplyStatusReport(); + void SendStatusUpdate(); + void SetName(char *newName); + +protected: + enum LocalCommandIDs { CMD_ID_PROXIES = 1 }; + void CMD_Proxies(char *cmdLine); + +private: + IProxy *m_Proxy; + float m_NextUpdateTime; + ObjectDictionary m_Proxies; + int m_NumberOfProxies; + int m_NumberOfSlots; + int m_NumberOfSpectators; + int m_MaxNumberOfSpectators; +}; + +#define STATUS_INTERFACE_VERSION "status000" diff --git a/rehlds/HLTV/Proxy/src/precompiled.cpp b/rehlds/HLTV/Proxy/src/precompiled.cpp new file mode 100644 index 0000000..5f656a4 --- /dev/null +++ b/rehlds/HLTV/Proxy/src/precompiled.cpp @@ -0,0 +1 @@ +#include "precompiled.h" diff --git a/rehlds/HLTV/Proxy/src/precompiled.h b/rehlds/HLTV/Proxy/src/precompiled.h new file mode 100644 index 0000000..d722eb0 --- /dev/null +++ b/rehlds/HLTV/Proxy/src/precompiled.h @@ -0,0 +1,49 @@ +#pragma once + +#include "basetypes.h" +#include "archtypes.h" +#include "mathlib.h" +#include "FileSystem.h" + +#include "interface.h" +#include "IBaseSystem.h" + +#include "mem.h" +#include "common.h" + +#include "common/md5.h" +#include "common/random.h" +#include "common/byteorder.h" +#include "common/ServerInfo.h" +#include "common/common_hltv.h" +#include "common/net_internal.h" +#include "common/mathlib_internal.h" + +// Hooks stuff +#include "hookers/HLTV/Proxy/hooklist.h" + +#include "common/DirectorCmd.h" +#include "common/NetAddress.h" +#include "common/NetChannel.h" +#include "common/BaseClient.h" + +#include "common/DemoFile.h" +#include "common/munge.h" + +#include + +#include +#include +#include +#include +#include +#include + +// Proxy module stuff +#include "Proxy.h" +#include "ProxyClient.h" +#include "DemoClient.h" +#include "FakeClient.h" + +#include "Master.h" +#include "Status.h" diff --git a/rehlds/HLTV/Proxy/src/public_amalgamation.cpp b/rehlds/HLTV/Proxy/src/public_amalgamation.cpp new file mode 100644 index 0000000..1fc308c --- /dev/null +++ b/rehlds/HLTV/Proxy/src/public_amalgamation.cpp @@ -0,0 +1,3 @@ +#include "precompiled.h" + +#include "interface.cpp" diff --git a/rehlds/HLTV/README.md b/rehlds/HLTV/README.md new file mode 100644 index 0000000..c774022 --- /dev/null +++ b/rehlds/HLTV/README.md @@ -0,0 +1,333 @@ +## Half-Life TV for Goldsrc based games HLTV Launcher + +### Building +On Windows: +

gradlew --max-workers=1 clean rehlds/HLTV:build
+ +On Linux (ICC): +
./gradlew --max-workers=1 clean rehlds/HLTV:build
+ +On Linux (GCC): +
./gradlew --max-workers=1 -PuseGcc clean rehlds/HLTV:build
+ +Compiled binaries will be placed in each project rehlds/HLTV/**/binaries/ directory + +### Overview +Half-Life TV offers the ability to have an unlimited number of spectators watching online games. +They can follow the game just like they would as a spectator on the game server. +Spectators are invisible to players and can't interact with the running game in any way. +Each spectator can choose any view position or choose any player to track individually. + +To have the most enjoyable spectating experience, spectators can enable the Auto-Director mode. +Then the camera is changed automatically so that only interesting scenes are shown from a suitable viewpoint. +Thus the spectator can lean back and won't miss any relevant action. +All the time, spectators may communicate between each other using the standard HL chat system. + +Most popular Half-Life MODs are supported like `Counter-Strike`, `Team Fortress Classic`, `Day of Defeat` and many others. +HLTV providers have full control over their HLTV system, may change number of spectator slots, add text messages or change the HLTV logo. + +The broadcast is delayed by a customizable amount of time, by default 30 seconds. This ensures that the playing teams can't use +HLTV to get any usable information about their opponents. Providing a single HLTV server for up to 100 spectators is an easy task +and doesn't need any changes in default configurations. + +Installing a larger HLTV network for thousands of spectators needs some more planning time and experience about required bandwidth +and CPU/RAM demands (see [Larger Broadcasts](#larger-broadcasts)). + +### Spectating Games +To watch a HLTV game, start Half-Life, open the Multiplayer menu and select 'Find Servers'. +To search for currently broadcasted games, choose the 'Spectate' section and hit 'Refresh All'. +After the list has been updated, double click on the server you want to spectate and you'll be connected. + +If computer game leagues announce important matches to be broadcasted via HLTV, they often provide IP:Port addresses of their HLTV servers. +Instead of searching them via the server browser, you can also go to the 'Favorites' folder and add the HLTV address to your server +list by pressing the right mouse button. Otherwise, you can also open the console window and use the 'connect' command to spectate a certain game. + +For example: +
+connect 192.168.130.42:27020
+
+ +The default HLTV port number is 27020, but may be changed. +It should always be included in the given address, since commonly this port number is different from the default port number 27015. + +You can spectate the game in different modes: `Chase Cam`, `First Person`, `Free Look`, `Map Overview` and `Map Chase`.
+The easiest way to change modes is to press the JUMP key (default `SPACE`). Alternatively you can use the spectator menu, which can be enabled by pressing the `DUCK` key (default `CTRL`). +Here you can customize your personal view style and enable the Auto-Director Mode. Press `USE` (default `E`) to cycle through the different `Picture-In-Picture` modes. + +The following HL console commands can be used to customize spectator settings: + +| Console commands | Default | Min | Max | Description | +| :---------------------------- | :-----: | :-: | :----------: | :--------------------------------------------- | +| spec_autodirector | 1 | 0 | 1 | Turns Auto Director mode on or off | +| spec_drawcone | 1 | 0 | 1 | Shows your view cone in map overview mode | +| spec_drawnames | 1 | 0 | 1 | Shows player names under their icons | +| spec_drawstatus | 1 | 0 | 1 | Shows game information (time, map etc) | +| spec_pip | 0 | 0 | 1 | Turns Picture-In-Picture mode on or off | +| spec_mode | 1 | 1 | 6 | Set the main view mode, seconds parameter is the PIP mode.
Not all combinations are valid.
Main modes are:
`1` Locked Chase
`2` Free Chase
`3` Free Roaming
`4` First Person
`5` Map Overview
`6` Chase Map Overview

PIP modes are:
`0` PIP off
`1` Free Chase
`2` First Person
`3` Map Overview
`4` Chase Map Overview
| +| spec_menu | - | - | - | Opens the spectator menu | +| spec_help | - | - | - | Shows a help screen | + +### HLTV Basics +The core of the HLTV broadcasting system is the HLTV server, also called HLTV proxy. +The HLTV executable is a console application that works much like a HL dedicated server. +To broadcast a game running on a certain game server, the HLTV proxy connects to this server just like a normal player. +Spectators connect themselves to the HLTV proxy and the game data stream is relayed through the HLTV proxy to all connected spectator clients. + +The next figure shows a basic HLTV configuration: +
+HL Game Server -> HLTV Proxy => Spectator Clients
+
+ +The number of clients that one HLTV proxy can serve depends on available hardware and network resources. +Theoretically, a single proxy can hold a maximum of 255 spectator clients. +But be careful, even a proxy with 100 spectator clients needs a full 2 MBit line to run smoothly. +If more spectator slots are needed, the required network load must be distributed over multiple HLTV proxies. + +The first HLTV proxy connected to the game server is called the Master proxy, which sets the general broadcast settings like +game stream delay or packet rate. All other HLTV proxies linked to this proxy are the Relay proxies. Their total number and +link order is not restricted, they may form a chain or tree of proxies. +Most important is that their location is in different networks to ensure a balanced bandwidth usage. + +
+                              -> HLTV Relay Proxy 1 => Spectator Clients
+HL Game Server -> HLTV Master -> HLTV Relay Proxy 2 => Spectator Clients
+                              -> HLTV Relay Proxy 3 => Spectator Clients
+
+ +### Broadcasting Games +Let's assume the most simple configuration, a single HLTV proxy in a LAN environment. +This is a very common situation and the default HLTV settings doesn't need to be changed. +Choose a dedicated computer as your HLTV proxy and install the Half-Life Dedicated Server, which also includes all files needed by a HLTV proxy. +This isn't needed if Half-Life is already installed. + +Start the HLTV application (HL icon with a small camera) and the HLTV console will open, showing some initialization messages +(if that takes a long time, HLTV maybe can't resolve some IP addresses, then start HLTV with the '-nodns' command line option). +Then the console is ready to accept your commands, here we use '>' as the console prompt. + +First give your HLTV proxy an unique name: +
+>name "My HLTV Proxy"
+
+ +Let's assume you have started the proxy on host `192.168.1.2` and the game server, +you want to spectate is running on host `192.168.1.3:27015`. + +Then connect the HLTV proxy to this game server by typing: +
+>connect 192.168.1.3:27015
+
+ +After a few seconds HLTV will be fully connected and ready to serve spectator clients. +Use the 'status' command to verify that the HLTV proxy has connected properly: +
+>status
+--- HLTV Status ---
+Online 00:23, FPS 79.0, Version 2435 (Win32)
+Local IP 192.168.1.2:27020, Network In 1.7, Out 1.0, Loss 0.00
+Local Slots 128, Spectators 0, Proxies 0
+Total Slots 128, Spectators 0, Proxies 1
+Source Game Server 192.168.1.3:27015, Delay 30
+Server Name "Half-Life dedicated server"
+Time 01:35, Game "valve", Map "maps/rapidcore.bsp", Players 1
+
+ +The 'status' command shows your own IP address, HLTV system cycles per second, total incoming and outgoing network traffic in `kB/sec`. +Local slot and spectator numbers your HLTV proxy is providing, total numbers are the sum of all slots & spectators on all proxies broadcasting this game. +The game source can be a game server, another HLTV proxy or a demo file. + +### Recording HLTV demos +HLTV demo files are like normal recorded games in Half-Life, but you can choose any view point, +view mode or player to chase during replay. To play back a HLTV demo, a HLTV proxy is not needed. +Just start Half-Life and type in console `playdemo ` or `viewdemo ` +(viewdemo offers more options during playback like fast forward/backward, pause & slowmotion). +To record a HLTV demo, connect the proxy to a game server (see [Broadcasting Games](#broadcasting-games)) and type in console: + +
+>record 
+
+ +All games will be recorded after issuing this command. The demo files will be saved in the current Mod directory, e.g. `\cstrike`. +All demo files have a special naming convention `--.dem`, including the given name, date/time and map name. +Demo files record the same data as send to spectator clients. That means also, the demo file records the game with the same delay as used for spectators. +To verify, that a demo file is recorded use the `status` command. The recording may be stopped with `stoprecording`. + +Sometimes a HLTV broadcast is not wanted and the HLTV proxy is only used to record a demo file. +In this case, some HLTV settings should be made to gain optimal recording results: +
+>maxclients 0   // don't allow any spectator clients
+>delay 0        // no game stream delay
+>rate 10000     // maximum data rate
+>updaterate 20  // standard update rate
+>nomaster 1     // don't register at master servers
+
+ +### Larger Broadcasts +Setting up a HLTV network that can handle a larger number of spectators (>1000) is a difficult and time consuming task. +The following guide should help to configure and run such a HLTV network. One of the most important rule should be `Quality, not Quantity`. +It's better to offer a smaller number of spectator slots, than operating at the maximum bandwidth limit, thus all spectators would suffer from lags and timeouts. +Check carefully your available bandwidth capacity and calculate how many spectators can be handled by your HLTV servers. +The average bandwidth demand per spectator is between 2 and 3 KB/sec and depends on the current mod, map and number of players. +CPU and RAM shouldn't be a bottleneck on modern PC systems. + + +This list for common Internet connection types gives a feeling, how bandwidth demanding HLTV can be: +
+-   ISDN         64 Kbps            :      2 spectators
+-   DSL         128 Kbps (upstream) :      5 spectators
+-   T1          1.5 Mbps            :     75 spectators
+-   LAN          10 Mbps            :    500 spectators
+-   T3           75 Mbps            :   4000 spectators
+
+ +Use the `maxclients` command to set how many clients should be accepted by a HLTV proxy. +Make sure that the `maxrate` variable is set too a reasonable value, e.g. `3500 kB/sec`. Lower values are possible, +but make sure spectators don't get too much `choke` during a running game. The `maxrate` command doesn't effect +the bandwidth limit between HLTV proxies, only for spectator clients. +To lower the general bandwidth demand, you can turn off the internal HLTV chat (`chatmode 0`) or decrease the game +update rate from the default value 20 to 10 (`updaterate 10`). A lower update rate may save up to 25% network traffic +and is an acceptable tradeoff in this case since spectators doesn't need a high update rate like real players does. + +A very common setup for large broadcasts is to use 2 dedicated HLTV servers to create a private and a public HLTV segment. +Let's assume the game server is in a closed LAN and not accessible from outside. +This ensures a maximum security against attacks (DOS etc) from outside. The HLTV master server is started within the +LAN and it's IP address should be kept secret. The second HLTV server is started outside the LAN with a global IP +and is connected to the HLTV master server. This second HLTV server is the public HLTV dispatcher, which IP address is given to the audience. +Any relay proxies are connected to this HLTV dispatcher. Thus the HLTV master server is in a secure LAN environment +and can be used for demo recording or for HL clients serving video projectors. +Spectators connect to the HLTV dispatcher and are relayed through the HLTV network to a relay proxy with a low usage. +Thus the total network load is balanced between all connected HLTV proxies. + +
+       Private LAN                 Public Internet
+                                            -> HLTV Proxy 1
+HL Server -> HLTV Master -> HLTV Dispatcher -> HLTV Proxy 2
+                                            -> HLTV Proxy 3
+
+ +The configuration files of HLTV master and HLTV dispatcher are different: + +**master.cfg:** +
+nomaster      1        // don't register at WON master servers
+proxypassword MyPWD    // protect HLTV server
+publicgame    0        // don't show game server IP
+dispatchmode  0        // don't dispatch spectators
+
+ +**dispatcher.cfg:** +
+forcemaster  1         // register at WON master servers
+publicgame   0         // don't show game server IP
+dispatchmode 2         // dispatch all clients to other proxies
+hostname     MyGame    // public HLTV server name
+
+ +If you're running 3 or more HLTV servers in total, it's a good idea to use RCON to manage them via a single server admin tool. +To enable RCON on a HLTV server an `adminpassword` must been set. +Also `proxypassword` should be set to ensure only known HLTV providers can connect to your HLTV network. +Otherwise anybody can connect with slow HLTV proxies and disturb your network load balancing. + +### HLTV Configuration + +A short note about console command syntax. +A command may have one or more parameters. Parameters in brackets `[]` are optional. + +Common used parameters are: +
+   : text, must be in quotes if text contains spaces "My Name"
+   : a whole number, e.g. 42
+   : a floating point number, e.g. 4.2
+   : an IP address, e.g. 192.168.130.42:27020
+   : a set of options, a or b or c
+
+ +`NOTE:` Any of these special characters <, >, |, [ or ] are not part of the final command as typed in the console. +Lots of these commands are boolean switches, were 1 is meaning ON and 0 is respectively OFF. + + +| HLTV Commands | Arguments | Description | +| :---------------------------- | :--------------------------------------------------------- | :------------------------------------------------------------------------------------------------------ | +| connect | IP:Port | Connect HLTV proxy to game server. (default port `27015`) | +| disconnect | - | Disconnects proxy from server, but doesn't stop the broadcast.
All spectator clients stay connected. | +| stop | [ `text` ] | Disconnects from server, disconnects all clients and stops demo recording.
Optional goodbye message. | +| quit | 1 | Quits the HLTV process. | +| retry | 0 | Retries the last server connection. | +| autoretry | `0/1` | If enabled, proxy will retry connection to server.
If connection was interrupted for any reason. | +| name | `text` | Sets the HLTV proxy scoreboard name. | +| hostname | `text` | Sets the HLTV host name for game browser list. | +| serverpassword | `text` | Sets the game server password. | +| adminpassword | `text` | Sets password for RCON & commentator. | +| proxypassword | `text` | Sets password for other relay proxies. | +| spectatorpassword | `text` | Sets spectator password. Will also exclude proxy from global load balancing. | +| clients | - | Lists connected spectator clients. | +| proxies | - | Lists connected relay proxies. | +| players | - | Lists players on game server. | +| kick | `ID` | Kicks a spectator client from proxy. | +| bann | `IP` | Banns an IP address. (completely ignored) | +| clearbanns | - | Removes all IPs from bann list. | +| say | `text` | Sends a text message to game server. (chat with players) | +| msg | `text` [ `duration` `pos x` `pos y` `rgba` ] | Sends a text message to all spectators as big HUD text. | +| localmsg | `text` [ `duration` `pos x` `pos y` `rgba` ] | Same as msg, but only seen by local clients. | +| servercmd | `string` | Forwards console command to game server. | +| clientcmd | `group` `string` | Forwards a console command to all clients of given group:
`1` SPECTATORS
`2` PROXIES
`3` ALL | +| loopcmd | `id` `n` `string` | Loopcmd will execute `string` every `n` seconds.
`` is a number between `1` and `64` to identify this loopcmd.
`loopcmd none` will disable a looping command again.
loopcmd without any parameter will list any command currently in the list. | +| signoncommands | `string` | Console commands that will be executed by local
spectator clients after connection is established.
Commands may be separated by semicolons. | +| maxclients | `n` | Set spectator number limit for this proxy. (default `128`) | +| delay | `n` | Delays the game stream for n seconds on the Master Proxy.
The default value is 30 seconds to avoid cheating.
If the delay is set to a value below 10 seconds (e.g. 0),
the auto director function will be disabled. | +| rate | `n` | Bandwidth rate the game server sends data to the proxy. | +| updaterate | `n` | Game updates per seconds send from server to proxy. | +| maxrate | `n` | Sets the maximum bandwidth rate for spectator clients. | +| maxloss | `f` | Sets the acceptable packet loss rate, default value is 0.05 (5%).
If packet loss is higher, new spectator clients will be rejected. | +| maxqueries | `n` | Maximum of status queries per second requested by server browsers. | +| dispatchmode | `0/1/2` | `0` (OFF) Won't redirect any clients.
`1` (AUTO) Will redirect connecting clients to other
proxies balancing work load between all proxies.
`2` (ALWAYS) Any spectator clients will be redirected,
so this proxy serves only as dispatcher.
| +| publicgame | `0/1` | `0` Private.
`1` Game server IP will be visible to spectators and 'joingame' is allowed. | +| offlinetext | `string` | Info text clients will see as reject reason if HLTV isn't broadcasting yet. | +| chatmode | `0/1/2` | `0` Spectators can't chat.
`1` Only spectators connected to the same proxy can see their chat messages.
`2` All spectators can chat between each other (then Master and all Relay proxies must have set chatmode 2).
| +| bannerfile | `file` | Specifies a TGA file (`RGBA`) that will be shown as logo in spectator GUI. | +| ping | `host:port` | Pings a HL server on the given port. (default `27015`) | +| nomaster | `0/1` | `0` Disabled.
`1` Proxy won't register at WON master servers. | +| forcemaster | `0/1` | `0` Disabled.
`1` Proxy will register at WON master server. | +| heartbeat | - | Sends manually a status packet to WON master servers. | +| region | `n` | Set the region your HLTV proxy is located in. | +| rcon | `string` | Sends a remote control command to other servers. | +| rconaddress | `IP:Port` | Sets the remote control target address. | +| rconpassword | `string` | Sets the password for the remote controlled host. | +| cheeringthreshold | `f` | Number of cheering players must be above this threshold to play
the cheering sound. (by default `0.25`). | +| blockvoice | `0/1` | `0` Disabled.
`1` All incoming voice data is blocked.
This is useful to override incoming voice commentators
or player voice with own commentators voice. | +| cmdlist | - | Shows all registered proxy commands. | +| logfile | `0/1` | Starts/stops console logging in `logfile.log` | +| status | - | Shows proxy status information. | +| modules | - | Shows all loaded HLTV modules and versions. | +| exec | `filename` | Executes a `.cfg` file. | +| echo | `string` | Prints a text to HLTV console. | +| developer | `0/1` | `0` Disabled.
`1` Additional debug messages are shown in developer mode. | +| record | `filename` | Records all following games to demo files
using name syntax `filename--.dem` | +| stoprecording | - | Stops recording a demo file. | +| playdemo | `filename` | Starts broadcasting a demo file. | + +The console does auto-completion by hitting `TAB`. +All commands in the config file `hltv.cfg` are executed during startup. + +Some parameters can only be set in the command line: +
+-port            - sets the HLTV proxy port that spectators connect to (default "27020" )
+-ip              - forces the proxy to use this IP on a multihomed host
+-nodns           - disables any DNS resolving (useful for LAN proxies)
+-maxfps          - sets maximum system cycles per seconds (default "100")
+-highpriority    - starts the HLTV proxy as high priority process
+-multicastttl    - sets the Time-To-Live value for multicast packets
+-steam           - proxy enables special Steam support
+-dev             - developer mode
+
+ +These parameters cannot be changed during runtime, thus they can't be used in config files.
+All console commands can be used in the command line, if a `+` is prepended to them, for example: +
+hltv.exe +connect localhost:27015 -port 27021
+
+ +A Half-Life server can set sv_proxies `n`, to determine how many proxies are allowed to connect.
+If HLTV proxies should be forbidden, set it to `0`, otherwise `1` to allow for a Master Proxy.
+Other values are experimental. + +Copyright © 2003, `Valve LLC`, All rights reserved. diff --git a/rehlds/HLTV/build.gradle b/rehlds/HLTV/build.gradle new file mode 100644 index 0000000..8f08d31 --- /dev/null +++ b/rehlds/HLTV/build.gradle @@ -0,0 +1,13 @@ +evaluationDependsOn(':rehlds/HLTV/Console'); +evaluationDependsOn(':rehlds/HLTV/Core'); +evaluationDependsOn(':rehlds/HLTV/DemoPlayer'); +evaluationDependsOn(':rehlds/HLTV/Director'); +evaluationDependsOn(':rehlds/HLTV/Proxy'); + +task build { + dependsOn project(':rehlds/HLTV/Console').tasks.build, + project(':rehlds/HLTV/Core').tasks.build, + project(':rehlds/HLTV/DemoPlayer').tasks.build, + project(':rehlds/HLTV/Director').tasks.build, + project(':rehlds/HLTV/Proxy').tasks.build +} diff --git a/rehlds/HLTV/common/BaseClient.cpp b/rehlds/HLTV/common/BaseClient.cpp new file mode 100644 index 0000000..dd33e9d --- /dev/null +++ b/rehlds/HLTV/common/BaseClient.cpp @@ -0,0 +1,776 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +bool BaseClient::Init(IBaseSystem *system, int serial, char *name) +{ + if (!BaseSystemModule::Init(system, serial, name)) { + return false; + } + + if (!name) { + strcopy(m_Name, CLIENT_INTERFACE_VERSION); + } + + SetState(CLIENT_INITIALIZING); + + m_ClientType = TYPE_CLIENT; + m_World = nullptr; + m_Socket = nullptr; + + m_VoiceEnabled = false; + m_VoiceQuery = false; + m_Userinfo.SetMaxSize(MAX_USER_INFO); + + return false; +} + +void BaseClient::RunFrame(double time) +{ + BaseSystemModule::RunFrame(time); + + if (m_ClientState != CLIENT_DISCONNECTED && m_ClientChannel.IsTimedOut()) { + m_System->Printf("Client %s timed out.\n", m_ClientChannel.GetTargetAddress()->ToString()); + Disconnect("Timed out.\n"); + } + + if (m_ClientState != CLIENT_DISCONNECTED && m_ClientChannel.IsCrashed()) { + m_System->Printf("Client %s netchannel crashed.\n", m_ClientChannel.GetTargetAddress()->ToString()); + Disconnect("Netchannel crashed.\n"); + } + + int numPackets = 0; + NetPacket *packet; + while ((packet = m_ClientChannel.GetPacket())) + { + if (packet->connectionless) + { + m_Socket->AddPacket(packet); + } + else if (numPackets < 32) + { + numPackets++; + ProcessMessage(packet); + } + + m_ClientChannel.FreePacket(packet); + } + + // process state + switch (m_ClientState) + { + case CLIENT_RUNNING: + { + if (m_World->IsActive() && m_ClientChannel.IsReadyToSend()) { + SendDatagram(); + } + break; + } + case CLIENT_DISCONNECTED: + ShutDown(); + break; + case CLIENT_INITIALIZING: + case CLIENT_CONNECTING: + /* do nothing */ + break; + default: + case CLIENT_UNDEFINED: + m_System->Errorf("Client::RunFrame: not valid state.\n"); + break; + } +} + +void BaseClient::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) { + return; + } + + if (m_ClientState != CLIENT_DISCONNECTED) { + Disconnect("Connection dropped (hard).\n"); + } + + m_ClientChannel.Close(); + BaseSystemModule::ShutDown(); +} + +bool BaseClient::Connect(INetSocket *socket, NetAddress *adr, char *userinfo) +{ + if (!userinfo || !adr) { + return false; + } + + m_ClientType = TYPE_CLIENT; + m_Socket = socket; + + if (!adr->Equal(m_ClientChannel.GetTargetAddress())) { + m_ClientChannel.Create(m_System, m_Socket, adr); + } else { + m_ClientChannel.Clear(); + m_ClientChannel.Reset(); + } + + SetState(CLIENT_CONNECTING); + m_ClientChannel.SetUpdateRate(20); + m_ClientChannel.SetRate(20000); + m_ClientChannel.SetConnected(1); + + UpdateUserInfo(userinfo); + m_ClientChannel.OutOfBandPrintf("%c0000000000000000", S2C_CONNECTION); + + return true; +} + +BaseClient::clc_func_s BaseClient::m_ClientFuncs[] = { + { clc_bad, "clc_bad", &BaseClient::ParseBad }, + { clc_nop, "clc_nop", &BaseClient::ParseNop }, + { clc_move, "clc_move", &BaseClient::ParseMove }, + { clc_stringcmd, "clc_stringcmd", &BaseClient::ParseStringCmd }, + { clc_delta, "clc_delta", &BaseClient::ParseDelta }, + { clc_resourcelist, "clc_resourcelist", nullptr }, + { clc_tmove, "clc_tmove", nullptr }, + { clc_fileconsistency, "clc_fileconsistency", nullptr }, + { clc_voicedata, "clc_voicedata", &BaseClient::ParseVoiceData }, + { clc_hltv, "clc_hltv", &BaseClient::ParseHLTV }, + { clc_cvarvalue, "clc_cvarvalue", &BaseClient::ParseCvarValue }, + { clc_cvarvalue2, "clc_cvarvalue2", &BaseClient::ParseCvarValue2 }, + { clc_endoflist, "End of List", nullptr }, +}; + +void BaseClient::ProcessMessage(NetPacket *packet) +{ + m_ClientDelta = 0; + m_DeltaFrameSeqNr = 0; + + while (true) + { + if (packet->data.IsOverflowed()) { + m_System->Printf("Client::ProcessMessage: packet read overflow\n"); + Disconnect("Dropped due to bad message format!\n"); + break; + } + + int cmd = packet->data.ReadByte(); + if (cmd == -1) + break; + + if (cmd < clc_bad || cmd > clc_cvarvalue2) + { + m_System->Printf("Client::ProcessMessage: unknown command char\n"); + Disconnect("Bad command character in client command"); + return; + } + + if (!m_ClientFuncs[cmd].func) { + m_System->Printf("TODO! Client::ProcessMessage: missing parsing routine for %s.\n", m_ClientFuncs[cmd].pszname); + return; + } + + (this->*m_ClientFuncs[cmd].func)(packet); + } +} + +char *BaseClient::GetClientName() +{ + return m_ClientName; +} + +InfoString *BaseClient::GetUserInfo() +{ + return &m_Userinfo; +} + +void BaseClient::Disconnect(const char *reason) +{ + SetState(CLIENT_DISCONNECTED); + + m_ClientChannel.m_reliableStream.WriteByte(svc_disconnect); + m_ClientChannel.m_reliableStream.WriteString(reason ? reason : ""); + + m_ClientChannel.m_unreliableStream.WriteByte(svc_disconnect); + m_ClientChannel.m_unreliableStream.WriteString(reason ? reason : ""); + m_ClientChannel.TransmitOutgoing(); +} + +void BaseClient::ParseNop(NetPacket *packet) +{ + ; +} + +void BaseClient::ParseBad(NetPacket *packet) +{ + m_System->Printf("Client::ParseBad: bad command char\n"); + Disconnect("Bad command character in client command"); +} + +void BaseClient::ParseStringCmd(NetPacket *packet) +{ + char *string = packet->data.ReadString(); + ProcessStringCmd(string); +} + +BaseClient::LocalCommandID_s BaseClient::m_LocalCmdReg[] = { + { "name", CMD_ID_NAME, &BaseClient::CMD_Name }, + { "spawn", CMD_ID_SPAWN, &BaseClient::CMD_Spawn }, + { "new", CMD_ID_NEW, &BaseClient::CMD_New }, + { "fullupdate", CMD_ID_FULLUPDATE, &BaseClient::CMD_FullUpdate }, + { "dropclient", CMD_ID_DROPCLIENT, &BaseClient::CMD_DropClient }, + { "dlfile", CMD_ID_DLFILE, &BaseClient::CMD_DownloadFile }, + { "setinfo", CMD_ID_SETINFO, &BaseClient::CMD_SetInfo }, + { "showinfo", CMD_ID_SHOWINFO, &BaseClient::CMD_ShowInfo }, + { "sendents", CMD_ID_SENDENTS, &BaseClient::CMD_SendEntities }, + { "VModEnable", CMD_ID_VMODENABLE, &BaseClient::CMD_VoiceModEnable }, + { "vban", CMD_ID_VBAN, &BaseClient::CMD_VoiceBan }, + + // TODO: Pure function's, finish them. + { "sendres", CMD_ID_SENDERS, &BaseClient::CMD_SendResources }, + { "ping", CMD_ID_PING, &BaseClient::CMD_RequestPing }, + { "spectate", CMD_ID_SPECTATE, &BaseClient::CMD_Spectate }, + { "spk", CMD_ID_SPK, &BaseClient::CMD_Spk }, + { "pause", CMD_ID_PAUSE, &BaseClient::CMD_Pause }, + { "unpause", CMD_ID_UNPAUSE, &BaseClient::CMD_UnPause }, + { "setpause", CMD_ID_SETPAUSE, &BaseClient::CMD_SetPause } +}; + +bool BaseClient::ProcessStringCmd(char *string) +{ + TokenLine cmdLine; + if (!cmdLine.SetLine(string)) { + m_System->Printf("WARNING! BaseClient::ProcessStringCmd: string command too long.\n"); + return false; + } + + char *cmd = cmdLine.GetToken(0); + for (auto& local_cmd : m_LocalCmdReg) + { + if (!_stricmp(local_cmd.name, cmd)) { + (this->*local_cmd.pfnCmd)(&cmdLine); + return true; + } + } + + return false; +} + +void BaseClient::CMD_Name(TokenLine *cmd) +{ + SetName(cmd->GetRestOfLine(1)); +} + +void BaseClient::CMD_Spawn(TokenLine *cmd) +{ + if (cmd->CountToken() != 3) { + m_System->Printf("Client::ParseStringCmd: spawn is not valid\n"); + Disconnect("Spawn is not valid."); + return; + } + + ReplySpawn(atoi(cmd->GetToken(1)), atoi(cmd->GetToken(2))); +} + +void BaseClient::CMD_New(TokenLine *cmd) +{ + ReplyNew(); +} + +void BaseClient::CMD_FullUpdate(TokenLine *cmd) +{ + ReplyFullUpdate(); +} + +void BaseClient::CMD_DropClient(TokenLine *cmd) +{ + Disconnect(); +} + +void BaseClient::CMD_DownloadFile(TokenLine *cmd) +{ + DownloadFile(cmd->GetToken(1)); +} + +void BaseClient::CMD_SetInfo(TokenLine *cmd) +{ + if (cmd->CountToken() != 3) { + return; + } + + m_Userinfo.SetValueForKey(cmd->GetToken(1), cmd->GetToken(2)); + UpdateUserInfo(); +} + +void BaseClient::CMD_ShowInfo(TokenLine *cmd) +{ + InfoString info(MAX_INFO_STRING); + + info.SetString(m_World->GetServerInfoString()->GetString()); + info.RemoveKey("proxy"); // remove proxy ip + PrintfToClient("%s\n", info.GetString()); +} + +void BaseClient::CMD_SendEntities(TokenLine *cmd) +{ + m_System->DPrintf("Client fully connected.\n"); + SetState(CLIENT_RUNNING); +} + +void BaseClient::CMD_VoiceModEnable(TokenLine *cmd) +{ + if (cmd->CountToken() != 2) { + return; + } + + m_VoiceQuery = false; + m_VoiceEnabled = atoi(cmd->GetToken(1)) ? true : false; + UpdateVoiceMask(&m_ClientChannel.m_reliableStream); +} + +void BaseClient::CMD_VoiceBan(TokenLine *cmd) +{ + if (cmd->CountToken() < 2) { + return; + } + + for (int i = 1; i < cmd->CountToken(); i++) + { + uint32 mask = 0; + sscanf(cmd->GetToken(i), "%x", &mask); + + if (i <= VOICE_MAX_PLAYERS_DW) { + m_SentBanMask.SetDWord(i - 1, mask); + } + } + + UpdateVoiceMask(&m_ClientChannel.m_reliableStream); +} + +void BaseClient::CMD_SendResources(TokenLine *cmd) { /* do nothing */ } +void BaseClient::CMD_RequestPing(TokenLine *cmd) { /* do nothing */ } +void BaseClient::CMD_Spectate(TokenLine *cmd) { /* do nothing */ } +void BaseClient::CMD_Spk(TokenLine *cmd) { /* do nothing */ } +void BaseClient::CMD_Pause(TokenLine *cmd) { /* do nothing */ } +void BaseClient::CMD_UnPause(TokenLine *cmd) { /* do nothing */ } +void BaseClient::CMD_SetPause(TokenLine *cmd) { /* do nothing */ } + +void BaseClient::UpdateUserInfo(char *userinfostring) +{ + char buffer[1024]; + char *string; + + if (userinfostring) { + m_Userinfo.SetString(userinfostring); + } + + strcopy(buffer, m_Userinfo.ValueForKey("name")); + + SetName(buffer); + m_ClientType = atoi(m_Userinfo.ValueForKey("*hltv")); + + if (m_ClientType < TYPE_CLIENT) { + m_System->DPrintf("WARNING! BaseClient::UpdateUserInfo: invalid client ype %i\n", m_ClientType); + m_ClientType = TYPE_CLIENT; + } + + string = m_Userinfo.ValueForKey("rate"); + if (*string) { + m_ClientChannel.SetRate(atoi(string)); + } + + string = m_Userinfo.ValueForKey("cl_updaterate"); + if (*string) { + m_ClientChannel.SetUpdateRate(atoi(string)); + } +} + +void BaseClient::PrintfToClient(char *fmt, ...) +{ + va_list argptr; + static char string[1024]; + + va_start(argptr, fmt); + _vsnprintf(string, sizeof(string), fmt, argptr); + va_end(argptr); + + m_ClientChannel.m_reliableStream.WriteByte(svc_print); + m_ClientChannel.m_reliableStream.WriteString(string); +} + +void BaseClient::ReplySpawn(int spawncount, int crcMap) +{ + BitBuffer msg(MAX_POSSIBLE_MSG); + + m_CRC_Value = crcMap; + COM_UnMunge2((unsigned char *)&m_CRC_Value, 4, (-1 - m_World->GetServerCount()) & 0xFF); + + if (m_World->GetServerCount() != spawncount) { + ReplyNew(); + return; + } + + m_World->WriteSigonData(&msg); + WriteSpawn(&msg); + + m_ClientChannel.CreateFragmentsFromBuffer(msg.GetData(), msg.CurrentSize(), FRAG_NORMAL_STREAM, nullptr); + m_ClientChannel.FragSend(); + m_LastFrameSeqNr = 0; +} + +void BaseClient::ReplyNew() +{ + BitBuffer msg(MAX_POSSIBLE_MSG); + + Reset(); + m_World->WriteNewData(&msg); + + m_ClientChannel.CreateFragmentsFromBuffer(msg.GetData(), msg.CurrentSize(), FRAG_NORMAL_STREAM, nullptr); + m_ClientChannel.FragSend(); + msg.Free(); +} + +void BaseClient::ReplyFullUpdate() +{ + BitBuffer msg(1024 * 9); + for (int i = 0; i < m_World->GetMaxClients(); i++) { + m_World->WriteClientUpdate(&msg, i); + } + + m_ClientChannel.CreateFragmentsFromBuffer(msg.GetData(), msg.CurrentSize(), FRAG_NORMAL_STREAM, nullptr); + m_ClientChannel.FragSend(); +} + +void BaseClient::SetState(ClientState newState) +{ + if (newState == m_ClientState) + return; + + bool stateError = false; + switch (newState) + { + case CLIENT_INITIALIZING: + break; + case CLIENT_CONNECTING: + { + if (m_ClientState != CLIENT_INITIALIZING + && m_ClientState != CLIENT_RUNNING) { + stateError = true; + } + + m_ClientChannel.SetKeepAlive(true); + m_ClientChannel.SetTimeOut(60); + break; + } + case CLIENT_RUNNING: + { + if (m_ClientState != CLIENT_CONNECTING) { + stateError = true; + } + + m_ClientChannel.SetKeepAlive(false); + m_ClientChannel.SetTimeOut(30); + break; + } + case CLIENT_DISCONNECTED: + { + m_ClientChannel.SetKeepAlive(true); + break; + } + default: + stateError = true; + break; + } + + if (stateError) + { + m_System->Errorf("Client::SetState: not valid m_ClientState (%i -> %i).\n", m_ClientState, newState); + return; + } + + m_ClientState = newState; +} + +void BaseClient::WriteSpawn(BitBuffer *stream) +{ + stream->WriteByte(svc_time); + stream->WriteFloat(1); + + for (int i = 0; i < m_World->GetMaxClients(); i++) { + m_World->WriteClientUpdate(stream, i); + } + + m_World->WriteLightStyles(stream); + + stream->WriteByte(svc_signonnum); + stream->WriteByte(1); +} + +void BaseClient::WriteDatagram(double time, frame_t *frame) +{ + if (!frame) { + return; + } + + if (!m_LastFrameSeqNr || m_LastFrameSeqNr > frame->seqnr) { + m_LastFrameSeqNr = frame->seqnr - 1; + m_ClientDelta = 0; + m_DeltaFrameSeqNr = 0; + } + + if (m_LastFrameSeqNr >= frame->seqnr && m_ClientChannel.GetIdleTime() <= 2) { + return; + } + + m_ClientChannel.m_unreliableStream.WriteByte(svc_time); + m_ClientChannel.m_unreliableStream.WriteFloat(float(time)); + m_World->WriteFrame(frame, m_LastFrameSeqNr, &m_ClientChannel.m_reliableStream, &m_ClientChannel.m_unreliableStream, m_DeltaFrameSeqNr, m_ClientDelta, IsHearingVoices()); + + if (m_VoiceQuery) { + QueryVoiceEnabled(&m_ClientChannel.m_unreliableStream); + } + + if (m_ClientChannel.m_reliableStream.IsOverflowed()) { + Disconnect("Reliable data stream overflow.\n"); + return; + } + + if (m_ClientChannel.m_unreliableStream.IsOverflowed()) { + m_System->DPrintf("Unreliable data stream overflow.\n"); + m_ClientChannel.m_unreliableStream.Clear(); + m_LastFrameSeqNr = 0; + } + + m_LastFrameSeqNr = frame->seqnr; + m_SeqNrMap[m_ClientChannel.m_outgoing_sequence & 0xFF] = frame->seqnr; + m_ClientChannel.TransmitOutgoing(); +} + +void BaseClient::ParseDelta(NetPacket *packet) +{ + if (m_ClientState != CLIENT_RUNNING) { + packet->data.SkipBytes(1); + return; + } + + m_ClientDelta = packet->data.ReadByte(); + m_DeltaFrameSeqNr = m_SeqNrMap[m_ClientDelta]; +} + +char *BaseClient::GetStatusLine() +{ + float in, out; + static char string[256]; + + m_ClientChannel.GetFlowStats(&in, &out); + _snprintf(string, sizeof(string), + "ID: %i, Name \"%s\", Time %s, IP %s, In %.2f, Out %.2f.\n", + GetSerial(), + m_ClientName, + COM_FormatTime(float(m_SystemTime - m_ClientChannel.m_connect_time)), + m_ClientChannel.GetTargetAddress()->ToString(), + in, + out + ); + + return string; +} + +void BaseClient::SetWorld(IWorld *world) +{ + if (m_World && m_World != world) { + Reconnect(); + } + + m_World = world; +} + +void BaseClient::Reconnect() +{ + Reset(); + m_ClientChannel.m_reliableStream.WriteByte(svc_stufftext); + m_ClientChannel.m_reliableStream.WriteString("reconnect\n"); +} + +bool BaseClient::IsActive() +{ + return (m_ClientState == CLIENT_RUNNING); +} + +void BaseClient::ParseVoiceData(NetPacket *packet) +{ + int nDataLength = packet->data.ReadShort(); + packet->data.SkipBytes(nDataLength); +} + +void BaseClient::ParseMove(NetPacket *packet) +{ + int nDataLength = packet->data.ReadByte(); + packet->data.SkipBytes(nDataLength + 1); +} + +void BaseClient::SetName(char *newName) +{ + char temp[32]; + COM_RemoveEvilChars(newName); + COM_TrimSpace(newName, temp); + + if (strlen(temp) > sizeof(temp) - 1) { + temp[sizeof(temp) - 1] = '\0'; + } + + if (!temp[0] || !_stricmp(temp, "console")) { + strcpy(temp, "unnamed"); + } + + strcopy(m_ClientName, temp); + m_Userinfo.SetValueForKey("name", m_ClientName); +} + +void BaseClient::ParseHLTV(NetPacket *packet) +{ + Disconnect("TODO Client::ParseHLTV: Invalid client command.\n"); +} + +void BaseClient::ParseCvarValue(NetPacket *packet) +{ + packet->data.ReadString(); +} + +void BaseClient::ParseCvarValue2(NetPacket *packet) +{ + packet->data.ReadWord(); + packet->data.ReadString(); + packet->data.ReadString(); +} + +void BaseClient::QueryVoiceEnabled(BitBuffer *stream) +{ + int reqState = m_World->FindUserMsgByName("ReqState"); + if (!reqState || !m_World->IsVoiceEnabled()) + return; + + stream->WriteByte(reqState); +} + +void BaseClient::UpdateVoiceMask(BitBuffer *stream) +{ + int voiceMask = m_World->FindUserMsgByName("VoiceMask"); + if (!voiceMask) { + m_System->DPrintf("WARNING! Client::UpdateVoiceMask(): could find User Msg VoiceMaks.\n"); + return; + } + + if (!m_World->IsVoiceEnabled()) { + return; + } + + CPlayerBitVec gameRulesMask; + gameRulesMask[m_World->GetSlotNumber()] = !!m_VoiceEnabled; + + if (gameRulesMask != m_SentGameRulesMask || m_BanMask != m_SentBanMask) + { + m_SentGameRulesMask = gameRulesMask; + m_SentBanMask = m_BanMask; + + stream->WriteByte(voiceMask); + for (int dw = 0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + stream->WriteLong(gameRulesMask.GetDWord(dw)); + stream->WriteLong(m_BanMask.GetDWord(dw)); + } + } +} + +bool BaseClient::IsHearingVoices() +{ + return m_BanMask[m_World->GetSlotNumber()] ? true : false; +} + +bool BaseClient::HasChatEnabled() +{ + return false; +} + +void BaseClient::DownloadFile(char *fileName) +{ + if (!fileName || !fileName[0]) + return; + + DownloadFailed(fileName); +} + +void BaseClient::DownloadFailed(char *fileName) +{ + if (!fileName || !fileName[0]) + return; + + m_ClientChannel.m_reliableStream.WriteByte(svc_filetxferfailed); + m_ClientChannel.m_reliableStream.WriteString(fileName); +} + +void BaseClient::Send(unsigned char *data, int length, bool isReliable) +{ + if (isReliable) + m_ClientChannel.m_reliableStream.WriteBuf(data, length); + else + m_ClientChannel.m_unreliableStream.WriteBuf(data, length); +} + +NetAddress *BaseClient::GetAddress() +{ + return m_ClientChannel.GetTargetAddress(); +} + +int BaseClient::GetClientType() +{ + return m_ClientType; +} + +char *BaseClient::GetType() +{ + return CLIENT_INTERFACE_VERSION; +} + +void BaseClient::SendDatagram() +{ + frame_t *frame = m_World->GetLastFrame(); + if (frame) { + WriteDatagram(frame->time, frame); + } +} + +void BaseClient::Reset() +{ + SetState(CLIENT_CONNECTING); + + m_LastFrameSeqNr = 0; + m_DeltaFrameSeqNr = 0; + m_ClientDelta = 0; + + memset(m_SeqNrMap, 0, sizeof(m_SeqNrMap)); + m_VoiceQuery = true; + m_ClientChannel.Clear(); +} diff --git a/rehlds/HLTV/common/BaseClient.h b/rehlds/HLTV/common/BaseClient.h new file mode 100644 index 0000000..7ef1c50 --- /dev/null +++ b/rehlds/HLTV/common/BaseClient.h @@ -0,0 +1,176 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include +#include +#include + +#include "InfoString.h" +#include "NetChannel.h" +#include "BaseSystemModule.h" + +class TokenLine; +class BaseClient: public IClient, public BaseSystemModule { +public: + BaseClient() {} + virtual ~BaseClient() {} + + virtual bool Init(IBaseSystem *system, int serial, char *name); + virtual void RunFrame(double time); + virtual char *GetStatusLine(); + virtual char *GetType(); + virtual void ShutDown(); + virtual bool Connect(INetSocket *socket, NetAddress *adr, char *userinfo); + virtual void Disconnect(const char *reason = nullptr); + virtual void Reconnect(); + virtual void SetWorld(IWorld *world); + virtual bool IsHearingVoices(); + virtual bool HasChatEnabled(); + virtual NetAddress *GetAddress(); + virtual InfoString *GetUserInfo(); + virtual int GetClientType(); + virtual char *GetClientName(); + virtual bool IsActive(); + virtual void Send(unsigned char *data, int length, bool isReliable); + virtual void DownloadFailed(char *fileName); + virtual void DownloadFile(char *fileName); + virtual void UpdateVoiceMask(BitBuffer *stream); + virtual void QueryVoiceEnabled(BitBuffer *stream); + virtual void SetName(char *newName); + virtual void WriteSpawn(BitBuffer *stream); + virtual void WriteDatagram(double time, frame_t *frame); + virtual void SendDatagram(); + virtual void Reset(); + + enum ClientState { + CLIENT_UNDEFINED = 0, + CLIENT_INITIALIZING, + CLIENT_CONNECTING, + CLIENT_RUNNING, + CLIENT_DISCONNECTED + }; + + virtual void SetState(ClientState newState); + virtual void ReplyNew(); + virtual void ReplySpawn(int spawncount, int crcMap); + virtual void ReplyFullUpdate(); + virtual void PrintfToClient(char *fmt, ...); + virtual void UpdateUserInfo(char *userinfostring = nullptr); + virtual void ParseStringCmd(NetPacket *packet); + virtual void ParseNop(NetPacket *packet); + virtual void ParseBad(NetPacket *packet); + virtual void ParseMove(NetPacket *packet); + virtual void ParseVoiceData(NetPacket *packet); + virtual void ParseHLTV(NetPacket *packet); + virtual void ParseDelta(NetPacket *packet); + virtual void ParseCvarValue(NetPacket *packet); + virtual void ParseCvarValue2(NetPacket *packet); + virtual void ProcessMessage(NetPacket *packet); + virtual bool ProcessStringCmd(char *string); + +private: + enum LocalCommandIDs { + CMD_ID_NAME = 1, + CMD_ID_SPAWN, + CMD_ID_NEW, + CMD_ID_FULLUPDATE, + CMD_ID_DROPCLIENT, + CMD_ID_DLFILE, + CMD_ID_SETINFO, + CMD_ID_SHOWINFO, + CMD_ID_SENDENTS, + CMD_ID_VMODENABLE, + CMD_ID_VBAN, + CMD_ID_SENDERS, + CMD_ID_PING, + CMD_ID_SPECTATE, + CMD_ID_SPK, + CMD_ID_PAUSE, + CMD_ID_UNPAUSE, + CMD_ID_SETPAUSE + }; + + void CMD_Name(TokenLine *cmd); + void CMD_Spawn(TokenLine *cmd); + void CMD_New(TokenLine *cmd); + void CMD_FullUpdate(TokenLine *cmd); + void CMD_DropClient(TokenLine *cmd); + void CMD_DownloadFile(TokenLine *cmd); + void CMD_SetInfo(TokenLine *cmd); + void CMD_ShowInfo(TokenLine *cmd); + void CMD_SendEntities(TokenLine *cmd); + void CMD_VoiceModEnable(TokenLine *cmd); + void CMD_VoiceBan(TokenLine *cmd); + void CMD_SendResources(TokenLine *cmd); + void CMD_RequestPing(TokenLine *cmd); + void CMD_Spectate(TokenLine *cmd); + void CMD_Spk(TokenLine *cmd); + void CMD_Pause(TokenLine *cmd); + void CMD_UnPause(TokenLine *cmd); + void CMD_SetPause(TokenLine *cmd); + + struct LocalCommandID_s { + char *name; + LocalCommandIDs id; + void (BaseClient::*pfnCmd)(TokenLine *cmd); + }; + static LocalCommandID_s m_LocalCmdReg[]; + +protected: + struct clc_func_s { + clc_commands opcode; + char *pszname; + void (BaseClient::*func)(NetPacket *packet); + }; + static clc_func_s m_ClientFuncs[]; + + IWorld *m_World; + INetSocket *m_Socket; + NetChannel m_ClientChannel; + + int m_ClientType; + int m_ClientState; + char m_ClientName[32]; + + enum { MAX_USER_INFO = 256 }; + InfoString m_Userinfo; + unsigned int m_LastFrameSeqNr; + unsigned int m_DeltaFrameSeqNr; + unsigned int m_ClientDelta; + unsigned int m_SeqNrMap[256]; + + int m_CRC_Value; + bool m_VoiceEnabled; + bool m_VoiceQuery; + + CPlayerBitVec m_SentGameRulesMask; + CPlayerBitVec m_SentBanMask; + CPlayerBitVec m_BanMask; +}; diff --git a/rehlds/HLTV/common/BitBuffer.cpp b/rehlds/HLTV/common/BitBuffer.cpp new file mode 100644 index 0000000..4c9f872 --- /dev/null +++ b/rehlds/HLTV/common/BitBuffer.cpp @@ -0,0 +1,887 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +const uint32 BITTABLE[] = +{ + 0x00000001, 0x00000002, 0x00000004, 0x00000008, + 0x00000010, 0x00000020, 0x00000040, 0x00000080, + 0x00000100, 0x00000200, 0x00000400, 0x00000800, + 0x00001000, 0x00002000, 0x00004000, 0x00008000, + 0x00010000, 0x00020000, 0x00040000, 0x00080000, + 0x00100000, 0x00200000, 0x00400000, 0x00800000, + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x00000000, +}; + +const uint32 ROWBITTABLE[] = +{ + 0x00000000, 0x00000001, 0x00000003, 0x00000007, + 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F, + 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF, + 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF, + 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, + 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, + 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, + 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, + 0xFFFFFFFF, +}; + +const uint32 INVBITTABLE[] = +{ + 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFB, 0xFFFFFFF7, + 0xFFFFFFEF, 0xFFFFFFDF, 0xFFFFFFBF, 0xFFFFFF7F, + 0xFFFFFEFF, 0xFFFFFDFF, 0xFFFFFBFF, 0xFFFFF7FF, + 0xFFFFEFFF, 0xFFFFDFFF, 0xFFFFBFFF, 0xFFFF7FFF, + 0xFFFEFFFF, 0xFFFDFFFF, 0xFFFBFFFF, 0xFFF7FFFF, + 0xFFEFFFFF, 0xFFDFFFFF, 0xFFBFFFFF, 0xFF7FFFFF, + 0xFEFFFFFF, 0xFDFFFFFF, 0xFBFFFFFF, 0xF7FFFFFF, + 0xEFFFFFFF, 0xDFFFFFFF, 0xBFFFFFFF, 0x7FFFFFFF, + 0xFFFFFFFF, +}; + +BitBuffer::BitBuffer() : m_Data(nullptr), + m_CurByte(nullptr), + m_CurSize(0), + m_MaxSize(0), + m_Overflowed(false), + m_LittleEndian(false), + m_OwnData(false) +{ + ; +} + +BitBuffer::BitBuffer(void *newData, unsigned int size) +{ + m_Data = (unsigned char *)newData; + m_CurByte = m_Data; + + m_CurSize = 0; + m_MaxSize = size; + m_Overflowed = false; + m_LittleEndian = true; + m_OwnData = false; +} + +BitBuffer::~BitBuffer() +{ + Free(); +} + +BitBuffer::BitBuffer(unsigned int size) +{ + m_Data = nullptr; + m_CurByte = nullptr; + + m_CurSize = 0; + m_MaxSize = size; + m_Overflowed = false; + m_LittleEndian = false; + m_OwnData = false; + + Resize(size); +} + +bool BitBuffer::Resize(unsigned int size) +{ + Free(); + + m_Data = (unsigned char *)Mem_ZeroMalloc(size + 4); + m_CurSize = 0; + m_Overflowed = false; + + if (m_Data) + { + m_CurByte = m_Data; + m_MaxSize = size; + + m_OwnData = true; + m_LittleEndian = true; + return true; + } + + m_MaxSize = 0; + m_OwnData = false; + m_CurByte = nullptr; + + return false; +} + +void BitBuffer::Clear() +{ + memset(m_Data, 0, m_MaxSize); + + m_CurByte = m_Data; + m_CurSize = 0; + + m_Overflowed = false; + m_LittleEndian = true; +} + +int BitBuffer::CurrentBit() +{ + return m_CurSize + 8 * (m_CurByte - m_Data); +} + +void BitBuffer::Reset() +{ + m_CurByte = m_Data; + m_CurSize = 0; + + m_Overflowed = false; + m_LittleEndian = true; +} + +void BitBuffer::Free() +{ + if (m_Data && m_OwnData) { + free(m_Data); + } + + m_Data = nullptr; + m_CurByte = nullptr; + + m_CurSize = 0; + m_MaxSize = 0; + + m_OwnData = false; + m_Overflowed = false; + m_LittleEndian = true; +} + +unsigned int BitBuffer::ReadBits(int numbits) +{ + unsigned int result = 0; + if (m_LittleEndian) + { + if (m_CurByte - m_Data >= m_MaxSize) + { + m_Overflowed = true; + return -1; + } + + int bits = m_CurSize + numbits; + if (bits <= 32) + { + result = (*(unsigned int *)m_CurByte >> m_CurSize) & ROWBITTABLE[numbits]; + + m_CurByte += numbits >> 3; + m_CurSize += numbits & 7; + + if (m_CurSize > 7) + { + m_CurSize &= 7; + m_CurByte++; + } + } + else + { + unsigned int data = *(unsigned int *)m_CurByte >> m_CurSize; + m_CurByte += 4; + result = ((ROWBITTABLE[bits & 7] & *(unsigned int *)m_CurByte) << (32 - m_CurSize)) | data; + m_CurSize = bits & 7; + } + } + else + { + int d = numbits; + while (d > 0) + { + --d; + if (ReadBit()) { + result |= (1 << d); + } + } + } + + return result; +} + +int BitBuffer::ReadBit() +{ + int result; + if (m_CurByte - m_Data >= m_MaxSize) { + m_Overflowed = true; + result = -1; + } + else + { + if (m_LittleEndian) + { + if (m_CurSize == 7) + { + m_CurSize = 0; + result = (*m_CurByte++ >> 7) & 1; + } + else + { + result = ((unsigned int)*m_CurByte >> m_CurSize++) & 1; + } + } + else + { + if (m_CurSize == 7) + { + m_CurSize = 0; + result = *m_CurByte++ & 1; + } + else + { + result = ((unsigned int)*m_CurByte >> (7 - m_CurSize++)) & 1; + } + } + } + + return result; +} + +unsigned int BitBuffer::PeekBits(int numbits) +{ + int oldcurrentBit = m_CurSize; + unsigned char *oldcurrentByte = m_CurByte; + unsigned int data = ReadBits(numbits); + + m_CurSize = oldcurrentBit; + m_CurByte = oldcurrentByte; + return data; +} + +int BitBuffer::ReadChar() +{ + return ReadBits(8); +} + +int BitBuffer::ReadByte() +{ + return ReadBits(8); +} + +int BitBuffer::ReadShort() +{ + return ReadBits(16); +} + +int BitBuffer::ReadWord() +{ + return ReadBits(16); +} + +unsigned int BitBuffer::ReadLong() +{ + return ReadBits(32); +} + +float BitBuffer::ReadFloat() +{ + union { + float f; + int i; + } dat; + + dat.i = _LittleLong(ReadLong()); + return dat.f; +} + +bool BitBuffer::ReadBuf(int iSize, void *pbuf) +{ + if (m_CurByte - m_Data + iSize > m_MaxSize) { + m_Overflowed = true; + return false; + } + + if (m_CurSize) + { + int i, j; + unsigned int *p = (unsigned int *)pbuf; + for (i = 4; i < iSize; i += 4) { + *p++ = ReadLong(); + } + + for (j = 0; j < iSize - (i - 4); ++j) { + *((unsigned char *)p + j) = ReadByte(); + } + } + else + { + memcpy(pbuf, m_CurByte, iSize); + m_CurByte += iSize; + } + + return true; +} + +void BitBuffer::WriteBuf(BitBuffer *buf, int length) +{ + WriteBuf(buf->m_CurByte, length); + buf->SkipBytes(length); +} + +char *BitBuffer::ReadString() +{ + int c = 0, l = 0; + static char string[8192]; + + while ((c = ReadChar(), c) && c != -1 && l < sizeof(string) - 1) { + string[l++] = c; + } + + string[l] = '\0'; + return string; +} + +char *BitBuffer::ReadStringLine() +{ + int c = 0, l = 0; + static char string[2048]; + + while ((c = ReadChar(), c) && c != '\n' && c != -1 && l < sizeof(string) - 1) { + string[l++] = c; + } + + string[l] = '\0'; + return string; +} + +float BitBuffer::ReadAngle() +{ + int c = ReadChar(); + if (c == -1) + { + // FIXED: Added check for wrong value, but just return 0 instead of -1 * (360.0 / 256) + return 0; + } + + return (float)(c * (360.0 / 256)); +} + +float BitBuffer::ReadHiresAngle() +{ + int c = ReadShort(); + if (c == -1) + { + // FIXED: Added check for wrong value, but just return 0 instead of -1 * (360.0 / 65536) + return 0; + } + + return (float)(c * (360.0 / 65536)); +} + +void BitBuffer::WriteBit(int c) +{ + if (m_CurByte - m_Data >= m_MaxSize) { + m_Overflowed = true; + return; + } + + if (m_LittleEndian) + { + if (m_CurSize == 7) + { + if (c) + { + m_CurByte[0] |= 0x80u; + } + else + { + m_CurByte[0] &= 0x7Fu; + } + + m_CurByte++; + m_CurSize = 0; + } + else + { + if (c) + { + m_CurByte[0] |= BITTABLE[ m_CurSize ]; + } + else + { + m_CurByte[0] &= INVBITTABLE[ m_CurSize ]; + } + + m_CurSize++; + } + } + else + { + static unsigned char masks[] = { 0x80u, 0x40u, 0x20u, 0x10u, 0x8u, 0x4u, 0x2u, 0x1u }; + static unsigned char inv_masks[] = { 0x7Fu, 0xBFu, 0xDFu, 0xEFu, 0xF7u, 0xFBu, 0xFDu, 0xFEu }; + + if (c) + m_CurByte[0] |= masks[ m_CurSize ]; + else + m_CurByte[0] &= inv_masks[ m_CurSize ]; + + if (++m_CurSize == 8) + { + m_CurSize = 0; + m_CurByte++; + } + } +} + +void BitBuffer::WriteBits(unsigned int data, int numbits) +{ + if (m_Overflowed) { + return; + } + + if (m_LittleEndian) + { + if (m_CurByte - m_Data + (numbits >> 8) > m_MaxSize) { + m_Overflowed = true; + return; + } + + int bits = numbits + m_CurSize; + if (bits <= 32) + { + *(uint32 *)m_CurByte |= (ROWBITTABLE[numbits] & data) << m_CurSize; + + m_CurByte = &m_CurByte[numbits >> 3]; + m_CurSize = m_CurSize + (numbits & 7); + + if (m_CurSize > 7) + { + m_CurSize = m_CurSize & 7; + m_CurByte = m_CurByte + 1; + } + } + else + { + *(uint32 *)m_CurByte |= (ROWBITTABLE[numbits] & data) << m_CurSize; + + int leftBits = (32 - m_CurSize); + m_CurSize = (m_CurSize + numbits) & 7; + + m_CurByte += 4; + *(uint32 *)m_CurByte |= (ROWBITTABLE[numbits] & data) >> leftBits; + } + + return; + } + + int nBitValue = data; + if (numbits <= 31 && nBitValue >= (1 << numbits) && nBitValue != -1) + nBitValue = (1 << numbits) - 1; + + while (--numbits > 0) + { + if (m_CurByte - m_Data >= m_MaxSize) { + m_Overflowed = true; + break; + } + + WriteBit(nBitValue & (1 << numbits)); + } +} + +void BitBuffer::WriteSBits(int data, int numbits) +{ + int idata = data; + if (numbits < 32) + { + int maxnum = (1 << (numbits - 1)) - 1; + if (data > maxnum || (maxnum = -maxnum, data < maxnum)) + { + idata = maxnum; + } + } + + int sigbits = idata < 0; + + WriteBit(sigbits); + WriteBits(abs(idata), numbits - 1); +} + +void BitBuffer::WriteChar(int c) +{ + WriteBits(c, 8 * sizeof(char)); +} + +void BitBuffer::WriteByte(int c) +{ + WriteBits(c, 8 * sizeof(uint8)); +} + +void BitBuffer::WriteShort(int c) +{ + WriteBits(c, 8 * sizeof(int16)); +} + +void BitBuffer::WriteWord(int c) +{ + WriteBits(c, 8 * sizeof(uint16)); +} + +void BitBuffer::WriteLong(unsigned int c) +{ + WriteBits(c, 8 * sizeof(uint32)); +} + +void BitBuffer::WriteFloat(float f) +{ + union { + float f; + int i; + } dat; + + dat.f = f; + WriteBits(_LittleLong(dat.i), 8 * sizeof(float)); +} + +void BitBuffer::WriteString(const char *p) +{ + if (p) + { + WriteBuf(p, strlen(p) + 1); + } + else + { + WriteChar('\0'); + } +} + +void BitBuffer::WriteBuf(const void *buf, int iSize) +{ + if (!buf || m_Overflowed || !iSize) { + return; + } + + if (m_CurByte - m_Data + iSize > m_MaxSize) { + m_Overflowed = true; + return; + } + + if (m_CurSize) + { + int i, j; + unsigned int *p = (unsigned int *)buf; + + for (i = 4; i < iSize; i += 4) { + WriteLong(*p++); + } + + for (j = 0; j < (iSize - (i - 4)); j++) { + WriteChar(*((unsigned char *)p + j)); + } + } + else + { + memcpy(m_CurByte, buf, iSize); + m_CurByte += iSize; + } +} + +void BitBuffer::WriteBitData(void *src, int length) +{ + int i; + unsigned char *p = (unsigned char *)src; + for (i = 0; i < length; i++, p++) + { + WriteChar(*p); + } +} + +void BitBuffer::WriteAngle(float f) +{ + WriteByte((int64)(fmod((double)f, 360.0) * 256.0 / 360.0) & 0xFF); +} + +void BitBuffer::WriteHiresAngle(float f) +{ + WriteShort((int64)(fmod((double)f, 360.0) * 65536.0 / 360.0) & 0xFFFF); +} + +int BitBuffer::CurrentSize() +{ + return (m_CurSize != 0) + m_CurByte - m_Data; +} + +unsigned char *BitBuffer::CurrentByte() +{ + return m_CurByte; +} + +int BitBuffer::SpaceLeft() +{ + return m_MaxSize + m_Data - m_CurByte; +} + +void BitBuffer::AlignByte() +{ + if (m_CurSize) + { + m_CurByte++; + m_CurSize = 0; + } +} + +int BitBuffer::ReadSBits(int numbits) +{ + int nSignBit = ReadBit(); + int result = ReadBits(numbits - 1); + + if (nSignBit) + { + result = -result; + } + + return result; +} + +float BitBuffer::ReadBitAngle(int numbits) +{ + return (float)(ReadBits(numbits) * (360.0 / (1 << numbits))); +} + +void BitBuffer::WriteBitAngle(float fAngle, int numbits) +{ + if (numbits >= 32) { + m_Overflowed = true; + return; + } + + unsigned int shift = (1 << numbits); + unsigned int mask = shift - 1; + + int d = (int)(shift * fmod((double)fAngle, 360.0)) / 360; + d &= mask; + + WriteBits(d, numbits); +} + +char *BitBuffer::ReadBitString() +{ + static char buf[8192]; + buf[0] = '\0'; + + char *p = &buf[0]; + for (unsigned int c = ReadChar(); c; c = ReadChar()) + { + // Prevent infinite cycle if m_Overflowed + if (m_Overflowed) { + break; + } + + *p++ = c; + } + + *p = '\0'; + return buf; +} + +void BitBuffer::WriteBitString(const char *p) +{ + const unsigned char *pch = (unsigned char *)p; + while (*pch) + { + WriteChar(*pch++); + } + + WriteChar('\0'); +} + +void BitBuffer::StartBitMode() +{ + if (m_CurSize) { + m_Overflowed = true; + } +} + +void BitBuffer::EndBitMode() +{ + AlignByte(); +} + +int BitBuffer::ReadBitData(void *dest, int length) +{ + unsigned char *p = (unsigned char *)dest; + for (int i = 0; i < length; i++) { + *p++ = ReadByte(); + } + + return length; +} + +void BitBuffer::SetBuffer(void *buffer, int size) +{ + Free(); + + m_Data = (unsigned char *)buffer; + m_CurByte = (unsigned char *)buffer; + m_MaxSize = size; + m_CurSize = 0; + + m_OwnData = false; + m_Overflowed = false; + m_LittleEndian = true; +} + +void BitBuffer::ReadBitVec3Coord(float *fa) +{ + int xflag = ReadBit(); + int yflag = ReadBit(); + int zflag = ReadBit(); + + if (xflag) + fa[0] = ReadBitCoord(); + if (yflag) + fa[1] = ReadBitCoord(); + if (zflag) + fa[2] = ReadBitCoord(); +} + +float BitBuffer::ReadBitCoord() +{ + float value = 0; + + int intval = ReadBit(); + int fractval = ReadBit(); + + if (intval || fractval) + { + int signbit = ReadBit(); + if (intval) { + intval = ReadBits(12); + } + + if (fractval) { + fractval = ReadBits(3); + } + + value = (float)(fractval / 8.0 + intval); + if (signbit) { + value = -value; + } + } + + return value; +} + +float BitBuffer::ReadCoord() +{ + return (float)(ReadShort() * (1.0 / 8)); +} + +void BitBuffer::SkipBytes(int numbits) +{ + if (numbits + m_CurByte - m_Data > m_MaxSize) { + m_Overflowed = true; + } + + m_CurByte += numbits; +} + +void BitBuffer::SkipBits(int numbits) +{ + if (m_LittleEndian) + { + if (m_CurByte - m_Data >= m_MaxSize) + { + m_Overflowed = true; + return; + } + + int bits = m_CurSize + numbits; + if (bits <= 32) + { + m_CurByte += numbits >> 3; + m_CurSize += numbits & 7; + + if (m_CurSize > 7) + { + m_CurSize &= 7; + m_CurByte++; + } + } + else + { + m_CurByte += 4; + m_CurSize = bits & 7; + } + } + else + { + int d = numbits; + while (d > 0) + { + --d; + if (m_CurSize == 7) + { + m_CurByte++; + m_CurSize = 0; + } + else + { + m_CurSize++; + } + } + } +} + +int BitBuffer::SkipString() +{ + int c = 0, l = 1; + const int maxString = 8192; + + while ((c = ReadChar(), c) && c != -1 && l < maxString) { + l++; + } + + return l; +} + +void BitBuffer::FastClear() +{ + int iSize = CurrentSize() + 4; + if (iSize > m_MaxSize) { + iSize = m_MaxSize; + } + + memset(m_Data, 0, iSize); + + m_CurByte = m_Data; + m_CurSize = 0; + + m_Overflowed = false; + m_LittleEndian = true; +} + +void BitBuffer::ConcatBuffer(BitBuffer *buffer) +{ + WriteBuf(buffer->m_Data, buffer->CurrentSize()); +} + +void BitBuffer::WriteCoord(float f) +{ + WriteShort((int)(f * 8.0)); +} diff --git a/rehlds/HLTV/common/BitBuffer.h b/rehlds/HLTV/common/BitBuffer.h new file mode 100644 index 0000000..119e6b6 --- /dev/null +++ b/rehlds/HLTV/common/BitBuffer.h @@ -0,0 +1,117 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +class BitBuffer { +public: + BitBuffer(); + BitBuffer(unsigned int size); + BitBuffer(void *newData, unsigned int size); + virtual ~BitBuffer(); + + unsigned int PeekBits(int numbits); + int CurrentBit(); + int CurrentSize(); + unsigned char *CurrentByte(); + + int GetMaxSize() const { return m_MaxSize; } + unsigned int GetCurSize() const { return m_CurSize; } + unsigned char *GetData() const { return m_Data; } + bool IsOverflowed() const { return m_Overflowed; } + + void SetBuffer(void *buffer, int size); + void Free(); + void Reset(); + void Clear(); + void FastClear(); + int SpaceLeft(); + void EndBitMode(); + void StartBitMode(); + bool Resize(unsigned int size); + void ConcatBuffer(BitBuffer *buffer); + int SkipString(); + + void SkipBits(int numbits); + void SkipBytes(int numbits); + + void AlignByte(); + + // function's read stuff + unsigned int ReadBits(int numbits); + int ReadBit(); + int ReadChar(); + int ReadByte(); + int ReadShort(); + int ReadWord(); + + unsigned int ReadLong(); + float ReadFloat(); + char *ReadString(); + char *ReadStringLine(); + char *ReadBitString(); + int ReadSBits(int numbits); + float ReadBitAngle(int numbits); + int ReadBitData(void *dest, int length); + bool ReadBuf(int iSize, void *pbuf); + float ReadAngle(); + float ReadHiresAngle(); + float ReadCoord(); + float ReadBitCoord(); + void ReadBitVec3Coord(float *fa); + + // function's write stuff + void WriteBits(unsigned int data, int numbits); + void WriteBit(int c); + void WriteChar(int c); + void WriteByte(int c); + void WriteShort(int c); + void WriteWord(int c); + void WriteLong(unsigned int c); + void WriteFloat(float f); + void WriteString(const char *p); + void WriteBitString(const char *p); + void WriteSBits(int data, int numbits); + void WriteBitAngle(float fAngle, int numbits); + void WriteBitData(void *src, int length); + void WriteBuf(const void *buf, int iSize); + void WriteBuf(BitBuffer *buf, int length); + void WriteAngle(float f); + void WriteHiresAngle(float f); + void WriteCoord(float f); + + bool m_Overflowed; + unsigned char *m_Data; + unsigned char *m_CurByte; + int m_CurSize; + int m_MaxSize; + +protected: + bool m_LittleEndian; + bool m_OwnData; +}; diff --git a/rehlds/HLTV/common/DemoFile.cpp b/rehlds/HLTV/common/DemoFile.cpp new file mode 100644 index 0000000..f676d8e --- /dev/null +++ b/rehlds/HLTV/common/DemoFile.cpp @@ -0,0 +1,604 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +DemoFile::DemoFile() : + m_FileSystem(nullptr), + m_FileHandle(FILESYSTEM_INVALID_HANDLE), + m_DemoChannel(nullptr), + m_Entries(nullptr) +{ + Reset(); +} + +void DemoFile::Init(IWorld *world, IServer *server, NetChannel *channel) +{ + m_World = world; + m_Server = server; + m_System = world->GetSystem(); + m_FileSystem = m_System->GetFileSystem(); + + m_DemoChannel = channel; + m_Entries = nullptr; + + Reset(); +} + +void DemoFile::Reset() +{ + memset(m_FileName, 0, sizeof(m_FileName)); + memset(&m_zeroDemoInfo, 0, sizeof(m_zeroDemoInfo)); + + CloseFile(); + m_Continuous = true; +} + +bool DemoFile::IsRecording() +{ + return m_DemoState == DEMO_RECORDING; +} + +void DemoFile::CloseFile() +{ + unsigned char c; + float f; + int curpos; + int i; + + if (m_FileSystem && m_FileHandle != FILESYSTEM_INVALID_HANDLE) + { + if (m_DemoState == DEMO_RECORDING) + { + c = 5; + m_FileSystem->Write(&c, sizeof(unsigned char), m_FileHandle); + + f = _LittleFloat(GetDemoTime()); + m_FileSystem->Write(&f, sizeof(float), m_FileHandle); + + i = _LittleLong(m_frameCount); + m_FileSystem->Write(&i, sizeof(int), m_FileHandle); + + curpos = m_FileSystem->Tell(m_FileHandle); + + m_gameEntry.nFileLength = curpos - m_gameEntry.nOffset; + m_gameEntry.fTrackTime = GetDemoTime(); + m_gameEntry.nFrames = m_frameCount; + + i = 2; + m_FileSystem->Write(&i, sizeof(int), m_FileHandle); + m_FileSystem->Write(&m_loadEntry, sizeof(m_loadEntry), m_FileHandle); + m_FileSystem->Write(&m_gameEntry, sizeof(m_gameEntry), m_FileHandle); + + m_demoHeader.nDirectoryOffset = curpos; + m_FileSystem->Seek(m_FileHandle, 0, FILESYSTEM_SEEK_HEAD); + m_FileSystem->Write(&m_demoHeader, sizeof(m_demoHeader), m_FileHandle); + m_System->Printf("Completed demo %s.\n", m_FileName); + } + + m_FileSystem->Close(m_FileHandle); + } + + if (m_Entries) + { + free(m_Entries); + m_Entries = nullptr; + } + + m_FileHandle = FILESYSTEM_INVALID_HANDLE; + m_DemoState = DEMO_IDLE; +} + +void DemoFile::WriteDemoInfo(demo_info_t *demoInfo) +{ + m_FileSystem->Write(demoInfo, sizeof(*demoInfo), m_FileHandle); +} + +void DemoFile::WriteSequenceInfo() +{ + m_FileSystem->Write(&m_DemoChannel->m_outgoing_sequence, sizeof(int), m_FileHandle); + m_FileSystem->Write(&m_DemoChannel->m_incoming_sequence, sizeof(int), m_FileHandle); + m_FileSystem->Write(&m_DemoChannel->m_last_reliable_sequence, sizeof(int), m_FileHandle); + m_FileSystem->Write(&m_DemoChannel->m_reliable_sequence, sizeof(int), m_FileHandle); + m_FileSystem->Write(&m_DemoChannel->m_incoming_acknowledged, sizeof(int), m_FileHandle); + m_FileSystem->Write(&m_DemoChannel->m_incoming_reliable_sequence, sizeof(int), m_FileHandle); + m_FileSystem->Write(&m_DemoChannel->m_incoming_reliable_acknowledged, sizeof(int), m_FileHandle); +} + +void DemoFile::WriteDemoStartup(BitBuffer *buffer) +{ + unsigned char c; + int i; + float f; + + int len = buffer->CurrentSize(); + if (len <= 0) { + return; + } + + c = 0; + m_FileSystem->Write(&c, sizeof(unsigned char), m_FileHandle); + + f = _LittleFloat(GetDemoTime()); + m_FileSystem->Write(&f, sizeof(float), m_FileHandle); + + i = _LittleLong(m_frameCount); + m_FileSystem->Write(&i, sizeof(int), m_FileHandle); + + WriteDemoInfo(&m_zeroDemoInfo); + WriteSequenceInfo(); + + i = _LittleLong(len); + m_FileSystem->Write(&i, sizeof(int), m_FileHandle); + m_FileSystem->Write(buffer->GetData(), len, m_FileHandle); +} + +void DemoFile::WriteDemoMessage(BitBuffer *unreliableData, BitBuffer *reliableData) +{ + int len; + int i; + float f; + unsigned char c; + + len = reliableData->CurrentSize() + unreliableData->CurrentSize(); + if (len <= 0 || m_FileHandle == FILESYSTEM_INVALID_HANDLE) { + return; + } + + if (!m_FileSystem) { + return; + } + + c = 1; + m_frameCount++; + + m_FileSystem->Write(&c, sizeof(unsigned char), m_FileHandle); + + f = _LittleFloat(GetDemoTime()); + m_FileSystem->Write(&f, sizeof(float), m_FileHandle); + + i = _LittleLong(m_frameCount); + m_FileSystem->Write(&i, sizeof(int), m_FileHandle); + + WriteDemoInfo(&m_zeroDemoInfo); + WriteSequenceInfo(); + + i = _LittleLong(len); + m_FileSystem->Write(&i, sizeof(int), m_FileHandle); + m_FileSystem->Write(unreliableData->GetData(), unreliableData->CurrentSize(), m_FileHandle); + m_FileSystem->Write(reliableData->GetData(), reliableData->CurrentSize(), m_FileHandle); +} + +void DemoFile::WriteUpdateClientData(client_data_t *cdata) +{ + if (!m_FileSystem || m_FileHandle == FILESYSTEM_INVALID_HANDLE) { + return; + } + + unsigned char cmd = 4; + m_FileSystem->Write(&cmd, sizeof(unsigned char), m_FileHandle); + + float f = _LittleFloat(GetDemoTime()); + m_FileSystem->Write(&f, sizeof(float), m_FileHandle); + + int i = _LittleLong(m_frameCount); + m_FileSystem->Write(&i, sizeof(int), m_FileHandle); + m_FileSystem->Write(cdata, sizeof(*cdata), m_FileHandle); +} + +float DemoFile::GetDemoTime() +{ + return m_System->GetTime() - m_startTime; +} + +void DemoFile::WriteSignonData() +{ + BitBuffer buffer(MAX_POSSIBLE_MSG * 2); + m_World->WriteNewData(&buffer); + m_World->WriteSigonData(&buffer); + + buffer.WriteByte(svc_time); + buffer.WriteFloat(GetDemoTime()); + + for (int i = 0; i < m_World->GetMaxClients(); i++) { + m_World->WriteClientUpdate(&buffer, i); + } + + m_World->WriteLightStyles(&buffer); + + buffer.WriteByte(svc_signonnum); + buffer.WriteByte(1); + + WriteDemoStartup(&buffer); +} + +bool DemoFile::StartRecording(char *newName) +{ + unsigned char b; + int i; + float f; + + if (IsPlaying() || !m_FileSystem) { + return false; + } + + if (m_FileHandle != FILESYSTEM_INVALID_HANDLE) { + CloseFile(); + } + + strcopy(m_FileName, newName); + + m_FileHandle = m_FileSystem->Open(m_FileName, "wb"); + if (!m_FileHandle) { + m_System->Printf("WARNING! DemoFile::StartRecording: coudn't open demo file %s.\n", m_FileName); + return false; + } + + memset(&m_demoHeader, 0, sizeof(m_demoHeader)); + strcopy(m_demoHeader.szFileStamp, "HLDEMO"); + + COM_FileBase(m_World->GetLevelName(), m_demoHeader.szMapName); + COM_FileBase(m_World->GetGameDir(), m_demoHeader.szDllDir); + + m_demoHeader.mapCRC = 0; + m_demoHeader.nDemoProtocol = DEMO_VERSION; + m_demoHeader.nNetProtocolVersion = PROTOCOL_VERSION; + m_demoHeader.nDirectoryOffset = 0; + m_FileSystem->Write(&m_demoHeader, sizeof(m_demoHeader), m_FileHandle); + + memset(&m_loadEntry, 0, sizeof(m_loadEntry)); + strcopy(m_loadEntry.szDescription, "LOADING"); + + m_loadEntry.nEntryType = 0; + m_loadEntry.nOffset = m_FileSystem->Tell(m_FileHandle); + + m_frameCount = 0; + m_startTime = m_System->GetTime(); + + WriteSignonData(); + + b = 5; + m_FileSystem->Write(&b, sizeof(unsigned char), m_FileHandle); + + f = _LittleFloat(GetDemoTime()); + m_FileSystem->Write(&f, sizeof(float), m_FileHandle); + + i = _LittleLong(m_frameCount); + m_FileSystem->Write(&i, sizeof(int), m_FileHandle); + + m_loadEntry.nFileLength = m_FileSystem->Tell(m_FileHandle) - m_loadEntry.nOffset; + + memset(&m_gameEntry, 0, sizeof(m_gameEntry)); + _snprintf(m_gameEntry.szDescription, sizeof(m_gameEntry.szDescription), "Playback"); + m_gameEntry.nEntryType = 1; + m_gameEntry.nOffset = m_FileSystem->Tell(m_FileHandle); + + b = 2; + m_FileSystem->Write(&b, sizeof(unsigned char), m_FileHandle); + + f = _LittleFloat(GetDemoTime()); + m_FileSystem->Write(&f, sizeof(float), m_FileHandle); + + i = _LittleLong(m_frameCount); + m_FileSystem->Write(&i, sizeof(int), m_FileHandle); + + m_DemoState = DEMO_RECORDING; + m_System->Printf("Start recording to %s.\n", m_FileName); + + return true; +} + +bool DemoFile::IsPlaying() +{ + return m_DemoState == DEMO_PLAYING; +} + +bool DemoFile::LoadDemo(char *demoname) +{ + if (IsRecording()) { + m_System->Printf("Cannot load demo, still recording.\n"); + return false; + } + + if (!m_FileSystem) { + return false; + } + + CloseFile(); + + strcopy(m_FileName, demoname); + _strlwr(m_FileName); + + if (!strstr(m_FileName, ".dem")) { + strcat(m_FileName, ".dem"); + } + + m_FileHandle = m_FileSystem->Open(m_FileName, "rb"); + if (!m_FileHandle) { + m_System->Printf("Coudn't open demo file %s.\n", m_FileName); + return false; + } + + memset(&m_demoHeader, 0, sizeof(m_demoHeader)); + m_FileSystem->Read(&m_demoHeader, sizeof(m_demoHeader), m_FileHandle); + + if (strcmp(m_demoHeader.szFileStamp, "HLDEMO") != 0) { + m_System->Printf("%s is not a HL demo file.\n", m_FileName); + m_FileSystem->Close(m_FileHandle); + return false; + } + + if (m_demoHeader.nNetProtocolVersion != PROTOCOL_VERSION || m_demoHeader.nDemoProtocol != DEMO_VERSION) { + m_System->Printf("WARNING! %s has an outdated demo format.\n", m_FileName); + } + + int fileMarker = m_FileSystem->Tell(m_FileHandle); + m_FileSystem->Seek(m_FileHandle, m_demoHeader.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + m_FileSystem->Read(&m_EntryNumber, sizeof(int), m_FileHandle); + m_CurrentEntry = 0; + + if (m_EntryNumber > 0 && m_EntryNumber <= 1024) + { + m_Entries = (demoentry_t *)Mem_ZeroMalloc(m_EntryNumber * MAX_DEMO_ENTRY); + m_FileSystem->Read(m_Entries, m_EntryNumber * MAX_DEMO_ENTRY, m_FileHandle); + m_FileSystem->Seek(m_FileHandle, m_Entries[m_CurrentEntry].nOffset, FILESYSTEM_SEEK_HEAD); + } + else + { + m_EntryNumber = 2; + m_Entries = nullptr; + + m_System->Printf("WARNING! Demo had bogus number of directory entries!\n"); + m_FileSystem->Seek(m_FileHandle, fileMarker, FILESYSTEM_SEEK_HEAD); + } + + m_startTime = m_System->GetTime(); + m_nextReadTime = m_System->GetTime(); + + m_Continuous = true; + memset(&m_ServerInfo, 0, sizeof(m_ServerInfo)); + + strcopy(m_ServerInfo.address, m_DemoChannel->m_remote_address.ToBaseString()); + strcopy(m_ServerInfo.name, m_FileName); + strcopy(m_ServerInfo.map, m_demoHeader.szMapName); + strcopy(m_ServerInfo.gamedir, m_demoHeader.szDllDir); + strcopy(m_ServerInfo.description, "Demo Playback"); + + m_ServerInfo.activePlayers = 0; + m_ServerInfo.maxPlayers = MAX_CLIENTS; + m_ServerInfo.protocol = m_demoHeader.nNetProtocolVersion; + m_ServerInfo.type = GetServerType(HLST_Dedicated)[0]; + m_ServerInfo.os = GetServerOS()[0]; + m_ServerInfo.pw = '\0'; + m_ServerInfo.mod = false; + m_DemoState = DEMO_PLAYING; + + return true; +} + +void DemoFile::StopPlayBack() +{ + if (m_DemoState != DEMO_PLAYING) { + return; + } + + CloseFile(); + if (m_Server) { + m_Server->Disconnect(); + } +} + +void DemoFile::ReadDemoPacket(BitBuffer *demoData, demo_info_t *demoInfo) +{ + if (!m_FileHandle || (m_nextReadTime > m_System->GetTime() && m_Continuous)) { + return; + } + + int msglen; + unsigned char msgbuf[MAX_POSSIBLE_MSG]; + float time; + unsigned char cmd; + int frame; + int channel; + int sampleSize; + + bool readNextCmd = true; + while (readNextCmd) + { + unsigned int curpos = m_FileSystem->Tell(m_FileHandle); + if (m_FileSystem->Read(&cmd, sizeof(unsigned char), m_FileHandle) != 1) { + StopPlayBack(); + return; + } + + m_FileSystem->Read(&time, sizeof(float), m_FileHandle); + time = _LittleFloat(time); + + m_FileSystem->Read(&frame, sizeof(int), m_FileHandle); + frame = _LittleLong(frame); + + if (cmd && cmd != 5) { + m_nextReadTime = m_startTime + time; + } + + if (m_nextReadTime > m_System->GetTime() && m_Continuous) { + m_FileSystem->Seek(m_FileHandle, curpos, FILESYSTEM_SEEK_HEAD); + return; + } + + msglen = 0; + + // TODO: Find out or guess the names of the opcode + switch (cmd) + { + case 2: + m_startTime = (float)m_System->GetTime(); + break; + case 3: + msglen = 64; + break; + case 4: + msglen = 32; + break; + case 5: + { + if (++m_CurrentEntry >= m_EntryNumber) { + StopPlayBack(); + return; + } + + if (m_Entries) { + m_FileSystem->Seek(m_FileHandle, m_Entries[m_CurrentEntry].nOffset, FILESYSTEM_SEEK_HEAD); + } + break; + } + case 6: + msglen = 84; + break; + case 7: + msglen = 8; + break; + case 8: + { + m_FileSystem->Read(&channel, sizeof(int), m_FileHandle); + channel = _LittleLong(channel); + + m_FileSystem->Read(&sampleSize, sizeof(int), m_FileHandle); + sampleSize = _LittleLong(sampleSize); + msglen = sampleSize + 16; + break; + } + case 9: + { + m_FileSystem->Read(&msglen, sizeof(int), m_FileHandle); + msglen = _LittleLong(msglen); + break; + } + default: + readNextCmd = false; + break; + } + + if (msglen) + { + m_FileSystem->Read(msgbuf, msglen, m_FileHandle); + + demoData->WriteByte(cmd); + + switch (cmd) + { + case 8: + demoData->WriteLong(channel); + demoData->WriteLong(sampleSize); + break; + case 9: + demoData->WriteLong(msglen); + break; + } + + demoData->WriteBuf(msgbuf, msglen); + } + } + + ReadDemoInfo(demoInfo); + ReadSequenceInfo(); + + int length; + if (m_FileSystem->Read(&length, sizeof(int), m_FileHandle) != 4) { + m_System->DPrintf("WARNING! DemoFile::ReadDemoPacket: Bad demo length.\n"); + StopPlayBack(); + return; + } + + length = _LittleLong(length); + if (length < 0) { + m_System->DPrintf("WARNING! DemoFile::ReadDemoPacket: Demo message length < 0.\n"); + StopPlayBack(); + return; + } + + if (length > MAX_POSSIBLE_MSG) { + m_System->DPrintf("WARNING! DemoFile::ReadDemoPacket: message length > MAX_POSSIBLE_MSG\n"); + StopPlayBack(); + return; + } + + if (length > 0) + { + if (m_FileSystem->Read(msgbuf, length, m_FileHandle) != length) { + m_System->DPrintf("WARNING! DemoFile::ReadDemoPacket: Error reading demo message data.\n"); + StopPlayBack(); + return; + } + + NetPacket *p = new NetPacket; + + p->connectionless = false; + p->time = m_System->GetTime(); + p->seqnr = m_DemoChannel->m_incoming_sequence; + p->data.Resize(length); + p->data.WriteBuf(msgbuf, length); + p->data.Reset(); + + m_DemoChannel->m_incomingPackets.AddHead(p); + } +} + +void DemoFile::ReadDemoInfo(demo_info_t *demoInfo) +{ + m_FileSystem->Read(demoInfo, sizeof(*demoInfo), m_FileHandle); + + demoInfo->rp.cmd = &demoInfo->cmd; + demoInfo->rp.movevars = &demoInfo->movevars; +} + +void DemoFile::ReadSequenceInfo() +{ + m_FileSystem->Read(&m_DemoChannel->m_incoming_sequence, sizeof(int), m_FileHandle); + m_FileSystem->Read(&m_DemoChannel->m_incoming_acknowledged, sizeof(int), m_FileHandle); + m_FileSystem->Read(&m_DemoChannel->m_incoming_reliable_acknowledged, sizeof(int), m_FileHandle); + m_FileSystem->Read(&m_DemoChannel->m_incoming_reliable_sequence, sizeof(int), m_FileHandle); + m_FileSystem->Read(&m_DemoChannel->m_outgoing_sequence, sizeof(int), m_FileHandle); + m_FileSystem->Read(&m_DemoChannel->m_reliable_sequence, sizeof(int), m_FileHandle); + m_FileSystem->Read(&m_DemoChannel->m_last_reliable_sequence, sizeof(int), m_FileHandle); +} + +char *DemoFile::GetFileName() +{ + return m_FileName; +} + +bool DemoFile::IsContinuous() +{ + return m_Continuous; +} + +void DemoFile::SetContinuous(bool state) +{ + m_Continuous = state; +} diff --git a/rehlds/HLTV/common/DemoFile.h b/rehlds/HLTV/common/DemoFile.h new file mode 100644 index 0000000..9fc46df --- /dev/null +++ b/rehlds/HLTV/common/DemoFile.h @@ -0,0 +1,135 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include +#include + +#include "usercmd.h" +#include "ref_params.h" +#include "common/ServerInfo.h" + +#include "vmodes.h" +#include "cdll_int.h" + +#define DEMO_VERSION 5 +#define MAX_DEMO_ENTRY 92 + +typedef struct demoheader_s { + char szFileStamp[6]; + int nDemoProtocol; + int nNetProtocolVersion; + char szMapName[260]; + char szDllDir[260]; + CRC32_t mapCRC; + int nDirectoryOffset; + +} demoheader_t; + +typedef struct demoentry_s { + int nEntryType; + char szDescription[64]; + int nFlags; + int nCDTrack; + float fTrackTime; + int nFrames; + int nOffset; + int nFileLength; +} demoentry_t; + +typedef struct demo_info_s { + float timestamp; + ref_params_t rp; + usercmd_t cmd; + movevars_t movevars; + vec3_t view; + int viewmodel; +} demo_info_t; + +class NetChannel; +class DemoFile { +public: + DemoFile(); + virtual ~DemoFile() {} + + void Init(IWorld *world, IServer *server, NetChannel *channel); + bool LoadDemo(char *demoname); + void StopPlayBack(); + bool StartRecording(char *newName); + void CloseFile(); + void Reset(); + void SetContinuous(bool state); + bool IsContinuous(); + bool IsPlaying(); + bool IsRecording(); + char *GetFileName(); + void ReadDemoPacket(BitBuffer *demoData, demo_info_t *demoInfo); + void WriteDemoMessage(BitBuffer *unreliableData, BitBuffer *reliableData); + void WriteUpdateClientData(client_data_t *cdata); + float GetDemoTime(); + void ReadSequenceInfo(); + void ReadDemoInfo(demo_info_t *demoInfo); + void WriteDemoStartup(BitBuffer *buffer); + void WriteSequenceInfo(); + void WriteDemoInfo(demo_info_t *demoInfo); + void WriteSignonData(); + + serverinfo_t m_ServerInfo; + +private: + char m_FileName[MAX_PATH]; + + enum DemoState { + DEMO_IDLE, + DEMO_PLAYING, + DEMO_RECORDING + }; + int m_DemoState; + unsigned int m_frameCount; + FileHandle_t m_FileHandle; + demoheader_t m_demoHeader; + demoentry_t m_loadEntry; + demoentry_t m_gameEntry; + demo_info_t m_zeroDemoInfo; + + float m_startTime; + float m_nextReadTime; + + NetChannel *m_DemoChannel; + int m_StartPos; + int m_EntryNumber; + int m_CurrentEntry; + demoentry_t *m_Entries; + bool m_Continuous; + + IBaseSystem *m_System; + IWorld *m_World; + IServer *m_Server; + IFileSystem *m_FileSystem; +}; diff --git a/rehlds/HLTV/common/DirectorCmd.cpp b/rehlds/HLTV/common/DirectorCmd.cpp new file mode 100644 index 0000000..0ec044d --- /dev/null +++ b/rehlds/HLTV/common/DirectorCmd.cpp @@ -0,0 +1,683 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +// define DRC_CMD_* +char *DirectorCmd::m_CMD_Name[] = +{ + "NONE", + "START", + "EVENT", + "MODE", + "CAMERA", + "TIMESCALE", + "MESSAGE", + "SOUND", + "STATUS", + "BANNER", + "STUFFTEXT", + "CHASE", + "INEYE", + "MAP", + "CAMPATH", + "WAYPOINTS" +}; + +DirectorCmd::DirectorCmd() +{ + Clear(); +} + +DirectorCmd::~DirectorCmd() +{ + Clear(); +} + +bool DirectorCmd::GetEventData(int &entity1, int &entity2, int &flags) +{ + if (m_Type != DRC_CMD_EVENT) { + return false; + } + + m_Data.Reset(); + entity1 = m_Data.ReadWord(); + entity2 = m_Data.ReadWord(); + flags = m_Data.ReadLong(); + + return true; +} + +bool DirectorCmd::GetModeData(int &mode) +{ + if (m_Type != DRC_CMD_MODE) { + return false; + } + + m_Data.Reset(); + mode = m_Data.ReadByte(); + + return true; +} + +bool DirectorCmd::GetChaseData(int &entity1, int &entity2, float &distance, int &flags) +{ + if (m_Type != DRC_CMD_CHASE) { + return false; + } + + m_Data.Reset(); + entity1 = m_Data.ReadByte(); + entity2 = m_Data.ReadByte(); + distance = m_Data.ReadFloat(); + flags = m_Data.ReadByte(); + + return true; +} + +bool DirectorCmd::GetInEyeData(int &player) +{ + if (m_Type != DRC_CMD_INEYE) { + return false; + } + + m_Data.Reset(); + player = m_Data.ReadByte(); + + return true; +} + +bool DirectorCmd::GetMapData(int &entity, float &angle, float &distance) +{ + if (m_Type != DRC_CMD_MAP) { + return false; + } + + m_Data.Reset(); + entity = m_Data.ReadByte(); + angle = m_Data.ReadFloat(); + distance = m_Data.ReadFloat(); + + return true; +} + +bool DirectorCmd::GetCameraData(vec_t *position, vec_t *angles, float &fov, int &entity) +{ + if (m_Type != DRC_CMD_CAMERA) { + return false; + } + + m_Data.Reset(); + + position[0] = m_Data.ReadCoord(); + position[1] = m_Data.ReadCoord(); + position[2] = m_Data.ReadCoord(); + + angles[0] = m_Data.ReadCoord(); + angles[1] = m_Data.ReadCoord(); + angles[2] = m_Data.ReadCoord(); + + fov = (float)m_Data.ReadByte(); + entity = m_Data.ReadWord(); + + return true; +} + +bool DirectorCmd::GetCamPathData(vec_t *position, vec_t *angles, float &fov, int &flags) +{ + if (m_Type != DRC_CMD_CAMPATH) { + return false; + } + + m_Data.Reset(); + + position[0] = m_Data.ReadCoord(); + position[1] = m_Data.ReadCoord(); + position[2] = m_Data.ReadCoord(); + + angles[0] = m_Data.ReadCoord(); + angles[1] = m_Data.ReadCoord(); + angles[2] = m_Data.ReadCoord(); + + fov = (float)m_Data.ReadByte(); + flags = m_Data.ReadByte(); + + return true; +} + +bool DirectorCmd::GetSoundData(char *name, float &volume) +{ + if (m_Type != DRC_CMD_SOUND) { + return false; + } + + m_Data.Reset(); + strcpy(name, m_Data.ReadString()); + volume = m_Data.ReadFloat(); + + return true; +} + +float DirectorCmd::GetTime() +{ + return m_Time; +} + +int DirectorCmd::GetType() +{ + return m_Type; +} + +char *DirectorCmd::GetName() +{ + return m_CMD_Name[m_Type]; +} + +bool DirectorCmd::GetTimeScaleData(float &factor) +{ + if (m_Type != DRC_CMD_TIMESCALE) { + return false; + } + + m_Data.Reset(); + factor = m_Data.ReadFloat(); + + return true; +} + +bool DirectorCmd::GetWayPointsData(int &number) +{ + if (m_Type != DRC_CMD_WAYPOINTS) { + return false; + } + + m_Data.Reset(); + number = m_Data.ReadByte(); + + return true; +} + +bool DirectorCmd::GetMessageData(int &effect, int &color, vec_t *position, float &fadein, float &fadeout, float &holdtime, float &fxtime, char *text) +{ + if (m_Type != DRC_CMD_MESSAGE) { + return false; + } + + m_Data.Reset(); + + effect = m_Data.ReadByte(); + color = m_Data.ReadLong(); + + position[0] = m_Data.ReadFloat(); + position[1] = m_Data.ReadFloat(); + + fadein = m_Data.ReadFloat(); + fadeout = m_Data.ReadFloat(); + holdtime = m_Data.ReadFloat(); + fxtime = m_Data.ReadFloat(); + strcpy(text, m_Data.ReadString()); + + return true; +} + +bool DirectorCmd::GetStatusData(int &slots, int &spectators, int &proxies) +{ + if (m_Type != DRC_CMD_STATUS) { + return false; + } + + m_Data.Reset(); + slots = m_Data.ReadLong(); + spectators = m_Data.ReadLong(); + proxies = m_Data.ReadWord(); + + return true; +} + +bool DirectorCmd::GetBannerData(char *filename) +{ + if (m_Type != DRC_CMD_BANNER) { + return false; + } + + m_Data.Reset(); + strcpy(filename, m_Data.ReadString()); + + return true; +} + +bool DirectorCmd::GetStuffTextData(char *commands) +{ + if (m_Type != DRC_CMD_STUFFTEXT) { + return false; + } + + m_Data.Reset(); + strcpy(commands, m_Data.ReadString()); + + return true; +} + +void DirectorCmd::SetEventData(int entity1, int entity2, int flags) +{ + m_Type = DRC_CMD_EVENT; + Resize(8); + + m_Data.WriteWord(entity1); + m_Data.WriteWord(entity2); + m_Data.WriteLong(flags); +} + +void DirectorCmd::SetChaseData(int entity1, int entity2, float distance, int flags) +{ + m_Type = DRC_CMD_CHASE; + Resize(9); + + m_Data.WriteWord(entity1); + m_Data.WriteWord(entity2); + m_Data.WriteFloat(distance); + m_Data.WriteByte(flags); +} + +void DirectorCmd::SetInEyeData(int entity) +{ + m_Type = DRC_CMD_INEYE; + Resize(2); + + m_Data.WriteWord(entity); +} + +void DirectorCmd::SetMapData(int entity, float angle, float distance) +{ + m_Type = DRC_CMD_MAP; + Resize(10); + + m_Data.WriteWord(entity); + m_Data.WriteFloat(angle); + m_Data.WriteFloat(distance); +} + +void DirectorCmd::SetStartData() +{ + m_Type = DRC_CMD_START; + Resize(0); +} + +void DirectorCmd::SetModeData(int mode) +{ + m_Type = DRC_CMD_MODE; + Resize(1); + + m_Data.WriteByte(mode); +} + +void DirectorCmd::SetCameraData(vec_t *position, vec_t *angles, float fov, int entity) +{ + m_Type = DRC_CMD_CAMERA; + Resize(15); + + m_Data.WriteCoord(position[0]); + m_Data.WriteCoord(position[1]); + m_Data.WriteCoord(position[2]); + m_Data.WriteCoord(angles[0]); + m_Data.WriteCoord(angles[1]); + m_Data.WriteCoord(angles[2]); + m_Data.WriteByte((int)fov); + m_Data.WriteWord(entity); +} + +void DirectorCmd::SetCamPathData(vec_t *position, vec_t *angles, float fov, int flags) +{ + m_Type = DRC_CMD_CAMPATH; + Resize(14); + + m_Data.WriteCoord(position[0]); + m_Data.WriteCoord(position[1]); + m_Data.WriteCoord(position[2]); + m_Data.WriteCoord(angles[0]); + m_Data.WriteCoord(angles[1]); + m_Data.WriteCoord(angles[2]); + m_Data.WriteByte((int)fov); + m_Data.WriteByte(flags); +} + +void DirectorCmd::SetSoundData(char *name, float volume) +{ + int len = strlen(name); + m_Type = DRC_CMD_SOUND; + Resize(len + 5); + + m_Data.WriteString(name); + m_Data.WriteFloat(volume); +} + +void DirectorCmd::SetTimeScaleData(float factor) +{ + m_Type = DRC_CMD_TIMESCALE; + + Resize(sizeof(float)); + m_Data.WriteFloat(factor); +} + +void DirectorCmd::SetTime(float time) +{ + m_Time = time; +} + +void DirectorCmd::SetMessageData(int effect, unsigned int color, vec_t *position, float fadein, float fadeout, float holdtime, float fxtime, char *text) +{ + int len = strlen(text); + m_Type = DRC_CMD_MESSAGE; + Resize(len + 30); + + m_Data.WriteByte(effect); + m_Data.WriteLong(color); + m_Data.WriteFloat(position[0]); + m_Data.WriteFloat(position[1]); + m_Data.WriteFloat(fadein); + m_Data.WriteFloat(fadeout); + m_Data.WriteFloat(holdtime); + m_Data.WriteFloat(fxtime); + m_Data.WriteString(text); +} + +void DirectorCmd::Copy(DirectorCmd *cmd) +{ + Clear(); + + m_Time = cmd->m_Time; + m_Type = cmd->m_Type; + m_Size = cmd->m_Size; + m_Index = cmd->m_Index; + + m_Data.Resize(m_Size); + m_Data.WriteBuf(cmd->m_Data.GetData(), m_Size); +} + +void DirectorCmd::SetStatusData(int slots, int spectators, int proxies) +{ + m_Type = DRC_CMD_STATUS; + Resize(10); + + m_Data.WriteLong(slots); + m_Data.WriteLong(spectators); + m_Data.WriteWord(proxies); +} + +void DirectorCmd::SetBannerData(char *filename) +{ + m_Type = DRC_CMD_BANNER; + + int len = strlen(filename); + Resize(len + 1); + m_Data.WriteString(filename); +} + +void DirectorCmd::SetStuffTextData(char *commands) +{ + m_Type = DRC_CMD_STUFFTEXT; + + int len = strlen(commands); + Resize(len + 1); + m_Data.WriteString(commands); +} + +void DirectorCmd::SetWayPoints(int number) +{ + m_Type = DRC_CMD_WAYPOINTS; + + Resize(1); + m_Data.WriteByte(number); +} + +bool DirectorCmd::ReadFromStream(BitBuffer *stream) +{ + char *string; + unsigned char *start; + int length; + + if (!stream) { + return false; + } + + Clear(); + m_Type = stream->ReadByte(); + + switch (m_Type) + { + case DRC_CMD_START: + Resize(0); + break; + case DRC_CMD_EVENT: + Resize(8); + m_Data.WriteBuf(stream, 8); + break; + case DRC_CMD_MODE: + Resize(1); + m_Data.WriteBuf(stream, 1); + break; + case DRC_CMD_CAMERA: + Resize(15); + m_Data.WriteBuf(stream, 15); + break; + case DRC_CMD_TIMESCALE: + Resize(4); + m_Data.WriteBuf(stream, 4); + break; + case DRC_CMD_MESSAGE: + { + start = stream->m_CurByte; + stream->SkipBytes(29); + + string = stream->ReadString(); + length = strlen(string); + Resize(length + 30); + + m_Data.WriteBuf(start, 29); + m_Data.WriteBuf(string, length + 1); + break; + } + case DRC_CMD_SOUND: + { + string = stream->ReadString(); + length = strlen(string); + Resize(length + 5); + + m_Data.WriteBuf(string, length + 1); + m_Data.WriteFloat(stream->ReadFloat()); + + break; + } + case DRC_CMD_STATUS: + Resize(10); + m_Data.WriteBuf(stream, 10); + break; + case DRC_CMD_BANNER: + { + string = stream->ReadString(); + length = strlen(string) + 1; + + Resize(length); + m_Data.WriteBuf(string, length); + break; + } + case DRC_CMD_STUFFTEXT: + { + string = stream->ReadString(); + length = strlen(string) + 1; + + Resize(length); + m_Data.WriteBuf(string, length); + break; + } + case DRC_CMD_CHASE: + Resize(7); + m_Data.WriteBuf(stream, 7); + break; + case DRC_CMD_INEYE: + Resize(1); + m_Data.WriteBuf(stream, 1); + break; + case DRC_CMD_MAP: + Resize(10); + m_Data.WriteBuf(stream, 15); + break; + case DRC_CMD_CAMPATH: + Resize(14); + m_Data.WriteBuf(stream, 14); + break; + case DRC_CMD_WAYPOINTS: + { + Resize(1); + length = stream->ReadByte(); + m_Data.WriteByte(length); + stream->SkipBytes(length * 14); + break; + } + default: + case DRC_CMD_NONE: + return false; + } + + return true; +} + +void DirectorCmd::WriteToStream(BitBuffer *stream) +{ + if (!stream) { + return; + } + + if ((m_Type > DRC_CMD_NONE && m_Type <= DRC_CMD_LAST) && m_Size < 255) + { + stream->WriteByte(svc_director); + stream->WriteByte(m_Size + 1); + stream->WriteByte(m_Type); + stream->WriteBuf(m_Data.GetData(), m_Size); + } +} + +char *DirectorCmd::ToString() +{ + int i1, i2, i3; + float f1, f2, f3, f4; + vec3_t v1, v2; + + char *t1 = m_CMD_Name[m_Type]; + char t2[1024]; + + static char s[1024]; + memset(s, 0, sizeof(s)); + + switch (m_Type) + { + case DRC_CMD_START: + sprintf(s, "%s", t1); + break; + case DRC_CMD_EVENT: + GetEventData(i1, i2, i3); + sprintf(s, "%s %i %i %i", t1, i1, i2, i3); + break; + case DRC_CMD_MODE: + GetModeData(i1); + sprintf(s, "%s %i", t1, i1); + break; + case DRC_CMD_CAMERA: + GetCameraData(v1, v2, f1, i1); + sprintf(s, "%s (%.1f %.1f %.1f) (%.1f %.1f %.1f) %.1f %i", t1, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], f1, i1); + break; + case DRC_CMD_TIMESCALE: + GetTimeScaleData(f1); + sprintf(s, "%s %.2f", t1, f1); + break; + case DRC_CMD_MESSAGE: + GetMessageData(i1, i2, v1, f1, f2, f3, f4, t2); + sprintf(s, "%s \"%s\" %i %x (%.2f %.2f) %.1f, %.1f %.1f %.1f", t1, t2, i1, i2, v1[0], v1[1], f1, f2, f3, f4); + break; + case DRC_CMD_SOUND: + GetSoundData(t2, f1); + sprintf(s, "%s \"%s\" %.2f", t1, t2, f1); + break; + case DRC_CMD_STATUS: + GetStatusData(i1, i2, i3); + sprintf(s, "%s %i %i %i", t1, i1, i2, i3); + break; + case DRC_CMD_BANNER: + GetBannerData(t2); + sprintf(s, "%s \"%s\"", t1, t2); + break; + case DRC_CMD_STUFFTEXT: + GetStuffTextData(t2); + sprintf(s, "%s \"%s\"", t1, t2); + break; + case DRC_CMD_CHASE: + GetChaseData(i1, i2, f1, i3); + sprintf(s, "%s %i %i %.1f %i", t1, i1, i2, f1, i3); + break; + case DRC_CMD_INEYE: + GetInEyeData(i1); + sprintf(s, "%s %i", t1, i1); + break; + case DRC_CMD_MAP: + GetMapData(i1, f1, f2); + sprintf(s, "%s %i %.1f %.1f", t1, i1, f1, f2); + break; + case DRC_CMD_CAMPATH: + GetCamPathData(v1, v2, f1, i1); + sprintf(s, "%s (%.1f %.1f %.1f) (%.1f %.1f %.1f) %.1f %i", t1, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], f1, i1); + break; + case DRC_CMD_WAYPOINTS: + GetWayPointsData(i1); + sprintf(s, "%s %i", t1, i1); + break; + default: + case DRC_CMD_NONE: + return nullptr; + } + + return s; +} + +void DirectorCmd::FromString(char *string) +{ + ; +} + +void DirectorCmd::Clear() +{ + m_Type = 0; + m_Time = 0; + + m_Data.Free(); +} + +void DirectorCmd::Resize(int size) +{ + m_Data.Resize(size); + m_Size = size; +} diff --git a/rehlds/HLTV/common/DirectorCmd.h b/rehlds/HLTV/common/DirectorCmd.h new file mode 100644 index 0000000..88e5101 --- /dev/null +++ b/rehlds/HLTV/common/DirectorCmd.h @@ -0,0 +1,89 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "hltv.h" +#include "BitBuffer.h" + +class DirectorCmd { +public: + DirectorCmd(); + virtual ~DirectorCmd(); + + void Clear(); + void Copy(DirectorCmd *cmd); + void Resize(int size); + void FromString(char *string); + char *ToString(); + void WriteToStream(BitBuffer *stream); + bool ReadFromStream(BitBuffer *stream); + int GetType(); + char *GetName(); + float GetTime(); + void SetTime(float time); + void SetStartData(); + void SetEventData(int entity1, int entity2, int flags); + void SetChaseData(int entity1, int entity2, float distance, int flags); + void SetModeData(int mode); + void SetInEyeData(int entity); + void SetMapData(int entity, float angle, float distance); + void SetCameraData(vec_t *position, vec_t *angles, float fov, int entity); + void SetCamPathData(vec_t *position, vec_t *angles, float fov, int flags); + void SetTimeScaleData(float factor); + void SetMessageData(int effect, unsigned int color, vec_t *position, float fadein, float fadeout, float holdtime, float fxtime, char *text); + void SetSoundData(char *name, float volume); + void SetStatusData(int slots, int spectators, int proxies); + void SetBannerData(char *filename); + void SetStuffTextData(char *commands); + void SetWayPoints(int number); + + bool GetEventData(int &entity1, int &entity2, int &flags); + bool GetChaseData(int &entity1, int &entity2, float &distance, int &flags); + bool GetInEyeData(int &player); + bool GetMapData(int &entity, float &angle, float &distance); + bool GetCameraData(vec_t *position, vec_t *angles, float &fov, int &entity); + bool GetCamPathData(vec_t *position, vec_t *angles, float &fov, int &flags); + bool GetTimeScaleData(float &factor); + bool GetMessageData(int &effect, int &color, vec_t *position, float &fadein, float &fadeout, float &holdtime, float &fxtime, char *text); + bool GetSoundData(char *name, float &volume); + bool GetModeData(int &mode); + bool GetStatusData(int &slots, int &spectators, int &proxies); + bool GetBannerData(char *filename); + bool GetStuffTextData(char *commands); + bool GetWayPointsData(int &number); + +public: + static char *m_CMD_Name[]; + + float m_Time; + int m_Type; + int m_Size; + BitBuffer m_Data; + int m_Index; +}; diff --git a/rehlds/HLTV/common/InfoString.cpp b/rehlds/HLTV/common/InfoString.cpp new file mode 100644 index 0000000..4cebd69 --- /dev/null +++ b/rehlds/HLTV/common/InfoString.cpp @@ -0,0 +1,431 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +InfoString::InfoString(char *string, unsigned int maxSize) + : m_String(nullptr), m_MaxSize(0) +{ + unsigned int len = strlen(string) + 1; + if (len < maxSize) { + len = maxSize; + } + + SetMaxSize(len); + SetString(string); +} + +InfoString::InfoString() + : m_String(nullptr), m_MaxSize(0) +{ +} + +InfoString::InfoString(unsigned int maxSize) + : m_String(nullptr), m_MaxSize(0) +{ + SetMaxSize(maxSize); +} + +InfoString::InfoString(char *string) + : m_String(nullptr), m_MaxSize(0) +{ + unsigned int len = strlen(string) + 1; + if (len < MAX_INFO_LEN) { + len = MAX_INFO_LEN; + } + + SetMaxSize(len); + SetString(string); +} + +InfoString::~InfoString() +{ + if (m_String) { + free(m_String); + m_String = nullptr; + } +} + +bool InfoString::SetString(char *string) +{ + if (!m_String || !string) { + return false; + } + + if (strlen(string) >= m_MaxSize) { + return false; + } + + strncpy(m_String, string, m_MaxSize - 1); + m_String[m_MaxSize - 1] = '\0'; + return true; +} + +void InfoString::SetMaxSize(unsigned int maxSize) +{ + char *newBuffer = (char *)Mem_ZeroMalloc(maxSize); + if (!newBuffer) { + return; + } + + if (m_String) + { + if (maxSize > strlen(m_String)) { + strncpy(newBuffer, m_String, maxSize - 1); + newBuffer[maxSize - 1] = '\0'; + } + + free(m_String); + } + + m_MaxSize = maxSize; + m_String = newBuffer; +} + +int InfoString::GetMaxSize() +{ + return m_MaxSize; +} + +int InfoString::GetCurrentSize() +{ + return strlen(m_String); +} + +void InfoString::Clear() +{ + if (m_String) { + memset(m_String, 0, m_MaxSize); + } +} + +char *InfoString::GetString() +{ + return m_String; +} + +// Searches the string for the given key and returns the associated value, or an empty string. +char *InfoString::ValueForKey(const char *key) +{ + // use two buffers so compares work without stomping on each other + static char value[MAX_INFO_VALUES][MAX_INFO_VALUE]; + static int valueindex; + char pkey[MAX_INFO_KEY]; + char *c; + char *s = m_String; + int nCount; + + while (*s) + { + if (*s == '\\') { + // skip the slash + s++; + } + + // Copy a key + nCount = 0; + c = pkey; + + while (*s != '\\') + { + if (!*s) + { + // key should end with a \, not a nullptr, but suppose its value as absent + return ""; + } + + if (nCount >= MAX_INFO_KEY) + { + s++; + // skip oversized key chars till the slash or EOL + continue; + } + + *c++ = *s++; + nCount++; + } + + *c = '\0'; + + // skip the slash + s++; + + // Copy a value + nCount = 0; + c = value[valueindex]; + + while (*s != '\\') + { + if (!*s) + { + // allow value to be ended with nullptr + break; + } + + if (nCount >= MAX_INFO_VALUE) + { + s++; + // skip oversized value chars till the slash or EOL + continue; + } + + *c++ = *s++; + nCount++; + } + + *c = '\0'; + + if (!strcmp(key, pkey)) + { + c = value[valueindex]; + valueindex = (valueindex + 1) % MAX_INFO_VALUES; + return c; + } + } + + return ""; +} + +bool InfoString::RemoveKey(const char *key) +{ + char *start; + char pkey[MAX_INFO_KEY]; + char value[MAX_INFO_VALUE]; + char *c; + char *s; + int cmpsize; + int nCount; + + s = m_String; + + if (strchr(key, '\\')) { + return false; + } + + cmpsize = strlen(key); + if (cmpsize > MAX_INFO_LEN - 1) { + cmpsize = MAX_INFO_LEN - 1; + } + + bool found = false; + while (*s) + { + start = s; + if (*s == '\\') { + // skip the slash + s++; + } + + // Copy a key + nCount = 0; + c = pkey; + while (*s != '\\') + { + if (!*s) { + // key should end with a \, not a nullptr, but allow to remove it + break; + } + + if (nCount >= MAX_INFO_KEY) + { + s++; + // skip oversized key chars till the slash or EOL + continue; + } + + *c++ = *s++; + nCount++; + } + + *c = '\0'; + if (*s) { + // skip the slash + s++; + } + + // Copy a value + nCount = 0; + c = value; + while (*s != '\\') + { + if (!*s) { + // allow value to be ended with nullptr + break; + } + + if (nCount >= MAX_INFO_VALUE) + { + s++; + // skip oversized value chars till the slash or EOL + continue; + } + + *c++ = *s++; + nCount++; + } + + *c = '\0'; + + // Compare keys + if (!strncmp(key, pkey, cmpsize) ) + { + found = true; + strcpy_safe(start, s); // remove this part + s = start; // continue searching + } + } + + return found; +} + +void InfoString::RemovePrefixedKeys(char prefix) +{ + char pkey[MAX_INFO_KEY]; + char value[MAX_INFO_VALUE]; + char *start; + char *c; + char *s; + int nCount; + + s = m_String; + while (*s) + { + start = s; + + if (*s == '\\') { + // skip the slash + s++; + } + + // Copy a key + nCount = 0; + c = pkey; + while (*s != '\\') + { + if (!*s) { + // key should end with a \, not a nullptr, but allow to remove it + break; + } + + if (nCount >= MAX_INFO_KEY) + { + s++; + // skip oversized key chars till the slash or EOL + continue; + } + + *c++ = *s++; + nCount++; + } + + *c = '\0'; + if (*s) { + // skip the slash + s++; + } + + // Copy a value + nCount = 0; + c = value; + while (*s != '\\') + { + if (!*s) { + // allow value to be ended with nullptr + break; + } + + if (nCount >= MAX_INFO_VALUE) { + s++; + // skip oversized value chars till the slash or EOL + continue; + } + + *c++ = *s++; + nCount++; + } + + *c = '\0'; + + // Compare prefix + if (pkey[0] == prefix) + { + strcpy_safe(start, s); // remove this part + s = start; // continue searching + } + } +} + +bool InfoString::SetValueForStarKey(const char *key, const char *value) +{ + char newtoken[MAX_INFO_LEN + 4]; + if (strstr(key, "\\") || strstr(value, "\\")) { + return false; + } + + if (strstr(key, "\"") || strstr(value, "\"")) { + return false; + } + + if (strlen(key) > MAX_INFO_KEY || strlen(value) > MAX_INFO_VALUE) { + return false; + } + + // Remove current key/value and return if we doesn't specified to set a value + RemoveKey(key); + + if (!value || !strlen(value)) { + return true; + } + + // Create key/value pair + _snprintf(newtoken, sizeof(newtoken), "\\%s\\%s", key, value); + + int length = strlen(m_String); + if ((length + strlen(newtoken)) < m_MaxSize) + { + char *v = newtoken; + char *s = m_String + length; + unsigned char c; + + while (*v) + { + c = (unsigned char)*v++; + *s++ = c; + } + + *s = '\0'; + return true; + } + + return false; +} + +bool InfoString::SetValueForKey(const char *key, const char *value) +{ + return SetValueForStarKey(key, value); +} diff --git a/rehlds/HLTV/common/InfoString.h b/rehlds/HLTV/common/InfoString.h new file mode 100644 index 0000000..732b16d --- /dev/null +++ b/rehlds/HLTV/common/InfoString.h @@ -0,0 +1,65 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +class InfoString { +public: + InfoString(); + InfoString(unsigned int maxSize); + InfoString(char *string); + InfoString(char *string, unsigned int maxSize); + + virtual ~InfoString(); + + void SetMaxSize(unsigned int maxSize); + bool SetString(char *string); + char *GetString(); + + void Clear(); + int GetMaxSize(); + int GetCurrentSize(); + + bool SetValueForStarKey(const char *key, const char *value); + char *ValueForKey(const char *key); + bool RemoveKey(const char *key); + void RemovePrefixedKeys(char prefix); + bool SetValueForKey(const char *key, const char *value); + +protected: + enum { + MAX_INFO_KEY = 512, + MAX_INFO_VALUE = 512, + + MAX_INFO_LEN = 256, + MAX_INFO_VALUES = 4 + }; + + unsigned int m_MaxSize; + char *m_String; +}; diff --git a/rehlds/HLTV/common/NetAddress.cpp b/rehlds/HLTV/common/NetAddress.cpp new file mode 100644 index 0000000..fd708d3 --- /dev/null +++ b/rehlds/HLTV/common/NetAddress.cpp @@ -0,0 +1,170 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +NetAddress::NetAddress() +{ + memset(this, 0, sizeof(NetAddress)); +} + +void NetAddress::SetPort_(int16 port) +{ + m_Port = htons(port); +} + +void NetAddress::ToSockadr(sockaddr *s) +{ + s->sa_family = AF_INET; + ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&m_IP; + ((struct sockaddr_in *)s)->sin_port = m_Port; +} + +bool NetAddress::FromSockadr(sockaddr *s) +{ + if (s->sa_family != AF_INET) { + return false; + } + + *(int *)&m_IP = ((struct sockaddr_in *)s)->sin_addr.s_addr; + m_Port = ((struct sockaddr_in *)s)->sin_port; + + return true; +} + +bool NetAddress::Equal(NetAddress *a) +{ + if (*(int *)&m_IP == *(int *)&a->m_IP && m_Port == a->m_Port) { + return true; + } + + return false; +} + +bool NetAddress::EqualBase(NetAddress *a) +{ + if (*(int *)&m_IP == *(int *)&a->m_IP) { + return true; + } + + return false; +} + +void NetAddress::ToStream(BitBuffer *stream) +{ + stream->WriteByte(m_IP[0]); + stream->WriteByte(m_IP[1]); + stream->WriteByte(m_IP[2]); + stream->WriteByte(m_IP[3]); + stream->WriteShort(m_Port); +} + +void NetAddress::FromStream(BitBuffer *stream) +{ + m_IP[0] = stream->ReadByte(); + m_IP[1] = stream->ReadByte(); + m_IP[2] = stream->ReadByte(); + m_IP[3] = stream->ReadByte(); + m_Port = stream->ReadShort(); +} + +char *NetAddress::ToString() +{ + _snprintf(m_String, sizeof(m_String), "%i.%i.%i.%i:%i", m_IP[0], m_IP[1], m_IP[2], m_IP[3], ntohs(m_Port)); + return m_String; +} + +char *NetAddress::ToBaseString() +{ + _snprintf(m_String, sizeof(m_String), "%i.%i.%i.%i", m_IP[0], m_IP[1], m_IP[2], m_IP[3]); + return m_String; +} + +void NetAddress::FromNetAddress(NetAddress *adr) +{ + if (!adr) { + memset(m_IP, 0, sizeof(m_IP)); + m_Port = 0; + return; + } + + *(int *)&m_IP[0] = *(int *)&adr->m_IP[0]; + m_Port = adr->m_Port; +} + +netadr_t *NetAddress::ToOldNetAdr() +{ + static netadr_t adr; + + adr.type = NA_IP; + adr.port = m_Port; + *(int *)&adr.ip[0] = *(int *)&m_IP[0]; + + return &adr; +} + +bool NetAddress::FromOldNetAdr(netadr_t *adr) +{ + if (adr->type != NA_IP) { + return false; + } + + *(int *)&m_IP[0] = *(int *)&adr->ip[0]; + m_Port = adr->port; + return true; +} + +bool NetAddress::IsValid() +{ + return m_Port && (m_IP[0] || m_IP[1] || m_IP[2] || m_IP[3]); +} + +void NetAddress::Clear() +{ + m_IP[3] = 0; + m_IP[2] = 0; + m_IP[1] = 0; + m_IP[0] = 0; + m_Port = 0; + + memset(m_String, 0, sizeof(m_String)); +} + +bool NetAddress::IsSubAdress(NetAddress *adr) +{ + if ((!m_IP[0] || m_IP[0] == adr->m_IP[0]) + && (!m_IP[1] || m_IP[1] == adr->m_IP[1]) + && (!m_IP[2] || m_IP[2] == adr->m_IP[2]) + && (!m_IP[3] || m_IP[3] == adr->m_IP[3]) + && (m_IP[0] || m_IP[1] || m_IP[2] || m_IP[3])) + { + return true; + } + + return false; +} diff --git a/rehlds/HLTV/common/NetAddress.h b/rehlds/HLTV/common/NetAddress.h new file mode 100644 index 0000000..0004554 --- /dev/null +++ b/rehlds/HLTV/common/NetAddress.h @@ -0,0 +1,74 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "netadr.h" +#include "BitBuffer.h" + +class NetAddress { +public: + NetAddress(); + + bool IsValid(); + bool IsSubAdress(NetAddress *adr); + + void Clear(); + + bool FromOldNetAdr(netadr_t *adr); + netadr_t *ToOldNetAdr(); + + void FromNetAddress(NetAddress *adr); + char *ToBaseString(); + char *ToString(); + + bool EqualBase(NetAddress *a); + bool Equal(NetAddress *a); + bool FromSockadr(struct sockaddr *s); + void ToSockadr(struct sockaddr *s); + void SetPort_(int16 port); + void ToStream(BitBuffer *stream); + void FromStream(BitBuffer *stream); + + virtual ~NetAddress() {} + +public: + unsigned char m_IP[4]; + short unsigned int m_Port; + char m_String[32]; +}; + +class NetPacket { +public: + NetAddress address; + BitBuffer data; + double time; + bool connectionless; + unsigned int seqnr; + bool hasReliableData; +}; diff --git a/rehlds/HLTV/common/NetChannel.cpp b/rehlds/HLTV/common/NetChannel.cpp new file mode 100644 index 0000000..4c041eb --- /dev/null +++ b/rehlds/HLTV/common/NetChannel.cpp @@ -0,0 +1,1286 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +NetChannel::NetChannel() +{ + for (int i = 0; i < MAX_STREAMS; i++) + { + m_waitlist[i] = nullptr; + m_fragbufs[i] = nullptr; + m_incomingbufs[i] = nullptr; + + m_frag_length[i] = 0; + m_frag_startpos[i] = 0; + m_fragbufcount[i] = 0; + + m_reliable_fragid[i] = 0; + m_reliable_fragment[i] = 0; + } + + m_Socket = nullptr; + m_tempBuffer = nullptr; +} + +void NetChannel::UnlinkFragment(fragbuf_t *buf, int stream) +{ + fragbuf_t *search; + fragbuf_t **list = &m_fragbufs[stream]; + + if (list == nullptr) + { + m_System->DPrintf("Netchan_UnlinkFragment: Asked to unlink fragment from empty list, ignored\n"); + return; + } + + if (*list == buf) + { + *list = buf->next; + free(buf); + return; + } + + search = *list; + while (search->next) + { + if (search->next == buf) + { + search->next = buf->next; + free(buf); + return; + } + + search = search->next; + } + + m_System->DPrintf("Netchan_UnlinkFragment: Couldn't find fragment\n"); +} + +void NetChannel::OutOfBandPrintf(const char *format, ...) +{ + va_list argptr; + char string[NET_MAX_MESSAGE]; + BitBuffer data(string, sizeof(string)); + + if (m_Socket) + { + *(int *)string = CONNECTIONLESS_HEADER; + + va_start(argptr, format); + _vsnprintf(&string[4], sizeof(string) - 4, format, argptr); + va_end(argptr); + + data.SkipBytes(strlen(string)); + m_Socket->SendPacket(&m_remote_address, data.GetData(), data.CurrentSize()); + } +} + +void NetChannel::ClearFragbufs(fragbuf_t **ppbuf) +{ + fragbuf_t *buf, *n; + + if (!ppbuf) + { + return; + } + + // Throw away any that are sitting around + buf = *ppbuf; + while (buf) + { + n = buf->next; + free(buf); + buf = n; + } + + *ppbuf = nullptr; +} + +void NetChannel::ClearFragments() +{ + fragbufwaiting_t *wait, *next; + for (int i = 0; i < MAX_STREAMS; i++) + { + wait = m_waitlist[i]; + while (wait) + { + next = wait->next; + ClearFragbufs(&wait->fragbufs); + free(wait); + wait = next; + } + m_waitlist[i] = nullptr; + + ClearFragbufs(&m_fragbufs[i]); + FlushIncoming(i); + } +} + +void NetChannel::FlushIncoming(int stream) +{ + fragbuf_t *p, *n; + + NetPacket *in; + while ((in = (NetPacket *)m_incomingPackets.RemoveTail())) { + FreePacket(in); + } + + p = m_incomingbufs[stream]; + while (p) + { + n = p->next; + free(p); + p = n; + } + + m_incomingbufs[stream] = nullptr; +} + +void NetChannel::Reset() +{ + m_keep_alive = true; + m_crashed = false; + m_connected = false; + + m_connect_time = m_System->GetTime(); + + SetTimeOut(30); + SetRate(10000); + SetUpdateRate(20); + + m_incoming_sequence = 0; + m_incoming_acknowledged = 0; + m_incoming_reliable_acknowledged = 0; + m_incoming_reliable_sequence = 0; + m_outgoing_sequence = 1; + m_reliable_sequence = 0; + m_last_reliable_sequence = 0; +} + +void NetChannel::Clear() +{ + NetPacket *packet; + while ((packet = (NetPacket *)m_incomingPackets.RemoveHead())) { + FreePacket(packet); + } + + ClearFragments(); + + for (int i = 0; i < MAX_STREAMS; i++) + { + m_reliable_fragid[i] = 0; + m_reliable_fragment[i] = 0; + m_fragbufcount[i] = 0; + m_frag_startpos[i] = 0; + m_frag_length[i] = 0; + } + + if (m_tempBuffer) + { + free(m_tempBuffer); + m_tempBuffer = nullptr; + } + + m_tempBufferSize = 0; + m_reliableOutSize = 0; + + memset(m_reliableOutBuffer, 0, sizeof(m_reliableOutBuffer)); + memset(m_flow, 0, sizeof(m_flow)); + + m_reliableStream.Clear(); + m_unreliableStream.Clear(); + + m_last_send = + m_last_received = + m_cleartime = m_System->GetTime(); + + m_loss = 0; +} + +bool NetChannel::Create(IBaseSystem *system, INetSocket *netsocket, NetAddress *adr) +{ + m_System = system; + m_incomingPackets.Init(); + m_blocksize = FRAGMENT_S2C_MAX_SIZE; + + if (!m_reliableStream.Resize(MAX_MSGLEN)) + { + m_System->Errorf("NetChannel::Create: m_reliableStream out of memory.\n"); + return false; + } + + if (!m_unreliableStream.Resize(MAX_MSGLEN)) + { + m_System->Errorf("NetChannel::Create: m_unreliableStream out of memory.\n"); + return false; + } + + m_remote_address.FromNetAddress(adr); + m_Socket = netsocket; + if (m_Socket) + { + if (!m_Socket->AddChannel(this)) + { + m_System->Errorf("NetChannel::Create: could not bound to NetSocket\n"); + return false; + } + } + else + { + m_System->DPrintf("Creating fake network channel.\n"); + } + + Clear(); + Reset(); + + return true; +} + +void NetChannel::Close() +{ + if (m_Socket) { + m_Socket->RemoveChannel(this); + } + + Clear(); + m_reliableStream.Free(); + m_unreliableStream.Free(); +} + +bool NetChannel::IsReadyToSend() +{ + if (m_System->GetTime() > m_cleartime) { + return true; + } + + return false; +} + +void NetChannel::UpdateFlow(int stream) +{ + int bytes = 0; + float faccumulatedtime = 0.0f; + flow_t *pflow = &m_flow[stream]; + + if (pflow->nextcompute > m_System->GetTime()) { + return; + } + + pflow->nextcompute = m_System->GetTime() + 0.5f; + + flowstats_t *pstat; + int start = pflow->current - 1; + for (int i = 1; i < (MAX_LATENT / 2); i++) + { + pstat = &pflow->stats[(start - i) & 0x1f]; + bytes += pstat->size; + } + + faccumulatedtime = m_System->GetTime() - pstat->time; + + pflow->kbytespersec = (faccumulatedtime == 0.0f) ? 0.0f : bytes / faccumulatedtime / 1024.0f; + pflow->avgkbytespersec = pflow->avgkbytespersec * (2.0 / 3) + pflow->kbytespersec * (1.0 / 3); +} + +void NetChannel::TransmitOutgoing() +{ + byte send_buf[NET_MAX_MESSAGE]; + BitBuffer data(send_buf, sizeof(send_buf)); + + bool send_reliable; + bool send_reliable_fragment; + bool send_resending = false; + unsigned w1, w2; + int i, j; + + if (IsFakeChannel()) + { + m_outgoing_sequence++; + + m_last_send = m_System->GetTime(); + m_cleartime = m_last_send + m_send_interval; + + m_reliableStream.FastClear(); + m_unreliableStream.FastClear(); + + FakeAcknowledgement(); + return; + } + + // check for reliable message overflow + if (m_reliableStream.IsOverflowed()) + { + m_System->DPrintf("Transmit:Outgoing m_reliableStream overflow (%s)\n", m_remote_address.ToString()); + m_reliableStream.Clear(); + return; + } + + // check for unreliable message overflow + if (m_unreliableStream.IsOverflowed()) + { + m_System->DPrintf("Transmit:Outgoing m_unreliableStream overflow (%s)\n", m_remote_address.ToString()); + m_unreliableStream.Clear(); + } + + // if the remote side dropped the last reliable message, resend it + send_reliable = false; + + if (m_incoming_acknowledged > m_last_reliable_sequence && m_incoming_reliable_acknowledged != m_reliable_sequence) + { + send_reliable = true; + send_resending = true; + } + + // A packet can have "reliable payload + frag payload + unreliable payload + // frag payload can be a file chunk, if so, it needs to be parsed on the receiving end and reliable payload + unreliable payload need + // to be passed on to the message queue. The processing routine needs to be able to handle the case where a message comes in and a file + // transfer completes + // + // if the reliable transmit buffer is empty, copy the current message out + if (!m_reliableOutSize) + { + bool send_frag = false; + fragbuf_t *pbuf; + + // Will be true if we are active and should let chan->message get some bandwidth + int send_from_frag[MAX_STREAMS] = { 0, 0 }; + int send_from_regular = 0; + + // If we have data in the waiting list(s) and we have cleared the current queue(s), then + // push the m_waitlist(s) into the current queue(s) + FragSend(); + + // Sending regular payload + send_from_regular = m_reliableStream.CurrentSize() ? 1 : 0; + + // Check to see if we are sending a frag payload + for (i = 0; i < MAX_STREAMS; i++) + { + if (m_fragbufs[i]) + { + send_from_frag[i] = 1; + } + } + + /*if (m_reliableStream.CurrentSize() > sizeof(send_buf)) + { + CreateFragmentsFromBuffer(m_reliableStream.GetData(), m_reliableStream.CurrentSize(), FRAG_NORMAL_STREAM); + m_reliableStream.FastClear(); + }*/ + + // Stall reliable payloads if sending from frag buffer + if (send_from_regular && (send_from_frag[FRAG_NORMAL_STREAM])) + { + send_from_regular = false; + + // If the reliable buffer has gotten too big, queue it at the end of everything and clear out buffer + if (m_reliableStream.CurrentSize() > MAX_RELIABLE_PAYLOAD) + { + CreateFragmentsFromBuffer(m_reliableStream.GetData(), m_reliableStream.CurrentSize(), FRAG_NORMAL_STREAM); + m_reliableStream.FastClear(); + } + } + + // Startpos will be zero if there is no regular payload + for (i = 0; i < MAX_STREAMS; i++) + { + m_frag_startpos[i] = 0; + + // Assume no fragment is being sent + m_reliable_fragment[i] = 0; + m_reliable_fragid[i] = 0; + m_frag_length[i] = 0; + + if (send_from_frag[i]) + { + send_frag = true; + } + } + + if (send_from_regular || send_frag) + { + m_reliable_sequence ^= 1u; + send_reliable = true; + } + + if (send_from_regular) + { + memcpy(m_reliableOutBuffer, m_reliableStream.GetData(), m_reliableStream.CurrentSize()); + + m_reliableOutSize = m_reliableStream.CurrentSize(); + m_reliableStream.FastClear(); + + // If we send fragments, this is where they'll start + for (i = 0; i < MAX_STREAMS; i++) { + m_frag_startpos[i] = m_reliableOutSize; + } + } + + for (i = 0; i < MAX_STREAMS; i++) + { + int fragment_size = 0; + + // Is there something in the fragbuf? + pbuf = m_fragbufs[i]; + if (pbuf) + { + fragment_size = pbuf->size; + + // Files set size a bit differently. + if (pbuf->isfile && !pbuf->isbuffer) + { + fragment_size = pbuf->size; + } + } + + // Make sure we have enought space left + if (send_from_frag[i] && pbuf && (m_reliableOutSize + fragment_size) < MAX_RELIABLE_PAYLOAD) + { + m_reliable_fragid[i] = MAKE_FRAGID(pbuf->bufferId, m_fragbufcount[i]); // Which buffer are we sending? + + // If it's not in-memory, then we'll need to copy it in frame the file handle. + if (pbuf->isfile && !pbuf->isbuffer) { + m_System->Printf("TODO! NetChannel::Transmit: system file support\n"); + } + + memcpy(m_reliableOutBuffer + m_reliableOutSize, pbuf->data, pbuf->size); + + m_reliableOutSize += pbuf->size; + m_frag_length[i] = pbuf->size; + + // Unlink pbuf + UnlinkFragment(pbuf, i); + m_reliable_fragment[i] = 1; + + // Offset the rest of the starting positions + for (j = i + 1; j < MAX_STREAMS; j++) + { + m_frag_startpos[j] += m_frag_length[i]; + } + } + } + } + + // Prepare the packet header + w1 = m_outgoing_sequence | (send_reliable << 31); + w2 = m_incoming_sequence | (m_incoming_reliable_sequence << 31); + + send_reliable_fragment = false; + + for (i = 0; i < MAX_STREAMS; i++) + { + if (m_reliable_fragment[i]) + { + send_reliable_fragment = true; + break; + } + } + + if (send_reliable && send_reliable_fragment) { + w1 |= (1 << 30); + } + + m_outgoing_sequence++; + + data.Clear(); + data.WriteLong(w1); + data.WriteLong(w2); + + if (send_reliable && send_reliable_fragment) + { + for (i = 0; i < MAX_STREAMS; i++) + { + if (m_reliable_fragment[i]) + { + data.WriteByte(1); + data.WriteLong(m_reliable_fragid[i]); + data.WriteShort(m_frag_startpos[i]); + data.WriteShort(m_frag_length[i]); + } + else + { + data.WriteByte(0); + } + } + } + + // Copy the reliable message to the packet first + if (send_reliable) { + data.WriteBuf(m_reliableOutBuffer, m_reliableOutSize); + m_last_reliable_sequence = m_outgoing_sequence - 1; + } + + // Is there room for the unreliable payload? + int max_send_size = send_resending ? MAX_ROUTEABLE_PACKET : NET_MAX_MESSAGE; + if ((max_send_size - data.CurrentSize()) >= m_unreliableStream.CurrentSize()) { + data.ConcatBuffer(&m_unreliableStream); + } + else { + m_System->DPrintf("WARNING! TransmitOutgoing: Unreliable would overfow, ignoring.\n"); + } + + m_unreliableStream.FastClear(); + + // Deal with packets that are too small for some networks + // Packet too small for some networks + if (data.CurrentSize() < 16) + { + // Go ahead and pad a full 16 extra bytes -- this only happens during authentication / signon + for (int i = data.CurrentSize(); i < 16; i++) + { + // Note that the server can parse svc_nop, too. + data.WriteByte(svc_nop); + } + } + + int statId = m_flow[FLOW_OUTGOING].current & 0x1f; + m_flow[FLOW_OUTGOING].stats[statId].size = data.CurrentSize() + UDP_HEADER_SIZE; + m_flow[FLOW_OUTGOING].stats[statId].time = m_System->GetTime(); + m_flow[FLOW_OUTGOING].current++; + + COM_Munge2(data.GetData() + 8, data.CurrentSize() - 8, (unsigned char)(m_outgoing_sequence - 1)); + + if (m_Socket) { + m_Socket->SendPacket(&m_remote_address, data.GetData(), data.CurrentSize()); + } + + m_last_send = m_System->GetTime(); + m_cleartime = max(m_send_interval, (data.CurrentSize() + UDP_HEADER_SIZE) * (1.0 / m_max_bandwidth_rate)) + m_last_send; +} + +NetChannel::fragbuf_t *NetChannel::FindBufferById(fragbuf_t **pplist, int id, bool allocate) +{ + fragbuf_t *list = *pplist; + fragbuf_t *pnewbuf; + + while (list) + { + if (list->bufferId == id) + return list; + + list = list->next; + } + + if (!allocate) + return nullptr; + + // Create new entry + pnewbuf = (fragbuf_t *)Mem_ZeroMalloc(sizeof(fragbuf_t)); + pnewbuf->bufferId = id; + AddBufferToList(pplist, pnewbuf); + + return pnewbuf; +} + +bool NetChannel::CheckForCompletion(int stream, int intotalbuffers) +{ + int c; + int size; + int id; + fragbuf_t *p; + + size = 0; + c = 0; + + if (stream != FRAG_NORMAL_STREAM && stream != FRAG_FILE_STREAM) { + m_System->DPrintf("ERROR! NetChannel::CheckForCompletion: invalid stream number %i.\n"); + return false; + } + + p = m_incomingbufs[stream]; + if (!p) { + return false; + } + + while (p) + { + size += p->size; + c++; + + id = FRAG_GETID(p->bufferId); + if (id != c) + { + m_System->DPrintf("WARNING! NetChannel::CheckForCompletion: lost/dropped fragment Lost/dropped fragment would cause stall, retrying connection\n"); + m_crashed = true; + return false; + } + + p = p->next; + } + + // Received final message + if (c == intotalbuffers) + { + switch (stream) + { + case FRAG_NORMAL_STREAM: + CopyNormalFragments(); + break; + case FRAG_FILE_STREAM: + m_System->Printf("TODO! NetChannel::CheckForCompletion: create file from fragments.\n"); + break; + } + + return true; + } + + return false; +} + +void NetChannel::ProcessIncoming(unsigned char *data, int size) +{ + BitBuffer message(data, size); + + int i; + unsigned int sequence, sequence_ack; + unsigned int reliable_ack, reliable_message; + unsigned int fragid[MAX_STREAMS] = { 0, 0 }; + + bool frag_message[MAX_STREAMS] = { false, false }; + int frag_offset[MAX_STREAMS] = { 0, 0 }; + int m_frag_length[MAX_STREAMS] = { 0, 0 }; + + bool message_contains_fragments; + int net_drop; + float newLoss; + float weight; + + // get sequence numbers + sequence = message.ReadLong(); + if (sequence == CONNECTIONLESS_HEADER) + { + NetPacket *p = new NetPacket; + + p->connectionless = true; + p->time = m_System->GetTime(); + p->seqnr = -1; + + p->address.FromNetAddress(&m_remote_address); + p->data.Resize(size - 4); + p->data.WriteBuf(data + 4, size - 4); + p->data.Reset(); + + m_incomingPackets.AddHead(p); + return; + } + + if (!m_connected) { + return; + } + + sequence_ack = message.ReadLong(); + + COM_UnMunge2(message.GetData() + 8, size - 8, sequence & 0xFF); + + reliable_message = sequence >> 31; + reliable_ack = sequence_ack >> 31; + message_contains_fragments = sequence & (1 << 30) ? true : false; + + // TODO: Looks like need to move it above COM_UnMunge2 + if (sequence_ack & 0x40000000) + { + m_crashed = true; + return; + } + + if (message_contains_fragments) + { + for (i = 0; i < MAX_STREAMS; i++) + { + if (message.ReadByte()) + { + frag_message[i] = true; + fragid[i] = message.ReadLong(); + frag_offset[i] = message.ReadShort(); + m_frag_length[i] = message.ReadShort(); + } + } + } + + sequence &= ~(1 << 31); + sequence &= ~(1 << 30); + + sequence_ack &= ~(1 << 31); + sequence_ack &= ~(1 << 30); + + if (sequence <= (unsigned int)m_incoming_sequence) + { + if (sequence == (unsigned int)m_incoming_sequence) + m_System->DPrintf("NetChannel::ProcessIncoming: duplicate packet %i at %i from %s\n", sequence, m_incoming_sequence, m_remote_address.ToString()); + else + m_System->DPrintf("NetChannel::ProcessIncoming: out of order packet %i at %i from %s\n", sequence, m_incoming_sequence, m_remote_address.ToString()); + + return; + } + + // dropped packets don't keep the message from being used + net_drop = sequence - (m_incoming_sequence + 1); + if (net_drop < 0) { + net_drop = 0; + } + + newLoss = (net_drop + 1) * (1.0f / 200.0f); + if (newLoss < 1.0f) + { + weight = (float)net_drop / (float)(net_drop + 1); + m_loss = (1.0 - newLoss) * m_loss + weight * newLoss; + } + else + m_loss = 1; + + // if the current outgoing reliable message has been acknowledged + // clear the buffer to make way for the next + if (reliable_ack == (unsigned int)m_reliable_sequence) + { + if (m_incoming_acknowledged + 1 >= m_last_reliable_sequence) + { + // it has been received + m_reliableOutSize = 0; + } + } + + // if this message contains a reliable message, bump incoming_reliable_sequence + m_incoming_sequence = sequence; + m_incoming_acknowledged = sequence_ack; + m_incoming_reliable_acknowledged = reliable_ack; + + if (reliable_message) { + m_incoming_reliable_sequence ^= 1u; + } + + int statId = m_flow[FLOW_INCOMING].current & 0x1f; + m_flow[FLOW_INCOMING].stats[statId].size = size + UDP_HEADER_SIZE; + m_flow[FLOW_INCOMING].stats[statId].time = m_System->GetTime(); + m_flow[FLOW_INCOMING].current++; + + m_last_received = m_System->GetTime(); + + if (message_contains_fragments) + { + for (i = 0; i <= 1; ++i) + { + int j; + fragbuf_t *pbuf; + int inbufferid; + int intotalbuffers; + + if (!frag_message[i]) + continue; + + inbufferid = FRAG_GETID(fragid[i]); + intotalbuffers = FRAG_GETCOUNT(fragid[i]); + + if (fragid[i]) + { + pbuf = FindBufferById(&m_incomingbufs[i], fragid[i], true); + if (pbuf) + { + memcpy(pbuf->data, message.GetData() + message.CurrentSize() + frag_offset[i], m_frag_length[i]); + pbuf->size = m_frag_length[i]; + } + else + { + m_System->Printf("NetChannel::ProcessIncoming: couldn't allocate or find buffer %i\n", inbufferid); + } + + // Count # of incoming bufs we've queued? are we done? + CheckForCompletion(i, intotalbuffers); + } + + // Rearrange incoming data to not have the frag stuff in the middle of it + int wpos = message.CurrentSize() + frag_offset[i]; + int rpos = wpos + m_frag_length[i]; + + memmove(message.GetData() + wpos, message.GetData() + rpos, message.GetMaxSize() - rpos); + message.m_MaxSize -= m_frag_length[i]; + + for (j = i + 1; j < MAX_STREAMS; j++) + { + // fragments order already validated + frag_offset[j] -= m_frag_length[i]; + } + } + } + + int curLen = message.GetMaxSize() - message.CurrentSize(); + if (curLen > 0) + { + NetPacket *p = new NetPacket; + p->connectionless = 0; + p->hasReliableData = reliable_message != 0; + p->time = m_System->GetTime(); + p->seqnr = m_incoming_sequence; + p->address.FromNetAddress(&m_remote_address); + p->data.Resize(curLen); + p->data.WriteBuf(message.m_CurByte, curLen); + p->data.Reset(); + m_incomingPackets.AddHead(p); + } +} + +void NetChannel::FragSend() +{ + fragbufwaiting_t *wait; + int i; + + for (i = 0; i < MAX_STREAMS; i++) + { + // Already something queued up, just leave in waitlist + if (m_fragbufs[i]) { + continue; + } + + wait = m_waitlist[i]; + + // Nothing to queue? + if (!wait) { + continue; + } + + m_waitlist[i] = wait->next; + wait->next = nullptr; + + // Copy in to fragbuf + m_fragbufs[i] = wait->fragbufs; + m_fragbufcount[i] = wait->fragbufcount; + + // Throw away wait list + free(wait); + } +} + +void NetChannel::AddBufferToList(fragbuf_t **pplist, fragbuf_t *pbuf) +{ + // Find best slot + fragbuf_t *pprev, *n; + int id1, id2; + + pbuf->next = nullptr; + + if (!pplist) + return; + + if (!*pplist) + { + pbuf->next = *pplist; + *pplist = pbuf; + return; + } + + pprev = *pplist; + while (pprev->next) + { + n = pprev->next; // Next item in list + id1 = FRAG_GETID(n->bufferId); + id2 = FRAG_GETID(pbuf->bufferId); + + if (id1 > id2) + { + // Insert here + pbuf->next = n->next; + pprev->next = pbuf; + return; + } + + pprev = pprev->next; + } + + // Insert at end + pprev->next = pbuf; +} + +bool NetChannel::CreateFragmentsFromBuffer(void *buffer, int size, int streamtype, char *filename) +{ + fragbuf_t *buf; + int chunksize; + int sendsize; + int remaining; + int pos; + int bufferid = 1; + bool firstfragment = true; + fragbufwaiting_t *wait, *p; + + if (IsFakeChannel()) + { + m_System->Printf("NetChannel::CreateFragmentsFromBuffer: IsFakeChannel()\n"); + return true; + } + + if (size == 0) { + return true; + } + + unsigned char compressed[65536]; + char hdr[4] = "BZ2"; + + unsigned int header_size = sizeof(hdr); + unsigned int compressedSize = size - sizeof(hdr); // we should fit in same data buffer minus 4 bytes for a header + + if (streamtype == FRAG_FILE_STREAM) { + compressedSize -= 4; + } + + if (!BZ2_bzBuffToBuffCompress((char *)compressed, &compressedSize, (char *)buffer, size, 9, 0, 30)) + { + m_System->DPrintf("Compressing split packet (%d -> %d bytes)\n", size, compressedSize); + memcpy(buffer, hdr, sizeof(hdr)); + + if (streamtype == FRAG_FILE_STREAM) { + memcpy((char *)buffer + 4, &size, sizeof(int)); + header_size = 8; + } + + memcpy((char *)buffer + header_size, compressed, compressedSize); + size = header_size + compressedSize; + } + + chunksize = FRAGMENT_S2C_MIN_SIZE; + wait = (fragbufwaiting_t *)Mem_ZeroMalloc(sizeof(fragbufwaiting_t)); + + remaining = size; + pos = 0; + while (remaining > 0) + { + sendsize = min(remaining, chunksize); + remaining -= sendsize; + + buf = (fragbuf_t *)Mem_ZeroMalloc(sizeof(fragbuf_t)); + if (!buf) + { + m_System->Printf("NetChannel::CreateFragmentsFromBuffer:Couldn't allocate fragbuf_t\n"); + free(wait); + return false; + } + + if (firstfragment && filename) + { + firstfragment = false; + + unsigned int len = strlen(filename) + 1; + memcpy(buf->data, filename, len); + sendsize -= len; + + memcpy(&buf->data[len], (char *)buffer + pos, sendsize); + buf->size = len + sendsize; + } + else + { + memcpy(buf->data, (char *)buffer + pos, sendsize); + buf->size = sendsize; + } + + buf->bufferId = bufferid++; + buf->isfile = filename ? true : false; + buf->isbuffer = true; + + // Copy in data + pos += sendsize; + + AddFragbufToTail(wait, buf); + } + + // Now add waiting list item to the end of buffer queue + if (!m_waitlist[streamtype]) + { + m_waitlist[streamtype] = wait; + } + else + { + p = m_waitlist[streamtype]; + while (p->next) { + p = p->next; + } + + p->next = wait; + } + + return true; +} + +void NetChannel::AddFragbufToTail(fragbufwaiting_t *wait, fragbuf_t *buf) +{ + fragbuf_t *p; + + buf->next = nullptr; + wait->fragbufcount++; + + p = wait->fragbufs; + if (p) + { + while (p->next) { + p = p->next; + } + + p->next = buf; + } + else + { + wait->fragbufs = buf; + } +} + +NetPacket *NetChannel::GetPacket() +{ + return (NetPacket *)m_incomingPackets.RemoveTail(); +} + +void NetChannel::FreePacket(NetPacket *packet) +{ + if (packet) { + delete packet; + } +} + +void NetChannel::SetUpdateRate(int newupdaterate) +{ + m_updaterate = newupdaterate; + if (newupdaterate > 100) { + m_updaterate = 100; + } else if (newupdaterate < 0) { + m_updaterate = 1; + } + + m_send_interval = (1.0f / m_updaterate); +} + +void NetChannel::CopyNormalFragments() +{ + fragbuf_t *p, *n; + int totalSize; + + if (!m_incomingbufs[FRAG_NORMAL_STREAM]) { + m_System->DPrintf("WARNING! NetChannel::CopyNormalFragments: called with no fragments readied.\n"); + return; + } + + totalSize = 0; + p = m_incomingbufs[FRAG_NORMAL_STREAM]; + while (p) + { + totalSize += p->size; + p = p->next; + } + + NetPacket *packet = new NetPacket; + packet->seqnr = m_incoming_sequence; + packet->connectionless = false; + packet->time = m_System->GetTime(); + packet->address.FromNetAddress(&m_remote_address); + packet->data.Resize(totalSize); + + p = m_incomingbufs[FRAG_NORMAL_STREAM]; + while (p) + { + n = p->next; + packet->data.WriteBuf(p->data, p->size); + + free(p); + p = n; + } + + if (*(uint32 *)packet->data.GetData() == MAKEID('B', 'Z', '2', '\0')) + { + char uncompressed[65536]; + unsigned int uncompressedSize = 65536; + + BZ2_bzBuffToBuffDecompress(uncompressed, &uncompressedSize, (char *)packet->data.GetData() + 4, totalSize - 4, 1, 0); + + packet->data.Resize(uncompressedSize); + packet->data.WriteBuf(uncompressed, uncompressedSize); + } + + packet->data.Reset(); + + m_incomingPackets.AddHead(packet); + m_incomingbufs[FRAG_NORMAL_STREAM] = nullptr; +} + +void NetChannel::SetConnected(bool flag) +{ + m_connected = flag; +} + +void NetChannel::SetRate(int newRate) +{ + m_max_bandwidth_rate = clamp(newRate, 1000, 20000); +} + +void NetChannel::GetFlowStats(float *avgInKBSec, float *avgOutKBSec) +{ + UpdateFlow(FLOW_OUTGOING); + UpdateFlow(FLOW_INCOMING); + + *avgInKBSec = m_flow[FLOW_OUTGOING].avgkbytespersec; + *avgOutKBSec = m_flow[FLOW_INCOMING].avgkbytespersec; +} + +void NetChannel::SetKeepAlive(bool flag) +{ + m_keep_alive = flag; +} + +bool NetChannel::KeepAlive() +{ + return m_keep_alive; +} + +NetAddress *NetChannel::GetTargetAddress() +{ + return &m_remote_address; +} + +bool NetChannel::IsFakeChannel() +{ + if (m_Socket) { + return false; + } + + return true; +} + +bool NetChannel::IsConnected() +{ + return m_connected; +} + +void NetChannel::SetTimeOut(float time) +{ + if (time > 0) { + m_timeout = time; + } +} + +bool NetChannel::IsTimedOut() +{ + if (m_Socket && m_System->GetTime() > m_timeout + m_last_received) { + return true; + } + + return false; +} + +float NetChannel::GetIdleTime() +{ + return m_System->GetTime() - m_last_send; +} + +int NetChannel::GetRate() +{ + return m_max_bandwidth_rate; +} + +int NetChannel::GetUpdateRate() +{ + return m_updaterate; +} + +float NetChannel::GetLoss() +{ + return m_loss; +} + +void NetChannel::FakeAcknowledgement() +{ + m_incoming_sequence = 0; + m_incoming_acknowledged = m_outgoing_sequence - 1; + m_incoming_reliable_acknowledged = m_reliable_sequence; + m_reliableOutSize = 0; + + m_last_received = m_System->GetTime(); +} + +bool NetChannel::CreateFragmentsFromFile(char *fileName) +{ + if (IsFakeChannel()) { + m_System->Printf("NetChannel::CreateFragmentsFromBuffer: IsFakeChannel()\n"); + return true; + } + + m_System->Printf("WARNING! Ignoring file request %s.\n", fileName); + return false; +} + +bool NetChannel::IsCrashed() +{ + return m_crashed; +} + +bool NetChannel::CopyFileFragments() +{ + fragbuf_t *p; + fragbuf_s *n; + char filename[MAX_PATH]; + int totalSize = 0; + + if (!m_incomingbufs[FRAG_FILE_STREAM]) { + m_System->DPrintf("WARNING! NetChannel::CopyFileFragments: called with no fragments readied.\n"); + return false; + } + + totalSize = 0; + p = m_incomingbufs[FRAG_FILE_STREAM]; + while (p) + { + totalSize += p->size; + p = p->next; + } + + BitBuffer filecontent(totalSize); + p = m_incomingbufs[FRAG_FILE_STREAM]; + while (p) + { + n = p->next; + filecontent.WriteBuf(p->data, p->size); + free(p); + p = n; + } + + filecontent.Reset(); + strcopy(filename, filecontent.ReadString()); + + if (!strlen(filename)) { + m_System->Printf("File fragment received with no filename\n"); + FlushIncoming(FRAG_FILE_STREAM); + return false; + } + + if (strstr(filename, "..")) { + m_System->Printf("File fragment received with relative path, ignoring\n"); + FlushIncoming(FRAG_FILE_STREAM); + return false; + } + + // TODO: Here is the missing code. + // TODO: Check me, value of return function only false. + + totalSize -= strlen(filename) - 1; + m_incomingbufs[FRAG_FILE_STREAM] = nullptr; + + return false; +} diff --git a/rehlds/HLTV/common/NetChannel.h b/rehlds/HLTV/common/NetChannel.h new file mode 100644 index 0000000..8c396e3 --- /dev/null +++ b/rehlds/HLTV/common/NetChannel.h @@ -0,0 +1,237 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include +#include + +#include "bzip2/bzlib.h" +#include "ObjectList.h" + +// 0 == regular, 1 == file stream +enum +{ + FRAG_NORMAL_STREAM = 0, + FRAG_FILE_STREAM, + + MAX_STREAMS +}; + +enum +{ + FLOW_OUTGOING = 0, + FLOW_INCOMING, + + MAX_FLOWS +}; + +#define MAX_LATENT 32 +#define FRAGMENT_MAX_SIZE 1400 // Size of fragmentation buffer internal buffers + +#define UDP_HEADER_SIZE 28 +#define MAX_RELIABLE_PAYLOAD 1200 + +#define MAKE_FRAGID(id, count) (((id & 0xffff) << 16) | (count & 0xffff)) +#define FRAG_GETID(fragid) ((fragid >> 16) & 0xffff) +#define FRAG_GETCOUNT(fragid) (fragid & 0xffff) + +// Max length of a reliable message +#define MAX_MSGLEN 3990 // 10 reserved for fragheader? +#define MAX_POSSIBLE_MSG 65536 + +#define MAX_ROUTEABLE_PACKET 1400 +#define MIN_ROUTEABLE_PACKET 16 + +#define SPLIT_SIZE (MAX_ROUTEABLE_PACKET - sizeof(SPLITPACKET)) + +// Pad this to next higher 16 byte boundary +// This is the largest packet that can come in/out over the wire, before processing the header +// bytes will be stripped by the networking channel layer +// #define NET_MAX_MESSAGE PAD_NUMBER( ( MAX_MSGLEN + HEADER_BYTES ), 16 ) +// This is currently used value in the engine. TODO: define above gives 4016, check it why. +#define NET_MAX_MESSAGE 4037 +#define NET_HEADER_FLAG_SPLITPACKET -2 + +class IBaseSystem; + +// Network Connection Channel +class NetChannel: public INetChannel { +public: + NetChannel(); + virtual ~NetChannel() {} + + virtual bool Create(IBaseSystem *system, INetSocket *netsocket = nullptr, NetAddress *adr = nullptr); + virtual bool IsConnected(); + virtual bool IsReadyToSend(); + virtual bool IsCrashed(); + virtual bool IsTimedOut(); + virtual bool IsFakeChannel(); + virtual bool KeepAlive(); + virtual NetAddress *GetTargetAddress(); + virtual void Close(); + virtual void Clear(); + virtual void Reset(); + virtual void TransmitOutgoing(); + virtual void ProcessIncoming(unsigned char *data, int size); + virtual void OutOfBandPrintf(const char *format, ...); + virtual void FakeAcknowledgement(); + virtual void SetUpdateRate(int newupdaterate); + virtual void SetRate(int newRate); + virtual void SetKeepAlive(bool flag); + virtual void SetTimeOut(float time); + virtual float GetIdleTime(); + virtual int GetRate(); + virtual int GetUpdateRate(); + virtual float GetLoss(); + + enum { FRAGMENT_C2S_MIN_SIZE = 16, FRAGMENT_S2C_MIN_SIZE = 256, FRAGMENT_S2C_MAX_SIZE = 1024 }; + + // Message data + typedef struct flowstats_s + { + int size; // Size of message sent/received + double time; // Time that message was sent/received + } flowstats_t; + + typedef struct flow_s + { + flowstats_t stats[MAX_LATENT]; // Data for last MAX_LATENT messages + int current; // Current message position + double nextcompute; // Time when we should recompute k/sec data + + // Average data + float kbytespersec; + float avgkbytespersec; + } flow_t; + + // Generic fragment structure + typedef struct fragbuf_s + { + struct fragbuf_s *next; // Next buffer in chain + int bufferId; // Id of this buffer + byte data[FRAGMENT_MAX_SIZE]; // The actual data sits here + + int size; // Size of data to read at that offset + bool isfile; // Is this a file buffer? + bool isbuffer; // Is this file buffer from memory ( custom decal, etc. ). + char fileName[MAX_PATH]; // Name of the file to save out on remote host + int fOffset; // Offset in file from which to read data + } fragbuf_t; + + // Waiting list of fragbuf chains + typedef struct fragbufwaiting_s + { + struct fragbufwaiting_s *next; // Next chain in waiting list + int fragbufcount; // Number of buffers in this chain + fragbuf_t *fragbufs; // The actual buffers + } fragbufwaiting_t; + + bool CreateFragmentsFromFile(char *fileName); + bool CopyFileFragments(); + void GetFlowStats(float *avgInKBSec, float *avgOutKBSec); + void SetConnected(bool flag); + void FlushOutgoing(); + void CopyNormalFragments(); + void UpdateFlow(int stream); + void FlushIncoming(int stream); + void ClearFragments(); + void ClearFragbufs(fragbuf_t **ppbuf); + void UnlinkFragment(fragbuf_t *buf, int stream); + NetPacket *GetPacket(); + void FreePacket(NetPacket *packet); + void AddFragbufToTail(fragbufwaiting_t *wait, fragbuf_t *buf); + bool CreateFragmentsFromBuffer(void *buffer, int size, int streamtype, char *filename = nullptr); + void AddBufferToList(fragbuf_t ** pplist, fragbuf_t *pbuf); + void FragSend(); + bool CheckForCompletion(int stream, int intotalbuffers); + fragbuf_t *FindBufferById(fragbuf_t **pplist, int id, bool allocate); + +public: + IBaseSystem *m_System; + INetSocket *m_Socket; + + NetAddress m_remote_address; // Address this channel is talking to. + double m_last_received; + double m_last_send; + double m_connect_time; // Time when channel was connected. + float m_timeout; + int m_max_bandwidth_rate; + double m_send_interval; + int m_updaterate; // Bandwidth choke, bytes per second + double m_cleartime; // If realtime > cleartime, free to send next packet + + bool m_keep_alive; + bool m_crashed; + bool m_connected; + + // Sequencing variables + int m_incoming_sequence; // Increasing count of sequence numbers + int m_incoming_acknowledged; // # of last outgoing message that has been ack'd. + int m_incoming_reliable_acknowledged; // Toggles T/F as reliable messages are received. + int m_incoming_reliable_sequence; // single bit, maintained local + int m_outgoing_sequence; // Message we are sending to remote + int m_reliable_sequence; // Whether the message contains reliable payload, single bit + int m_last_reliable_sequence; // Outgoing sequence number of last send that had reliable data + + void *m_connection_status; + + int m_blocksize; + BitBuffer m_reliableStream; + BitBuffer m_unreliableStream; + ObjectList m_incomingPackets; + + // Reliable message buffer. + // We keep adding to it until reliable is acknowledged. Then we clear it. + int m_reliableOutSize; + unsigned char m_reliableOutBuffer[MAX_MSGLEN + 20]; + + fragbufwaiting_t *m_waitlist[MAX_STREAMS]; // Waiting list of buffered fragments to go onto queue. Multiple outgoing buffers can be queued in succession. + + int m_reliable_fragment[MAX_STREAMS]; // Is reliable waiting buf a fragment? + size_t m_reliable_fragid[MAX_STREAMS]; // Buffer id for each waiting fragment + + fragbuf_t *m_fragbufs[MAX_STREAMS]; // The current fragment being set + int m_fragbufcount[MAX_STREAMS]; // The total number of fragments in this stream + + int16 m_frag_startpos[MAX_STREAMS]; // Position in outgoing buffer where frag data starts + int16 m_frag_length[MAX_STREAMS]; // Length of frag data in the buffer + + fragbuf_t *m_incomingbufs[MAX_STREAMS]; // Incoming fragments are stored here + + // Only referenced by the FRAG_FILE_STREAM component + // Name of file being downloaded + char m_incomingfilename[MAX_PATH]; + + void *m_tempBuffer; + int m_tempBufferSize; + + // Incoming and outgoing flow metrics + flow_t m_flow[MAX_FLOWS]; + float m_loss; +}; diff --git a/rehlds/HLTV/common/ServerInfo.h b/rehlds/HLTV/common/ServerInfo.h new file mode 100644 index 0000000..dde21e5 --- /dev/null +++ b/rehlds/HLTV/common/ServerInfo.h @@ -0,0 +1,85 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +typedef struct serverinfo_s +{ + char address[64]; + char name[80]; + char map[16]; + char gamedir[256]; + char description[256]; + + int activePlayers; + int maxPlayers; + + char type; // HLServerType + char os; + char pw; + bool mod; + + char url_info[256]; + char url_dl[256]; + char hlversion[256]; + + int ver; + int size; + + bool svonly; + bool cldll; + + unsigned char protocol; +} serverinfo_t; + +enum HLServerType { + HLST_Dedicated, + HLST_NonDedicated, + HLST_TV, +}; + +inline const char *GetServerType(HLServerType type) +{ + switch (type) + { + case HLST_Dedicated: return "d"; + case HLST_NonDedicated: return "l"; + case HLST_TV: return "p"; + } + + return ""; +} + +inline const char *GetServerOS() +{ +#ifdef _WIN32 + return "w"; +#else + return "l"; +#endif +} diff --git a/rehlds/HLTV/common/byteorder.cpp b/rehlds/HLTV/common/byteorder.cpp new file mode 100644 index 0000000..b5d340e --- /dev/null +++ b/rehlds/HLTV/common/byteorder.cpp @@ -0,0 +1,89 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +short _BigShort(short l) +{ + return bswap(l); +} + +short _LittleShort(short l) +{ + return l; +} + +int _BigLong(int l) +{ + return bswap(l); +} + +int _LittleLong(int l) +{ + return l; +} + +float _BigFloat(float l) +{ + return bswap(l); +} + +float _LittleFloat(float l) +{ + return l; +} + +int _LongSwap(int l) +{ + return bswap(l); +} + +int _LongNoSwap(int l) +{ + return l; +} + +short _ShortSwap(short l) +{ + return bswap(l); +} + +short _ShortNoSwap(short l) +{ + return l; +} + +float _FloatSwap(float f) +{ + return bswap(f); +} + +float _FloatNoSwap(float f) +{ + return f; +} diff --git a/rehlds/HLTV/common/byteorder.h b/rehlds/HLTV/common/byteorder.h new file mode 100644 index 0000000..2364874 --- /dev/null +++ b/rehlds/HLTV/common/byteorder.h @@ -0,0 +1,42 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +short _BigShort(short l); +short _LittleShort(short l); +int _BigLong(int l); +int _LittleLong(int l); +float _BigFloat(float l); +float _LittleFloat(float l); +int _LongSwap(int l); +int _LongNoSwap(int l); +short _ShortSwap(short l); +short _ShortNoSwap(short l); +float _FloatSwap(float f); +float _FloatNoSwap(float f); diff --git a/rehlds/HLTV/common/common.cpp b/rehlds/HLTV/common/common.cpp new file mode 100644 index 0000000..9e4bf33 --- /dev/null +++ b/rehlds/HLTV/common/common.cpp @@ -0,0 +1,468 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +static char *date = __DATE__; +static char *mon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +static char mond[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +int COM_BuildNumber() +{ + int m = 0; + int d = 0; + int y = 0; + static int b = 0; + + if (b != 0) + return b; + + for (m = 0; m < 11; m++) + { + if (_strnicmp(&date[0], mon[m], 3) == 0) + break; + d += mond[m]; + } + + d += atoi(&date[4]) - 1; + y = atoi(&date[7]) - 1900; + b = d + (int)((y - 1) * 365.25); + + if (((y % 4) == 0) && m > 1) + { + b += 1; + } + + // return days since initial commit on Apr 12 2014 (Happy Cosmonautics Day!) + b -= 41374; + return b; +} + +char *COM_TimeString() +{ + static char timedate[16]; + time_t ltime = time(nullptr); + tm *now = localtime(<ime); + + strftime(timedate, sizeof(timedate), "%y%m%d%H%M", now); + return timedate; +} + +char *COM_SkipPath(char *pathname) +{ + char *last = pathname; + while (*pathname) + { + if (*pathname == '/' || *pathname == '\\') { + last = pathname + 1; + } + + pathname++; + } + + return last; +} + +#ifdef _WIN32 +char *COM_GetBaseDir() +{ + static char basedir[MAX_PATH]; + basedir[0] = '\0'; + + if (GetModuleFileName((HMODULE)nullptr, basedir, sizeof(basedir))) + { + char *pBuffer = strrchr(basedir, '\\'); + + if (pBuffer && *pBuffer) + pBuffer[1] = '\0'; + + int j = strlen(basedir); + if (j > 0 && (basedir[j - 1] == '\\' || basedir[j - 1] == '/')) + basedir[j - 1] = '\0'; + } + + return basedir; +} + +#else // _WIN32 + +char g_szEXEName[256]; +char *COM_GetBaseDir() +{ + static char basedir[MAX_PATH]; + basedir[0] = '\0'; + + strcpy(basedir, g_szEXEName); + char *pBuffer = strrchr(basedir, '/'); + + if (pBuffer && *pBuffer) + pBuffer[1] = '\0'; + + int j = strlen(basedir); + if (j > 0 && (basedir[j - 1] == '\\' || basedir[j - 1] == '/')) + basedir[j - 1] = '\0'; + + return basedir; +} + +#endif // _WIN32 + +void COM_FixSlashes(char *pname) +{ + while (*pname) + { +#ifdef _WIN32 + if (*pname == '/') + { + *pname = '\\'; + } +#else + if (*pname == '\\') + { + *pname = '/'; + } +#endif + + pname++; + } +} + +// Fills "out" with the file name without path and extension. +void COM_FileBase(char *in, char *out) +{ + *out = '\0'; + + int len = strlen(in); + if (len <= 0) { + return; + } + + const char *start = in + len - 1; + const char *end = in + len; + + while (start >= in && *start != '/' && *start != '\\') + { + if (*start == '.') { + end = start; + } + + start--; + } + start++; + + len = end - start; + strncpy(out, start, len); + out[len] = '\0'; +} + +char com_token[COM_TOKEN_LEN]; +qboolean s_com_token_unget = FALSE; + +void COM_UngetToken() +{ + s_com_token_unget = TRUE; +} + +char *COM_Parse(char *data) +{ + int c; + int len; + + if (s_com_token_unget) + { + s_com_token_unget = FALSE; + return data; + } + + len = 0; + com_token[0] = '\0'; + + if (!data) { + return nullptr; + } + +skipwhite: + while (*data <= 32) + { + if (!*data) { + return nullptr; + } + + data++; + } + + c = *data; + + // skip // comments till the next line + if (c == '/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + + // start over new line + goto skipwhite; + } + + // handle quoted strings specially: copy till the end or another quote + if (c == '\"') + { + // skip starting quote + data++; + while (true) + { + c = *data++; // get char and advance + if (c == '\"') // closing quote + { + com_token[len] = '\0'; + return data; + } + + if (!c || len == COM_TOKEN_LEN - 1) // check if buffer is full + { + com_token[len] = 0; + return data; + } + + com_token[len++] = c; + } + } + else + { + // parse single characters + if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',') + { + com_token[len++] = c; + com_token[len] = '\0'; + return data + 1; + } + + // parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',') + break; + } + while (len < COM_TOKEN_LEN - 1 && (c < 0 || c > 32)); + } + + com_token[len] = '\0'; + return data; +} + +char *COM_VarArgs(char *format, ...) +{ + va_list argptr; + static char string[1024]; + + va_start(argptr, format); + _vsnprintf(string, sizeof(string), format, argptr); + va_end(argptr); + + return string; +} + +unsigned char COM_Nibble(char c) +{ + if (c >= '0' && c <= '9') + { + return (unsigned char)(c - '0'); + } + + if (c >= 'A' && c <= 'F') + { + return (unsigned char)(c - 'A' + 0x0A); + } + + if (c >= 'a' && c <= 'f') + { + return (unsigned char)(c - 'a' + 0x0A); + } + + return '0'; +} + +void COM_HexConvert(const char *pszInput, int nInputLength, unsigned char *pOutput) +{ + const char *pIn; + unsigned char *p = pOutput; + for (int i = 0; i < nInputLength - 1; i += 2) + { + pIn = &pszInput[i]; + if (!pIn[0] || !pIn[1]) + break; + + *p++ = ((COM_Nibble(pIn[0]) << 4) | COM_Nibble(pIn[1])); + } +} + +char *COM_BinPrintf(unsigned char *buf, int length) +{ + char szChunk[10]; + static char szReturn[4096]; + memset(szReturn, 0, sizeof(szReturn)); + + for (int i = 0; i < length; i++) + { + _snprintf(szChunk, sizeof(szChunk), "%02x", buf[i]); + strncat(szReturn, szChunk, sizeof(szReturn) - strlen(szReturn) - 1); + } + + return szReturn; +} + +char *COM_FormatTime(float seconds) +{ + + static char time[32]; + int hours = (int)seconds / 3600; + if (hours > 0) + { + _snprintf(time, sizeof(time), "%02i:%2i:%02i", hours, (int)seconds / 60, (int)seconds % 60); + } + else + { + _snprintf(time, sizeof(time), "%02i:%02i", (int)seconds / 60, (int)seconds % 60); + } + + return time; +} + +void COM_RemoveEvilChars(char *string) +{ + char *c = string; + if (!c) { + return; + } + + while (*c) + { + if (*c < ' ' || *c > '~' || *c == '%' || *c == ';') { + *c = ' '; + } + + c++; + } +} + +int COM_FileNameCmp(const char *file1, const char *file2) +{ + while (*file1 && *file2) + { + if ((*file1 != '/' || *file2 != '\\') && (*file2 != '/' || *file1 != '\\')) + { + if (tolower(*file1) != tolower(*file2)) + return -1; + + if (!*file1) + return 0; + } + + file1++; + file2++; + } + + return 0; +} + +bool COM_IsWhiteSpace(char space) +{ + switch (space) { + case '\t': + case '\r': + case '\n': + case ' ': + return true; + } + + return false; +} + +void COM_TrimSpace(const char *source, char *dest) +{ + int start = 0; + while (source[start] && COM_IsWhiteSpace(source[start])) { + start++; + } + + int end = strlen(source) - 1; + while (end > 0 && COM_IsWhiteSpace(source[end])) { + end--; + } + + end++; + + int length = end - start; + if (length > 0) { + strncpy(dest, &source[start], length); + } + else + length = 0; + + dest[length] = '\0'; +} + +void COM_UnpackRGB(unsigned char &r, unsigned char &g, unsigned char &b, unsigned int color) +{ + r = (color >> 16) & 0xFF; + g = (color >> 8) & 0xFF; + b = (color) & 0xFF; +} + +unsigned int COM_PackRGB(unsigned char r, unsigned char g, unsigned char b) +{ + return (r << 16) | (g << 8) | b; +} + +unsigned int COM_PackRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return (a << 24) | (r << 16) | (g << 8) | b; +} + +void NORETURN HLTV_SysError(const char *fmt, ...) +{ + va_list argptr; + static char string[8192]; + + va_start(argptr, fmt); + vsnprintf(string, sizeof(string), fmt, argptr); + va_end(argptr); + + printf("%s\n", string); + + FILE* fl = fopen("hltv_error.txt", "w"); + fprintf(fl, "%s\n", string); + fclose(fl); + + int *null = 0; + *null = 0; + exit(-1); +} diff --git a/rehlds/HLTV/common/common_hltv.h b/rehlds/HLTV/common/common_hltv.h new file mode 100644 index 0000000..8af86ed --- /dev/null +++ b/rehlds/HLTV/common/common_hltv.h @@ -0,0 +1,55 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +int COM_BuildNumber(); +char *COM_TimeString(); +char *COM_SkipPath(char *pathname); +char *COM_GetBaseDir(); +void COM_FixSlashes(char *pname); +void COM_FileBase(char *in, char *out); +void COM_UngetToken(); +char *COM_Parse(char *data); +char *COM_VarArgs(char *format, ...); +unsigned char COM_Nibble(char c); +void COM_HexConvert(const char *pszInput, int nInputLength, unsigned char *pOutput); +char *COM_BinPrintf(unsigned char *buf, int length); +char *COM_FormatTime(float seconds); +void COM_RemoveEvilChars(char *string); +int COM_FileNameCmp(const char *file1, const char *file2); +bool COM_IsWhiteSpace(char space); +void COM_TrimSpace(const char *source, char *dest); +void COM_UnpackRGB(unsigned char &r, unsigned char &g, unsigned char &b, unsigned int color); +unsigned int COM_PackRGB(unsigned char r, unsigned char g, unsigned char b); +unsigned int COM_PackRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a); +void NORETURN HLTV_SysError(const char *fmt, ...); + +#ifdef LINUX +extern char g_szEXEName[256]; +#endif // LINUX diff --git a/rehlds/HLTV/common/mathlib.cpp b/rehlds/HLTV/common/mathlib.cpp new file mode 100644 index 0000000..8b3f96f --- /dev/null +++ b/rehlds/HLTV/common/mathlib.cpp @@ -0,0 +1,390 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +vec3_t vec3_origin; + +float TriangleDiameter(const vec_t *v1, vec_t *v2, vec_t *v3) +{ + vec3_t e1, e2, e3; + float l1, l2, l3; + int i; + + l1 = 0; + l2 = 0; + l3 = 0; + + VectorSubtract(v2, v1, e1); + VectorSubtract(v3, v2, e2); + VectorSubtract(v1, v3, e3); + + for (i = 0; i < 3; i++) { + l3 = e1[i] * e1[i] + l3; + } + + for (i = 0; i < 3; i++) { + l2 = e2[i] * e2[i] + l2; + } + + for (i = 0; i < 3; i++) { + l1 = e3[i] * e3[i] + l1; + } + + if (l3 > l2 && l3 > l1) { + return sqrt(l3); + } + + if (l2 > l3 && l2 > l1) { + return sqrt(l2); + } + + return sqrt(l1); +} + +float VectorNormalize(vec_t *v) +{ + float length = Length(v); + if (length) + { + float ilength = 1 / length; + + v[0] *= ilength; + v[1] *= ilength; + v[2] *= ilength; + } + + return length; +} + +float VectorDistance(const vec_t *v1, const vec_t *v2) +{ + vec3_t t; + VectorSubtract(v1, v2, t); + return Length(t); +} + +void VectorAngles(const float *forward, float *angles) +{ + float tmp, yaw, pitch; + if (forward[1] == 0 && forward[0] == 0) + { + yaw = 0; + if (forward[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + yaw = float(atan2(forward[1], forward[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + tmp = sqrt(forward[0] * forward[0] + forward[1] * forward[1]); + pitch = float(atan2(forward[2], tmp) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + + angles[0] = pitch; + angles[1] = yaw; + angles[2] = 0; +} + +void VectorRAngles(const float *v, float *a) +{ + a[0] = atan2(v[2], sqrt(v[0] * v[0] + v[1] * v[1])); + a[1] = atan2(v[1], v[0]); + NormalizeRAngles(a); +} + +int BoxOnPlaneSide(vec_t *emins, vec_t *emaxs, mplane_t *p) +{ + // From sources + float dist1, dist2; + int sides = 0; + + // general case + switch (p->signbits) + { + case 0: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; + break; + case 1: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; + break; + case 2: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; + break; + case 3: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; + break; + case 4: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; + break; + case 5: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; + break; + case 6: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; + break; + case 7: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; + break; + default: + dist1 = dist2 = 0.0; + break; + } + + if (dist1 >= p->dist) + sides = 1; + if (dist2 < p->dist) + sides |= 2; + + return sides; +} + +float AngleBetweenVectors(const vec_t *angle1, const vec_t *angle2) +{ + float angle; + float d1 = Length(angle1); + float d2 = Length(angle2); + + if (!d1 || !d2) { + return 0; + } + + angle = acos(DotProduct(angle1, angle2) / (d1 * d2)); + angle = angle * float(180.0f / M_PI); + + return angle; +} + +float RAngleBetweenVectors(const vec_t *angle1, const vec_t *angle2) +{ + float d1, d2, d3; + + d1 = Length(angle1); + d2 = Length(angle2); + + if (!d1 || !d2) { + return 0; + } + + d3 = DotProduct(angle1, angle2) / (d1 * d2); + if (d3 > 1) { + return 0; + } + + if (d3 < -1) { + return (float)M_PI; + } + + return acosf(d3); +} + +void NormalizeAngles(vec_t *angles) +{ + // Normalize angles + for (int i = 0; i < 3; ++i) + { + if (angles[i] > 180.0) + { + angles[i] -= 360.0; + } + else if (angles[i] < -180.0) + { + angles[i] += 360.0; + } + } +} + +void NormalizeRAngles(vec_t *a) +{ + if (a[0] > M_PI) { + a[0] -= float(M_PI * 2); + } + else if (a[0] < -M_PI) { + a[0] += float(M_PI * 2); + } + + if (a[1] > M_PI) { + a[1] -= float(M_PI * 2); + } + else if (a[1] < -M_PI) { + a[1] += float(M_PI * 2); + } + + a[2] = 0; +} + +void AngleVectors(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up) +{ + float sr, sp, sy, cr, cp, cy; + + float angle; + angle = (float)(angles[YAW] * (M_PI * 2 / 360)); + sy = sin(angle); + cy = cos(angle); + angle = (float)(angles[PITCH] * (M_PI * 2 / 360)); + sp = sin(angle); + cp = cos(angle); + angle = (float)(angles[ROLL] * (M_PI * 2 / 360)); + sr = sin(angle); + cr = cos(angle); + + if (forward) + { + forward[0] = cp * cy; + forward[1] = cp * sy; + forward[2] = -sp; + } + + if (right) + { + right[0] = (-1 * sr * sp * cy + -1 * cr * -sy); + right[1] = (-1 * sr * sp * sy + -1 * cr * cy); + right[2] = -1 * sr * cp; + } + + if (up) + { + up[0] = (cr * sp * cy + -sr * -sy); + up[1] = (cr * sp * sy + -sr * cy); + up[2] = cr * cp; + } +} + +int AngleLeftOfOther(const vec_t *v1, const vec_t *v2) +{ + float a = v1[1]; + float b = v2[1]; + + if (a >= 180) + return (b >= a) || ((a - 180) > b); + else + return (b > a) && ((a + 180) >= b); +} + +float RadiusFromBounds(const vec_t *mins, const vec_t *maxs) +{ + vec3_t corner; + for (int i = 0; i < 3; i++) + { + float fmin = fabs(mins[i]); + float fmax = fabs(mins[i]); + + if (fmin > fmax) + corner[i] = fmin; + else + corner[i] = fmax; + } + + return Length(corner); +} + +bool SolveLSE(vec_t *v0, vec_t *v1, vec_t *v2, vec_t *v3, float *x, float *y, float *z) +{ + float d = v1[2] * (v2[0] * v3[1] - v2[1] * v3[0]) + v1[1] * (v3[0] * v2[2] - v2[0] * v3[2]) + v1[0] * (v2[1] * v3[2] - v3[1] * v2[2]); + if (!d) { + return false; + } + + if (x) *x = ((v2[0] * v3[1] - v2[1] * v3[0]) * v0[2] + (v3[0] * v2[2] - v2[0] * v3[2]) * v0[1] + (v2[1] * v3[2] - v3[1] * v2[2]) * v0[0]) / d; + if (y) *y = ((v0[0] * v3[1] - v0[1] * v3[0]) * v1[2] + (v3[0] * v0[2] - v0[0] * v3[2]) * v1[1] + (v0[1] * v3[2] - v3[1] * v0[2]) * v1[0]) / d; + if (z) *z = ((v2[0] * v0[1] - v2[1] * v0[0]) * v1[2] + (v0[0] * v2[2] - v2[0] * v0[2]) * v1[1] + (v2[1] * v0[2] - v0[1] * v2[2]) * v1[0]) / d; + + return true; +} + +void NormalizePoints(vec_t *v0, vec_t *v1) +{ + vec3_t a; + VectorSubtract(v1, v0, a); + + if (Length(a)) + { + VectorNormalize(a); + VectorAdd(a, v0, v1); + } +} + +void Normal2Plane(vec_t *v1, vec_t *v2, vec_t *v3) +{ + if (v1[0]) + { + v2[0] = -v1[1] / v1[0]; + v2[1] = 1; + v2[2] = 0; + + v3[0] = -v1[2] / v1[0]; + v3[1] = 0; + v3[2] = 1; + return; + } + + if (v1[1]) + { + v2[0] = 1; + v2[1] = -v1[0] / v1[1]; + v2[2] = 0; + + v3[0] = 0; + v3[1] = -v1[2] / v1[1]; + v3[2] = 1; + + return; + } + + v2[0] = 1; + v2[1] = 0; + v2[2] = -v1[0] / v1[2]; + + v3[0] = 0; + v3[1] = 1; + v3[2] = -v1[1] / v1[2]; +} + +float Length(const vec_t *v) +{ + return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); +} + +float DotProduct(const vec_t *v1, const vec_t *v2) +{ + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} diff --git a/rehlds/HLTV/common/mathlib_internal.h b/rehlds/HLTV/common/mathlib_internal.h new file mode 100644 index 0000000..2fa959f --- /dev/null +++ b/rehlds/HLTV/common/mathlib_internal.h @@ -0,0 +1,65 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "model.h" + +#define PITCH 0 // up / down +#define YAW 1 // left / right +#define ROLL 2 // fall over + +extern vec3_t vec3_origin; + +static const int nanmask = 0x7F800000; +#define IS_NAN(fvar) ((*reinterpret_cast(&(fvar)) & nanmask) == nanmask) + +#define VectorScale(a,b,c) {(c)[0]=(b)*(a)[0];(c)[1]=(b)*(a)[1];(c)[2]=(b)*(a)[2];} +#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];} +#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];} +#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} +#define VectorClear(a) {(a)[0]=0.0;(a)[1]=0.0;(a)[2]=0.0;} + +float DotProduct(const vec_t *v1, const vec_t *v2); +float TriangleDiameter(const vec_t *v1, vec_t *v2, vec_t *v3); +float VectorNormalize(vec_t *v); +float VectorDistance(const vec_t *v1, const vec_t *v2); +void VectorAngles(const float *forward, float *angles); +void VectorRAngles(const float *v, float *a); +int BoxOnPlaneSide(vec_t *emins, vec_t *emaxs, struct mplane_s *p); +float AngleBetweenVectors(const vec_t *angle1, const vec_t *angle2); +float RAngleBetweenVectors(const vec_t *angle1, const vec_t *angle2); +void NormalizeAngles(vec_t *angles); +void NormalizeRAngles(vec_t *a); +void AngleVectors(const vec_t *angles, vec_t *forward, vec_t *right = nullptr, vec_t *up = nullptr); +int AngleLeftOfOther(const vec_t *v1, const vec_t *v2); +float RadiusFromBounds(const vec_t *mins, const vec_t *maxs); +bool SolveLSE(vec_t *v0, vec_t *v1, vec_t *v2, vec_t *v3, float *x, float *y, float *z); +void NormalizePoints(vec_t *v0, vec_t *v1); +void Normal2Plane(vec_t *v1, vec_t *v2, vec_t *v3); +float Length(const vec_t *v); diff --git a/rehlds/HLTV/common/md5.cpp b/rehlds/HLTV/common/md5.cpp new file mode 100644 index 0000000..801b933 --- /dev/null +++ b/rehlds/HLTV/common/md5.cpp @@ -0,0 +1,317 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +static unsigned char PADDING[64] = +{ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G and H are basic MD5 functions: selection, majority, parity */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + { \ + (a) += F ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + { \ + (a) += G ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + { \ + (a) += H ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + { \ + (a) += I ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +void MD5_Init(MD5Context_t *ctx) +{ + ctx->bits[0] = ctx->bits[1] = 0; + + // Load magic initialization constants. + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; +} + +void MD5_Transform(unsigned int *buf, const unsigned int *in) +{ + uint32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + // Round 1 +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF(a, b, c, d, in[0], S11, 3614090360); /* 1 */ + FF(d, a, b, c, in[1], S12, 3905402710); /* 2 */ + FF(c, d, a, b, in[2], S13, 606105819); /* 3 */ + FF(b, c, d, a, in[3], S14, 3250441966); /* 4 */ + FF(a, b, c, d, in[4], S11, 4118548399); /* 5 */ + FF(d, a, b, c, in[5], S12, 1200080426); /* 6 */ + FF(c, d, a, b, in[6], S13, 2821735955); /* 7 */ + FF(b, c, d, a, in[7], S14, 4249261313); /* 8 */ + FF(a, b, c, d, in[8], S11, 1770035416); /* 9 */ + FF(d, a, b, c, in[9], S12, 2336552879); /* 10 */ + FF(c, d, a, b, in[10], S13, 4294925233); /* 11 */ + FF(b, c, d, a, in[11], S14, 2304563134); /* 12 */ + FF(a, b, c, d, in[12], S11, 1804603682); /* 13 */ + FF(d, a, b, c, in[13], S12, 4254626195); /* 14 */ + FF(c, d, a, b, in[14], S13, 2792965006); /* 15 */ + FF(b, c, d, a, in[15], S14, 1236535329); /* 16 */ + + // Round 2 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG(a, b, c, d, in[1], S21, 4129170786); /* 17 */ + GG(d, a, b, c, in[6], S22, 3225465664); /* 18 */ + GG(c, d, a, b, in[11], S23, 643717713); /* 19 */ + GG(b, c, d, a, in[0], S24, 3921069994); /* 20 */ + GG(a, b, c, d, in[5], S21, 3593408605); /* 21 */ + GG(d, a, b, c, in[10], S22, 38016083); /* 22 */ + GG(c, d, a, b, in[15], S23, 3634488961); /* 23 */ + GG(b, c, d, a, in[4], S24, 3889429448); /* 24 */ + GG(a, b, c, d, in[9], S21, 568446438); /* 25 */ + GG(d, a, b, c, in[14], S22, 3275163606); /* 26 */ + GG(c, d, a, b, in[3], S23, 4107603335); /* 27 */ + GG(b, c, d, a, in[8], S24, 1163531501); /* 28 */ + GG(a, b, c, d, in[13], S21, 2850285829); /* 29 */ + GG(d, a, b, c, in[2], S22, 4243563512); /* 30 */ + GG(c, d, a, b, in[7], S23, 1735328473); /* 31 */ + GG(b, c, d, a, in[12], S24, 2368359562); /* 32 */ + + // Round 3 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH(a, b, c, d, in[5], S31, 4294588738); /* 33 */ + HH(d, a, b, c, in[8], S32, 2272392833); /* 34 */ + HH(c, d, a, b, in[11], S33, 1839030562); /* 35 */ + HH(b, c, d, a, in[14], S34, 4259657740); /* 36 */ + HH(a, b, c, d, in[1], S31, 2763975236); /* 37 */ + HH(d, a, b, c, in[4], S32, 1272893353); /* 38 */ + HH(c, d, a, b, in[7], S33, 4139469664); /* 39 */ + HH(b, c, d, a, in[10], S34, 3200236656); /* 40 */ + HH(a, b, c, d, in[13], S31, 681279174); /* 41 */ + HH(d, a, b, c, in[0], S32, 3936430074); /* 42 */ + HH(c, d, a, b, in[3], S33, 3572445317); /* 43 */ + HH(b, c, d, a, in[6], S34, 76029189); /* 44 */ + HH(a, b, c, d, in[9], S31, 3654602809); /* 45 */ + HH(d, a, b, c, in[12], S32, 3873151461); /* 46 */ + HH(c, d, a, b, in[15], S33, 530742520); /* 47 */ + HH(b, c, d, a, in[2], S34, 3299628645); /* 48 */ + + // Round 4 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II(a, b, c, d, in[0], S41, 4096336452); /* 49 */ + II(d, a, b, c, in[7], S42, 1126891415); /* 50 */ + II(c, d, a, b, in[14], S43, 2878612391); /* 51 */ + II(b, c, d, a, in[5], S44, 4237533241); /* 52 */ + II(a, b, c, d, in[12], S41, 1700485571); /* 53 */ + II(d, a, b, c, in[3], S42, 2399980690); /* 54 */ + II(c, d, a, b, in[10], S43, 4293915773); /* 55 */ + II(b, c, d, a, in[1], S44, 2240044497); /* 56 */ + II(a, b, c, d, in[8], S41, 1873313359); /* 57 */ + II(d, a, b, c, in[15], S42, 4264355552); /* 58 */ + II(c, d, a, b, in[6], S43, 2734768916); /* 59 */ + II(b, c, d, a, in[13], S44, 1309151649); /* 60 */ + II(a, b, c, d, in[4], S41, 4149444226); /* 61 */ + II(d, a, b, c, in[11], S42, 3174756917); /* 62 */ + II(c, d, a, b, in[2], S43, 718787259); /* 63 */ + II(b, c, d, a, in[9], S44, 3951481745); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +void MD5_Update(MD5Context_t *ctx, const unsigned char *buf, unsigned int len) +{ + uint32 in[16]; + int mdi; + unsigned int i, ii; + + // Compute number of bytes mod 64 + mdi = (int)((ctx->bits[0] >> 3) & 0x3F); + + // Update number of bits + if ((ctx->bits[0] + ((uint32)len << 3)) < ctx->bits[0]) + { + ctx->bits[1]++; + } + + ctx->bits[0] += ((uint32)len << 3); + ctx->bits[1] += ((uint32)len >> 29); + + while (len--) + { + // Add new character to buffer, increment mdi + ctx->in[mdi++] = *buf++; + + // Transform if necessary + if (mdi == 0x40) + { + for (i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((uint32)ctx->in[ii + 3]) << 24) | + (((uint32)ctx->in[ii + 2]) << 16) | + (((uint32)ctx->in[ii + 1]) << 8) | + ((uint32)ctx->in[ii]); + MD5_Transform(ctx->buf, in); + mdi = 0; + } + } +} + +void MD5_Final(unsigned char *digest, MD5Context_t *ctx) +{ + uint32 in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + // save number of bits + in[14] = ctx->bits[0]; + in[15] = ctx->bits[1]; + + // Compute number of bytes mod 64 + mdi = (int)((ctx->bits[0] >> 3) & 0x3F); + + // Pad out to 56 mod 64 + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5_Update(ctx, PADDING, padLen); + + // Append length in bits and transform + for (i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((uint32)ctx->in[ii + 3]) << 24) | + (((uint32)ctx->in[ii + 2]) << 16) | + (((uint32)ctx->in[ii + 1]) << 8) | + ((uint32)ctx->in[ii]); + MD5_Transform(ctx->buf, in); + + // Store buffer in digest + for (i = 0, ii = 0; i < 4; i++, ii += 4) + { + digest[ii] = (unsigned char)(ctx->buf[i] & 0xFF); + digest[ii + 1] = (unsigned char)((ctx->buf[i] >> 8) & 0xFF); + digest[ii + 2] = (unsigned char)((ctx->buf[i] >> 16) & 0xFF); + digest[ii + 3] = (unsigned char)((ctx->buf[i] >> 24) & 0xFF); + } +} + +char *MD5_Print(unsigned char *hash) +{ + static char szReturn[64]; + char szChunk[10]; + int i; + + memset(szReturn, 0, sizeof(szReturn)); + + for (i = 0; i < 16; i++) + { + _snprintf(szChunk, sizeof(szChunk), "%02x", hash[i]); + strncat(szReturn, szChunk, sizeof(szReturn) - strlen(szReturn) - 1); + } + + return szReturn; +} + +char *MD5_GetCDKeyHash(const char *key) +{ + static char szHashedKeyBuffer[256]; + + char szKeyBuffer[256]; + int nKeyLength = strlen(key); + if (nKeyLength <= 0 || nKeyLength > 255) { + return nullptr; + } + + strncpy(szKeyBuffer, key, sizeof(szKeyBuffer) - 1); + szKeyBuffer[sizeof(szKeyBuffer) - 1] = '\0'; + szKeyBuffer[nKeyLength] = '\0'; + + MD5Context_t ctx; + unsigned char digest[16]; + + memset(&ctx, 0, sizeof(ctx)); + memset(digest, 0, sizeof(digest)); + memset(szHashedKeyBuffer, 0, sizeof(szHashedKeyBuffer)); + + MD5_Init(&ctx); + MD5_Update(&ctx, (unsigned char *)szKeyBuffer, nKeyLength); + MD5_Final(digest, &ctx); + + strncpy(szHashedKeyBuffer, MD5_Print(digest), sizeof(szHashedKeyBuffer) - 1); + szHashedKeyBuffer[sizeof(szHashedKeyBuffer) - 1] = '\0'; + + return szHashedKeyBuffer; +} + +void MD5_Hash_Mem(unsigned char *digest, unsigned char *mem, int size) +{ + MD5Context_t ctx; + memset(&ctx, 0, sizeof(ctx)); + + MD5_Init(&ctx); + MD5_Update(&ctx, mem, size); + MD5_Final(digest, &ctx); +} diff --git a/rehlds/HLTV/common/md5.h b/rehlds/HLTV/common/md5.h new file mode 100644 index 0000000..22b7945 --- /dev/null +++ b/rehlds/HLTV/common/md5.h @@ -0,0 +1,45 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +// MD5 Hash +typedef struct +{ + unsigned int buf[4]; + unsigned int bits[2]; + unsigned char in[64]; +} MD5Context_t; + +void MD5_Init(MD5Context_t *ctx); +void MD5_Transform(unsigned int *buf, const unsigned int *in); +void MD5_Update(MD5Context_t *ctx, const unsigned char *buf, unsigned int len); +void MD5_Final(unsigned char *digest, MD5Context_t *ctx); +char *MD5_Print(unsigned char *hash); +char *MD5_GetCDKeyHash(const char *key); +void MD5_Hash_Mem(unsigned char *digest, unsigned char *mem, int size); diff --git a/rehlds/HLTV/common/munge.cpp b/rehlds/HLTV/common/munge.cpp new file mode 100644 index 0000000..0a0395e --- /dev/null +++ b/rehlds/HLTV/common/munge.cpp @@ -0,0 +1,235 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +const unsigned char mungify_table[] = +{ + 0x7A, 0x64, 0x05, 0xF1, + 0x1B, 0x9B, 0xA0, 0xB5, + 0xCA, 0xED, 0x61, 0x0D, + 0x4A, 0xDF, 0x8E, 0xC7 +}; + +const unsigned char mungify_table2[] = +{ + 0x05, 0x61, 0x7A, 0xED, + 0x1B, 0xCA, 0x0D, 0x9B, + 0x4A, 0xF1, 0x64, 0xC7, + 0xB5, 0x8E, 0xDF, 0xA0 +}; + +unsigned char mungify_table3[] = +{ + 0x20, 0x07, 0x13, 0x61, + 0x03, 0x45, 0x17, 0x72, + 0x0A, 0x2D, 0x48, 0x0C, + 0x4A, 0x12, 0xA9, 0xB5 +}; + +// Anti-proxy/aimbot obfuscation code +// COM_UnMunge should reversably fixup the data +void COM_Munge(unsigned char *data, int len, int seq) +{ + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= ~seq; + c = _LongSwap(c); + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table[(i + j) & 0x0f]); + } + + c ^= seq; + *pc = c; + } +} + +void COM_UnMunge(unsigned char *data, int len, int seq) +{ + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= seq; + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table[(i + j) & 0x0f]); + } + + c = _LongSwap(c); + c ^= ~seq; + *pc = c; + } +} + +void COM_Munge2(unsigned char *data, int len, int seq) +{ + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= ~seq; + c = _LongSwap(c); + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table2[(i + j) & 0x0f]); + } + + c ^= seq; + *pc = c; + } +} + +void COM_UnMunge2(unsigned char *data, int len, int seq) +{ + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= seq; + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table2[(i + j) & 0x0f]); + } + + c = _LongSwap(c); + c ^= ~seq; + *pc = c; + } +} + +void COM_Munge3(unsigned char *data, int len, int seq) +{ + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= ~seq; + c = _LongSwap(c); + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table3[(i + j) & 0x0f]); + } + + c ^= seq; + *pc = c; + } +} + +void COM_UnMunge3(unsigned char *data, int len, int seq) +{ + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= seq; + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table3[(i + j) & 0x0f]); + } + + c = _LongSwap(c); + c ^= ~seq; + *pc = c; + } +} diff --git a/rehlds/HLTV/common/munge.h b/rehlds/HLTV/common/munge.h new file mode 100644 index 0000000..d68b498 --- /dev/null +++ b/rehlds/HLTV/common/munge.h @@ -0,0 +1,36 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +void COM_Munge(unsigned char *data, int len, int seq); +void COM_UnMunge(unsigned char *data, int len, int seq); +void COM_UnMunge2(unsigned char *data, int len, int seq); +void COM_Munge2(unsigned char *data, int len, int seq); +void COM_Munge3(unsigned char *data, int len, int seq); +void COM_UnMunge3(unsigned char *data, int len, int seq); diff --git a/rehlds/HLTV/common/net_internal.h b/rehlds/HLTV/common/net_internal.h new file mode 100644 index 0000000..bb304d7 --- /dev/null +++ b/rehlds/HLTV/common/net_internal.h @@ -0,0 +1,181 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#define MAX_VOICEDATA_LEN 4096 +#define PROTOCOL_VERSION 48 + +// all OOB packet start with this sequence +#define CONNECTIONLESS_HEADER 0xFFFFFFFF + +// info request +#define S2A_INFO 'C' // deprecated goldsrc response +#define S2A_INFO_DETAILED 'm' // New Query protocol, returns dedicated or not, + other performance info. + +#define S2A_PROXY_LISTEN 'G' +#define S2A_PROXY_REDIRECT 'L' + +// Response details about each player on the server +#define S2A_PLAYERS 'D' + +// Response as multi-packeted the rules the server is using +#define S2A_RULES 'E' + +/* ------ S2C_* - Server to client ------ */ +// Rejected the connection because the password is invalid +#define S2C_REJECT_BADPASSWORD '8' + +// Rejected the connection by explain the reason +#define S2C_REJECT '9' + +// Client connection is initiated by requesting a challenge value +// the server sends this value back +#define S2C_CHALLENGE 'A' // + challenge value + +// Send a userid, client remote address, is this server secure and engine build number +#define S2C_CONNECTION 'B' + +// HLMaster rejected a server's connection because the server needs to be updated +#define M2S_REQUESTRESTART 'O' + +// Send a log event as key value +#define S2A_LOGSTRING 'R' + +// Send a log string +#define S2A_LOGKEY 'S' + +// Basic information about the server +#define A2S_INFO 'T' + +// Details about each player on the server +#define A2S_PLAYER 'U' + +// The rules the server is using +#define A2S_RULES 'V' + +/* ------ A2A_* - Another Answer to ------ */ +// Another user is requesting a challenge value from this machine +#define A2A_GETCHALLENGE 'W' // Request challenge # from another machine + +// Generic Ping Request +#define A2A_PING 'i' // respond with an A2A_ACK + +// Generic Ack +#define A2A_ACK 'j' // general acknowledgement without info + +// Print to client console. +#define A2A_PRINT 'l' // print a message on client + +// Challenge response from master +#define M2A_CHALLENGE 's' // + challenge value + +// Max size of udp packet payload +#define MAX_UDP_PACKET 4010 // 9 bytes SPLITHEADER + 4000 payload? + +enum svc_commands_e +{ + svc_bad, + svc_nop, + svc_disconnect, + svc_event, + svc_version, + svc_setview, + svc_sound, + svc_time, + svc_print, + svc_stufftext, + svc_setangle, + svc_serverinfo, + svc_lightstyle, + svc_updateuserinfo, + svc_deltadescription, + svc_clientdata, + svc_stopsound, + svc_pings, + svc_particle, + svc_damage, + svc_spawnstatic, + svc_event_reliable, + svc_spawnbaseline, + svc_temp_entity, + svc_setpause, + svc_signonnum, + svc_centerprint, + svc_killedmonster, + svc_foundsecret, + svc_spawnstaticsound, + svc_intermission, + svc_finale, + svc_cdtrack, + svc_restore, + svc_cutscene, + svc_weaponanim, + svc_decalname, + svc_roomtype, + svc_addangle, + svc_newusermsg, + svc_packetentities, + svc_deltapacketentities, + svc_choke, + svc_resourcelist, + svc_newmovevars, + svc_resourcerequest, + svc_customization, + svc_crosshairangle, + svc_soundfade, + svc_filetxferfailed, + svc_hltv, + svc_director, + svc_voiceinit, + svc_voicedata, + svc_sendextrainfo, + svc_timescale, + svc_resourcelocation, + svc_sendcvarvalue, + svc_sendcvarvalue2, + svc_startofusermessages = svc_sendcvarvalue2, + svc_endoflist = 255, +}; + +enum clc_commands : byte +{ + clc_bad, + clc_nop, + clc_move, + clc_stringcmd, + clc_delta, + clc_resourcelist, + clc_tmove, + clc_fileconsistency, + clc_voicedata, + clc_hltv, + clc_cvarvalue, + clc_cvarvalue2, + clc_endoflist = 255, +}; diff --git a/rehlds/HLTV/common/random.cpp b/rehlds/HLTV/common/random.cpp new file mode 100644 index 0000000..8d4910f --- /dev/null +++ b/rehlds/HLTV/common/random.cpp @@ -0,0 +1,144 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +int idum; + +void SeedRandomNumberGenerator() +{ + idum = -(int)time(nullptr); + if (idum > 1000) + { + idum = -idum; + } + else if (idum > -1000) + { + idum -= 22261048; + } +} + +#define IA 16807 +#define IM 2147483647 +#define IQ 127773 +#define IR 2836 +#define NTAB 32 +#define NDIV (1 + (IM - 1) / NTAB) + +int ran1() +{ + int j; + long k; + static long iy = 0; + static long iv[NTAB]; + + if (idum <= 0 || !iy) + { + if (-(idum) < 1) + idum = 1; + else + idum = -(idum); + + for (j = NTAB + 7; j >= 0; j--) + { + k = (idum) / IQ; + idum = IA * (idum - k * IQ) - IR * k; + + if (idum < 0) + idum += IM; + + if (j < NTAB) + iv[j] = idum; + } + iy = iv[0]; + } + + k = (idum) / IQ; + idum = IA * (idum - k * IQ) - IR * k; + if (idum < 0) + idum += IM; + + j = iy / NDIV; + iy = iv[j]; + iv[j] = idum; + + return iy; +} + +#define AM (1.0 / IM) +#define EPS 1.2e-7 +#define RNMX (1.0 - EPS) + +float fran1() +{ + float temp = (float)AM * ran1(); + if (temp > RNMX) { + return (float)RNMX; + } + else + return temp; +} + +float RandomFloat(float flLow, float flHigh) +{ + SeedRandomNumberGenerator(); + + float fl = fran1(); // float in (0, 1) + return (fl * (flHigh - flLow)) + flLow; // float in (low, high) +} + +#define MAX_RANDOM_RANGE 0x7FFFFFFFUL + +int RandomLong(int lLow, int lHigh) +{ + SeedRandomNumberGenerator(); + + unsigned long maxAcceptable; + unsigned long x = lHigh - lLow + 1; + unsigned long n; + if (x <= 0 || MAX_RANDOM_RANGE < x - 1) + { + return lLow; + } + + // The following maps a uniform distribution on the interval [0,MAX_RANDOM_RANGE] + // to a smaller, client-specified range of [0,x-1] in a way that doesn't bias + // the uniform distribution unfavorably. Even for a worst case x, the loop is + // guaranteed to be taken no more than half the time, so for that worst case x, + // the average number of times through the loop is 2. For cases where x is + // much smaller than MAX_RANDOM_RANGE, the average number of times through the + // loop is very close to 1. + maxAcceptable = MAX_RANDOM_RANGE - ((MAX_RANDOM_RANGE + 1) % x); + do + { + n = ran1(); + } + while (n > maxAcceptable); + + return lLow + (n % x); +} diff --git a/rehlds/HLTV/common/random.h b/rehlds/HLTV/common/random.h new file mode 100644 index 0000000..b2b42da --- /dev/null +++ b/rehlds/HLTV/common/random.h @@ -0,0 +1,33 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +void SeedRandomNumberGenerator(); +float RandomFloat(float flLow, float flHigh); +int RandomLong(int lLow, int lHigh); diff --git a/rehlds/HLTV/msvc/hltv.sln b/rehlds/HLTV/msvc/hltv.sln new file mode 100644 index 0000000..e2dd3a3 --- /dev/null +++ b/rehlds/HLTV/msvc/hltv.sln @@ -0,0 +1,52 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Console", "..\Console\msvc\Console.vcxproj", "{D5CAB879-D54F-456F-8592-31D549CFD1D8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Core", "..\Core\msvc\Core.vcxproj", "{52F752EA-73D1-422D-B805-17EF1FB20E09}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Director", "..\Director\msvc\Director.vcxproj", "{04D0594C-57F5-4277-AF1B-EAE90AED0C3C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DemoPlayer", "..\DemoPlayer\msvc\DemoPlayer.vcxproj", "{05292761-0847-4A68-BA10-9D384DC0D3EE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzip2", "..\..\..\dep\bzip2\msvc\bzip2.vcxproj", "{792DF067-9904-4579-99B9-46C17277ADE3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Proxy", "..\Proxy\msvc\Proxy.vcxproj", "{ADDFF069-D39D-4A1B-87C9-85A62B980547}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D5CAB879-D54F-456F-8592-31D549CFD1D8}.Debug|Win32.ActiveCfg = Debug|Win32 + {D5CAB879-D54F-456F-8592-31D549CFD1D8}.Debug|Win32.Build.0 = Debug|Win32 + {D5CAB879-D54F-456F-8592-31D549CFD1D8}.Release|Win32.ActiveCfg = Release|Win32 + {D5CAB879-D54F-456F-8592-31D549CFD1D8}.Release|Win32.Build.0 = Release|Win32 + {52F752EA-73D1-422D-B805-17EF1FB20E09}.Debug|Win32.ActiveCfg = Debug|Win32 + {52F752EA-73D1-422D-B805-17EF1FB20E09}.Debug|Win32.Build.0 = Debug|Win32 + {52F752EA-73D1-422D-B805-17EF1FB20E09}.Release|Win32.ActiveCfg = Release|Win32 + {52F752EA-73D1-422D-B805-17EF1FB20E09}.Release|Win32.Build.0 = Release|Win32 + {04D0594C-57F5-4277-AF1B-EAE90AED0C3C}.Debug|Win32.ActiveCfg = Debug|Win32 + {04D0594C-57F5-4277-AF1B-EAE90AED0C3C}.Debug|Win32.Build.0 = Debug|Win32 + {04D0594C-57F5-4277-AF1B-EAE90AED0C3C}.Release|Win32.ActiveCfg = Release|Win32 + {04D0594C-57F5-4277-AF1B-EAE90AED0C3C}.Release|Win32.Build.0 = Release|Win32 + {05292761-0847-4A68-BA10-9D384DC0D3EE}.Debug|Win32.ActiveCfg = Debug|Win32 + {05292761-0847-4A68-BA10-9D384DC0D3EE}.Debug|Win32.Build.0 = Debug|Win32 + {05292761-0847-4A68-BA10-9D384DC0D3EE}.Release|Win32.ActiveCfg = Release|Win32 + {05292761-0847-4A68-BA10-9D384DC0D3EE}.Release|Win32.Build.0 = Release|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug|Win32.ActiveCfg = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug|Win32.Build.0 = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Release|Win32.ActiveCfg = Release|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Release|Win32.Build.0 = Release|Win32 + {ADDFF069-D39D-4A1B-87C9-85A62B980547}.Debug|Win32.ActiveCfg = Debug|Win32 + {ADDFF069-D39D-4A1B-87C9-85A62B980547}.Debug|Win32.Build.0 = Debug|Win32 + {ADDFF069-D39D-4A1B-87C9-85A62B980547}.Release|Win32.ActiveCfg = Release|Win32 + {ADDFF069-D39D-4A1B-87C9-85A62B980547}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/rehlds/common/BaseSystemModule.h b/rehlds/common/BaseSystemModule.h index 0a15382..385c418 100644 --- a/rehlds/common/BaseSystemModule.h +++ b/rehlds/common/BaseSystemModule.h @@ -62,7 +62,7 @@ public: virtual int GetState(); virtual int GetVersion(); virtual void ShutDown(); - virtual char *COM_GetBaseDir() { return ""; } + virtual char *GetBaseDir() { return ""; } void FireSignal(unsigned int signal, void *data = nullptr); protected: diff --git a/rehlds/common/IBaseSystem.h b/rehlds/common/IBaseSystem.h index 209950b..9f50fe3 100644 --- a/rehlds/common/IBaseSystem.h +++ b/rehlds/common/IBaseSystem.h @@ -28,6 +28,14 @@ #pragma once +#if defined(_WIN32) + #define LIBRARY_PREFIX "dll" +#elif defined(OSX) + #define LIBRARY_PREFIX "dylib" +#else + #define LIBRARY_PREFIX "so" +#endif + #include "ISystemModule.h" #include "IVGuiModule.h" @@ -77,5 +85,7 @@ public: virtual bool RemoveModule(ISystemModule *module) = 0; virtual void Stop() = 0; - virtual char *COM_GetBaseDir() = 0; + virtual char *GetBaseDir() = 0; }; + +#define BASESYSTEM_INTERFACE_VERSION "basesystem002" diff --git a/rehlds/common/IDemoPlayer.h b/rehlds/common/IDemoPlayer.h new file mode 100644 index 0000000..2431b54 --- /dev/null +++ b/rehlds/common/IDemoPlayer.h @@ -0,0 +1,93 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "ref_params.h" + +class IWorld; +class IProxy; +class DirectorCmd; +class IBaseSystem; +class ISystemModule; +class IObjectContainer; + +class IDemoPlayer { +public: + virtual ~IDemoPlayer() {} + + virtual bool Init(IBaseSystem *system, int serial, char *name) = 0; + virtual void RunFrame(double time) = 0; + virtual void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) = 0; + virtual void ExecuteCommand(int commandID, char *commandLine) = 0; + virtual void RegisterListener(ISystemModule *module) = 0; + virtual void RemoveListener(ISystemModule *module) = 0; + virtual IBaseSystem *GetSystem() = 0; + virtual int GetSerial() = 0; + virtual char *GetStatusLine() = 0; + virtual char *GetType() = 0; + virtual char *GetName() = 0; + virtual int GetState() = 0; + virtual int GetVersion() = 0; + virtual void ShutDown() = 0; + + virtual void NewGame(IWorld *world, IProxy *proxy = nullptr) = 0; + virtual char *GetModName() = 0; + virtual void WriteCommands(BitBuffer *stream, float startTime, float endTime) = 0; + virtual int AddCommand(DirectorCmd *cmd) = 0; + virtual bool RemoveCommand(int index) = 0; + virtual DirectorCmd *GetLastCommand() = 0; + virtual IObjectContainer *GetCommands() = 0; + virtual void SetWorldTime(double time, bool relative) = 0; + virtual void SetTimeScale(float scale) = 0; + virtual void SetPaused(bool state) = 0; + virtual void SetEditMode(bool state) = 0; + virtual void SetMasterMode(bool state) = 0; + virtual bool IsPaused() = 0; + virtual bool IsLoading() = 0; + virtual bool IsActive() = 0; + virtual bool IsEditMode() = 0; + virtual bool IsMasterMode() = 0; + virtual void RemoveFrames(double starttime, double endtime) = 0; + virtual void ExecuteDirectorCmd(DirectorCmd *cmd) = 0; + virtual double GetWorldTime() = 0; + virtual double GetStartTime() = 0; + virtual double GetEndTime() = 0; + virtual float GetTimeScale() = 0; + virtual IWorld *GetWorld() = 0; + virtual char *GetFileName() = 0; + virtual bool SaveGame(char *filename) = 0; + virtual bool LoadGame(char *filename) = 0; + virtual void Stop() = 0; + virtual void ForceHLTV(bool state) = 0; + virtual void GetDemoViewInfo(ref_params_t *rp, float *view, int *viewmodel) = 0; + virtual int ReadDemoMessage(unsigned char *buffer, int size) = 0; + virtual void ReadNetchanState(int *incoming_sequence, int *incoming_acknowledged, int *incoming_reliable_acknowledged, int *incoming_reliable_sequence, int *outgoing_sequence, int *reliable_sequence, int *last_reliable_sequence) = 0; +}; + +#define DEMOPLAYER_INTERFACE_VERSION "demoplayer001" diff --git a/rehlds/common/IEngineWrapper.h b/rehlds/common/IEngineWrapper.h new file mode 100644 index 0000000..7162d5b --- /dev/null +++ b/rehlds/common/IEngineWrapper.h @@ -0,0 +1,71 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "event_args.h" +#include "cdll_int.h" + +class IBaseSystem; +class IEngineWrapper { +public: + virtual ~IEngineWrapper() {} + + virtual bool Init(IBaseSystem *system, int serial, char *name) = 0; + virtual void RunFrame(double time) = 0; + virtual void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) = 0; + virtual void ExecuteCommand(int commandID, char *commandLine) = 0; + virtual void RegisterListener(ISystemModule *module) = 0; + virtual void RemoveListener(ISystemModule *module) = 0; + + virtual IBaseSystem *GetSystem() = 0; + + virtual int GetSerial() = 0; + virtual char *GetStatusLine() = 0; + virtual char *GetType() = 0; + virtual char *GetName() = 0; + + virtual int GetState() = 0; + virtual int GetVersion() = 0; + virtual void ShutDown() = 0; + + virtual bool GetViewOrigin(float *origin) = 0; + virtual bool GetViewAngles(float *angles) = 0; + virtual int GetTraceEntity() = 0; + virtual float GetCvarFloat(char *szName) = 0; + virtual char *GetCvarString(char *szName) = 0; + virtual void SetCvar(char *szName, char *szValue) = 0; + virtual void Cbuf_AddText(char *text) = 0; + virtual void DemoUpdateClientData(client_data_t *cdat) = 0; + virtual void CL_QueueEvent(int flags, int index, float delay, event_args_t *pargs) = 0; + virtual void HudWeaponAnim(int iAnim, int body) = 0; + virtual void CL_DemoPlaySound(int channel, char* sample, float attenuation, float volume, int flags, int pitch) = 0; + virtual void ClientDLL_ReadDemoBuffer(int size, unsigned char *buffer) = 0; +}; + +#define ENGINEWRAPPER_INTERFACE_VERSION "enginewrapper001" diff --git a/rehlds/common/IObjectContainer.h b/rehlds/common/IObjectContainer.h index de08bbf..333e9d0 100644 --- a/rehlds/common/IObjectContainer.h +++ b/rehlds/common/IObjectContainer.h @@ -41,7 +41,7 @@ public: virtual void *GetFirst() = 0; virtual void *GetNext() = 0; - virtual int CountElements() = 0;; + virtual int CountElements() = 0; virtual bool Contains(void *object) = 0; virtual bool IsEmpty() = 0; }; diff --git a/rehlds/common/IVGuiModule.h b/rehlds/common/IVGuiModule.h index 4af7658..e6864c8 100644 --- a/rehlds/common/IVGuiModule.h +++ b/rehlds/common/IVGuiModule.h @@ -41,7 +41,7 @@ public: // called after all the modules have been initialized // modules should use this time to link to all the other module interfaces - virtual bool PostInitialize(CreateInterfaceFn *modules, int factoryCount) = 0; + virtual bool PostInitialize(CreateInterfaceFn *modules = nullptr, int factoryCount = 0) = 0; // called when the module is selected from the menu or otherwise activated virtual bool Activate() = 0; diff --git a/rehlds/common/entity_state.h b/rehlds/common/entity_state.h index 4bd381e..91fe2ed 100644 --- a/rehlds/common/entity_state.h +++ b/rehlds/common/entity_state.h @@ -23,8 +23,9 @@ // For entityType below -#define ENTITY_NORMAL (1<<0) -#define ENTITY_BEAM (1<<1) +#define ENTITY_NORMAL (1<<0) +#define ENTITY_BEAM (1<<1) +#define ENTITY_UNINITIALIZED (1<<30) // Entity state is used for the baseline and for delta compression of a packet of // entities that is sent to a client. diff --git a/rehlds/common/hltv.h b/rehlds/common/hltv.h index 556ef32..635c8c3 100644 --- a/rehlds/common/hltv.h +++ b/rehlds/common/hltv.h @@ -42,7 +42,6 @@ #define DRC_CMD_LAST 15 - // DRC_CMD_EVENT event flags #define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) #define DRC_FLAG_SIDE (1<<4) // @@ -53,7 +52,6 @@ #define DRC_FLAG_FINAL (1<<9) // is a final scene #define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data - // DRC_CMD_WAYPOINT flags #define DRC_FLAG_STARTPATH 1 // end with speed 0.0 #define DRC_FLAG_SLOWSTART 2 // start with speed 0.0 diff --git a/rehlds/dedicated/README.md b/rehlds/dedicated/README.md new file mode 100644 index 0000000..63a472a --- /dev/null +++ b/rehlds/dedicated/README.md @@ -0,0 +1,16 @@ +## HLDS Launcher HLDS Launcher + +## What is this? +Dedicated Server Launcher for Goldsrc based games + +### Building +On Windows: +
gradlew --max-workers=1 clean rehlds/dedicated:build
+ +On Linux (ICC): +
./gradlew --max-workers=1 clean rehlds/dedicated:build
+ +On Linux (GCC): +
./gradlew --max-workers=1 -PuseGcc clean rehlds/dedicated:build
+ +Compiled binaries will be placed in the rehlds/dedicated/build/binaries/ directory diff --git a/rehlds/dedicated/src/dedicated_exports.cpp b/rehlds/dedicated/src/dedicated_exports.cpp index 956fb15..6db5576 100644 --- a/rehlds/dedicated/src/dedicated_exports.cpp +++ b/rehlds/dedicated/src/dedicated_exports.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" -class CDedicatedExports: IDedicatedExports { +class CDedicatedExports: public IDedicatedExports { public: void Sys_Printf(char *text); }; diff --git a/rehlds/engine/mathlib.cpp b/rehlds/engine/mathlib.cpp index fe2c7db..7f44e63 100644 --- a/rehlds/engine/mathlib.cpp +++ b/rehlds/engine/mathlib.cpp @@ -126,7 +126,7 @@ int BoxOnPlaneSide(vec_t *emins, vec_t *emaxs, mplane_t *p) int sides = 0; __m128 emin = _mm_loadu_ps(emins); - __m128 emax = _mm_loadu_ps(emaxs);; + __m128 emax = _mm_loadu_ps(emaxs); avec4_t d1, d2; // general case diff --git a/rehlds/engine/textures.cpp b/rehlds/engine/textures.cpp index 2f160a1..3c8708d 100644 --- a/rehlds/engine/textures.cpp +++ b/rehlds/engine/textures.cpp @@ -139,7 +139,7 @@ qboolean TEX_InitFromWad(char *path) SafeRead(texfile, &lumpinfo[nTexLumps], sizeof(lumpinfo_t)); CleanupName(lumpinfo[nTexLumps].lump.name, lumpinfo[nTexLumps].lump.name); lumpinfo[nTexLumps].lump.filepos = LittleLong(lumpinfo[nTexLumps].lump.filepos); - lumpinfo[nTexLumps].lump.disksize = LittleLong(lumpinfo[nTexLumps].lump.disksize);; + lumpinfo[nTexLumps].lump.disksize = LittleLong(lumpinfo[nTexLumps].lump.disksize); lumpinfo[nTexLumps].iTexFile = nTexFiles - 1; } diff --git a/rehlds/engine/unicode_strtools.h b/rehlds/engine/unicode_strtools.h index 9b319c5..7a14e08 100644 --- a/rehlds/engine/unicode_strtools.h +++ b/rehlds/engine/unicode_strtools.h @@ -57,6 +57,6 @@ int Q_UChar32ToUTF8(uchar32 uVal, char * pUTF8Out); int Q_UChar32ToUTF8Len(uchar32 uVal); qboolean Q_UnicodeValidate(const char *pUTF8); char *Q_UnicodeAdvance(char *pUTF8, int nChars); -qboolean Q_StripUnprintableAndSpace(char *pch);; +qboolean Q_StripUnprintableAndSpace(char *pch); qboolean V_UTF8ToUChar32(const char *pUTF8_, uchar32 *uValueOut); int Q_UnicodeRepair(char *pUTF8); diff --git a/rehlds/engine/zone.cpp b/rehlds/engine/zone.cpp index 2f67b78..da6f3ab 100644 --- a/rehlds/engine/zone.cpp +++ b/rehlds/engine/zone.cpp @@ -227,7 +227,7 @@ NOXREF void Z_Print(memzone_t *zone) memblock_t *block; Con_Printf("zone size: %i location: %p\n", mainzone->size, mainzone); - for (block = zone->blocklist.next;; block = block->next) + for (block = zone->blocklist.next; ; block = block->next) { Con_Printf("block:%p size:%7i tag:%3i\n", block, block->size, block->tag); @@ -257,7 +257,7 @@ void Z_CheckHeap(void) { memblock_t *block; - for (block = mainzone->blocklist.next;; block = block->next) + for (block = mainzone->blocklist.next; ; block = block->next) { if (block->next == &mainzone->blocklist) { diff --git a/rehlds/game_shared/bitvec.h b/rehlds/game_shared/bitvec.h new file mode 100644 index 0000000..a8e352f --- /dev/null +++ b/rehlds/game_shared/bitvec.h @@ -0,0 +1,164 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +class CBitVecAccessor +{ +public: + CBitVecAccessor(uint32 *pDWords, int iBit); + + void operator=(int val); + operator uint32(); + +private: + uint32 *m_pDWords; + int m_iBit; +}; + +// CBitVec allows you to store a list of bits and do operations on them like they were +// an atomic type +template +class CBitVec +{ +public: + CBitVec(); + + // Set all values to the specified value (0 or 1..) + void Init(int val = 0); + + // Access the bits like an array. + CBitVecAccessor operator[](int i); + + // Operations on other bit vectors. + CBitVec &operator=(CBitVec const &other); + bool operator==(CBitVec const &other); + bool operator!=(CBitVec const &other); + + // Get underlying dword representations of the bits. + int GetNumDWords() { return NUM_DWORDS; } + uint32 GetDWord(int i); + void SetDWord(int i, uint32 val); + int GetNumBits(); + +private: + + enum + { + NUM_DWORDS = NUM_BITS / 32 + !!(NUM_BITS & 31) + }; + + unsigned int m_DWords[ NUM_DWORDS ]; +}; + +inline CBitVecAccessor::CBitVecAccessor(uint32 *pDWords, int iBit) +{ + m_pDWords = pDWords; + m_iBit = iBit; +} + +inline void CBitVecAccessor::operator=(int val) +{ + if (val) + m_pDWords[m_iBit >> 5] |= (1 << (m_iBit & 31)); + else + m_pDWords[m_iBit >> 5] &= ~(uint32)(1 << (m_iBit & 31)); +} + +inline CBitVecAccessor::operator uint32() +{ + return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); +} + +template +inline int CBitVec::GetNumBits() +{ + return NUM_BITS; +} + +template +inline CBitVec::CBitVec() +{ + for (int i = 0; i < NUM_DWORDS; ++i) + m_DWords[i] = 0; +} + +template +inline void CBitVec::Init(int val) +{ + for (int i = 0; i < GetNumBits(); ++i) + { + (*this)[i] = val; + } +} + +template +inline CBitVec &CBitVec::operator=(CBitVec const &other) +{ + Q_memcpy(m_DWords, other.m_DWords, sizeof(m_DWords)); + return *this; +} + +template +inline CBitVecAccessor CBitVec::operator[](int i) +{ + assert(i >= 0 && i < GetNumBits()); + return CBitVecAccessor(m_DWords, i); +} + +template +inline bool CBitVec::operator==(CBitVec const &other) +{ + for (int i = 0; i < NUM_DWORDS; ++i) + { + if (m_DWords[i] != other.m_DWords[i]) + return false; + } + + return true; +} + +template +inline bool CBitVec::operator!=(CBitVec const &other) +{ + return !(*this == other); +} + +template +inline uint32 CBitVec::GetDWord(int i) +{ + assert(i >= 0 && i < NUM_DWORDS); + return m_DWords[i]; +} + +template +inline void CBitVec::SetDWord(int i, uint32 val) +{ + assert(i >= 0 && i < NUM_DWORDS); + m_DWords[i] = val; +} diff --git a/rehlds/game_shared/counter.h b/rehlds/game_shared/counter.h new file mode 100644 index 0000000..aedaf43 --- /dev/null +++ b/rehlds/game_shared/counter.h @@ -0,0 +1,187 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#ifdef _WIN32 + #include + #include + #include +#else + #include + #include + #include + #include + #ifdef OSX + #include + #else + #include + #endif + #include +#endif + +#include +#include +#include +#include +#include + +class CCounter +{ +public: + CCounter(); + + bool Init(); + double GetCurTime(); + +private: + int m_iLowShift; + double m_flPerfCounterFreq; + double m_flCurrentTime; + double m_flLastCurrentTime; +}; + +inline CCounter::CCounter() : + m_iLowShift(0), + m_flPerfCounterFreq(0), + m_flCurrentTime(0), + m_flLastCurrentTime(0) +{ + Init(); +} + +inline bool CCounter::Init() +{ +#ifdef _WIN32 + + LARGE_INTEGER performanceFreq; + if (!QueryPerformanceFrequency(&performanceFreq)) + return false; + + // get 32 out of the 64 time bits such that we have around + // 1 microsecond resolution + unsigned int lowpart, highpart; + lowpart = (unsigned int)performanceFreq.LowPart; + highpart = (unsigned int)performanceFreq.HighPart; + m_iLowShift = 0; + + while (highpart || (lowpart > 2000000.0)) + { + m_iLowShift++; + lowpart >>= 1; + lowpart |= (highpart & 1) << 31; + highpart >>= 1; + } + + m_flPerfCounterFreq = 1.0 / (double)lowpart; + +#endif // _WIN32 + + return true; +} + +inline double CCounter::GetCurTime() +{ +#ifdef _WIN32 + + static int sametimecount; + static unsigned int oldtime; + static int first = 1; + LARGE_INTEGER PerformanceCount; + unsigned int temp, t2; + double time; + + QueryPerformanceCounter(&PerformanceCount); + if (m_iLowShift == 0) + { + temp = (unsigned int)PerformanceCount.LowPart; + } + else + { + temp = ((unsigned int)PerformanceCount.LowPart >> m_iLowShift) | + ((unsigned int)PerformanceCount.HighPart << (32 - m_iLowShift)); + } + + if (first) + { + oldtime = temp; + first = 0; + } + else + { + // check for turnover or backward time + if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000)) + { + // so we can't get stuck + oldtime = temp; + } + else + { + t2 = temp - oldtime; + + time = (double)t2 * m_flPerfCounterFreq; + oldtime = temp; + + m_flCurrentTime += time; + + if (m_flCurrentTime == m_flLastCurrentTime) + { + if (++sametimecount > 100000) + { + m_flCurrentTime += 1.0; + sametimecount = 0; + } + } + else + { + sametimecount = 0; + } + + m_flLastCurrentTime = m_flCurrentTime; + } + } + + return m_flCurrentTime; + +#else // _WIN32 + + struct timeval tp; + static int secbase = 0; + + gettimeofday(&tp, NULL); + + if (!secbase) + { + secbase = tp.tv_sec; + return (tp.tv_usec / 1000000.0); + } + + return ((tp.tv_sec - secbase) + tp.tv_usec / 1000000.0); + +#endif // _WIN32 +} diff --git a/rehlds/game_shared/voice_common.h b/rehlds/game_shared/voice_common.h new file mode 100644 index 0000000..32e1ed9 --- /dev/null +++ b/rehlds/game_shared/voice_common.h @@ -0,0 +1,43 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef VOICE_COMMON_H +#define VOICE_COMMON_H +#ifdef _WIN32 +#pragma once +#endif + +#include "bitvec.h" + +// TODO: this should just be set to MAX_CLIENTS +#define VOICE_MAX_PLAYERS 32 +#define VOICE_MAX_PLAYERS_DW ((VOICE_MAX_PLAYERS / 32) + !!(VOICE_MAX_PLAYERS & 31)) + +typedef CBitVec< VOICE_MAX_PLAYERS > CPlayerBitVec; + +#endif // VOICE_COMMON_H diff --git a/rehlds/hookers/HLTV/Core/DeltaEx.cpp b/rehlds/hookers/HLTV/Core/DeltaEx.cpp new file mode 100644 index 0000000..99c5784 --- /dev/null +++ b/rehlds/hookers/HLTV/Core/DeltaEx.cpp @@ -0,0 +1,1537 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#ifdef HOOK_HLTV + +DeltaWrapper World::m_Delta; + +delta_definition_list_t *g_defs; +delta_encoder_t *g_encoders; +delta_registry_t *g_deltaregistry; + +double g_delta_Time; +bool g_large_Time_Buffers; + +delta_t *g_pentitydelta; +delta_t *g_pplayerdelta; +delta_t *g_pcustomentitydelta; +delta_t *g_pclientdelta; +delta_t *g_pweapondelta; +delta_t *g_peventdelta; + +#define DELTA_D_DEF(member) #member, offsetof(delta_description_s, member) +#define DELTA_DEF(structname, member) { #member, offsetof(structname, member) } + +delta_definition_t g_DeltaDataDefinition[] = +{ + DELTA_DEF(delta_description_s, fieldType), + DELTA_DEF(delta_description_s, fieldName), + DELTA_DEF(delta_description_s, fieldOffset), + DELTA_DEF(delta_description_s, fieldSize), + DELTA_DEF(delta_description_s, significant_bits), + DELTA_DEF(delta_description_s, premultiply), + DELTA_DEF(delta_description_s, postmultiply), + DELTA_DEF(delta_description_s, flags) +}; + +delta_description_t g_MetaDescription[] = +{ + { DT_INTEGER, DELTA_D_DEF(fieldType), 1, 32, 1.0, 1.0, 0, 0, 0 }, + { DT_STRING, DELTA_D_DEF(fieldName), 1, 1, 1.0, 1.0, 0, 0, 0 }, + { DT_INTEGER, DELTA_D_DEF(fieldOffset), 1, 16, 1.0, 1.0, 0, 0, 0 }, + { DT_INTEGER, DELTA_D_DEF(fieldSize), 1, 8, 1.0, 1.0, 0, 0, 0 }, + { DT_INTEGER, DELTA_D_DEF(significant_bits), 1, 8, 1.0, 1.0, 0, 0, 0 }, + { DT_FLOAT, DELTA_D_DEF(premultiply), 1, 32, 4000.0, 1.0, 0, 0, 0 }, + { DT_FLOAT, DELTA_D_DEF(postmultiply), 1, 32, 4000.0, 1.0, 0, 0, 0 } +}; + +namespace Delta { + delta_t g_MetaDelta[] = + { + { 0, ARRAYSIZE(g_MetaDescription), "", NULL, g_MetaDescription }, + }; + +}; // namespace Delta + +delta_definition_t g_EventDataDefinition[] = +{ + DELTA_DEF(event_args_s, entindex), + DELTA_DEF(event_args_s, origin[0]), + DELTA_DEF(event_args_s, origin[1]), + DELTA_DEF(event_args_s, origin[2]), + DELTA_DEF(event_args_s, angles[0]), + DELTA_DEF(event_args_s, angles[1]), + DELTA_DEF(event_args_s, angles[2]), + DELTA_DEF(event_args_s, fparam1), + DELTA_DEF(event_args_s, fparam2), + DELTA_DEF(event_args_s, iparam1), + DELTA_DEF(event_args_s, iparam2), + DELTA_DEF(event_args_s, bparam1), + DELTA_DEF(event_args_s, bparam2), + DELTA_DEF(event_args_s, ducking) +}; + +delta_definition_t g_EntityDataDefinition[] = +{ + DELTA_DEF(entity_state_s, startpos[0]), + DELTA_DEF(entity_state_s, startpos[1]), + DELTA_DEF(entity_state_s, startpos[2]), + DELTA_DEF(entity_state_s, endpos[0]), + DELTA_DEF(entity_state_s, endpos[1]), + DELTA_DEF(entity_state_s, endpos[2]), + DELTA_DEF(entity_state_s, impacttime), + DELTA_DEF(entity_state_s, starttime), + DELTA_DEF(entity_state_s, origin[0]), + DELTA_DEF(entity_state_s, origin[1]), + DELTA_DEF(entity_state_s, origin[2]), + DELTA_DEF(entity_state_s, angles[0]), + DELTA_DEF(entity_state_s, angles[1]), + DELTA_DEF(entity_state_s, angles[2]), + DELTA_DEF(entity_state_s, modelindex), + DELTA_DEF(entity_state_s, frame), + DELTA_DEF(entity_state_s, movetype), + DELTA_DEF(entity_state_s, colormap), + DELTA_DEF(entity_state_s, skin), + DELTA_DEF(entity_state_s, solid), + DELTA_DEF(entity_state_s, scale), + DELTA_DEF(entity_state_s, effects), + DELTA_DEF(entity_state_s, sequence), + DELTA_DEF(entity_state_s, animtime), + DELTA_DEF(entity_state_s, framerate), + DELTA_DEF(entity_state_s, controller[0]), + DELTA_DEF(entity_state_s, controller[1]), + DELTA_DEF(entity_state_s, controller[2]), + DELTA_DEF(entity_state_s, controller[3]), + DELTA_DEF(entity_state_s, blending[0]), + DELTA_DEF(entity_state_s, blending[1]), + DELTA_DEF(entity_state_s, body), + DELTA_DEF(entity_state_s, owner), + DELTA_DEF(entity_state_s, rendermode), + DELTA_DEF(entity_state_s, renderamt), + DELTA_DEF(entity_state_s, renderfx), + DELTA_DEF(entity_state_s, rendercolor.r), + DELTA_DEF(entity_state_s, rendercolor.g), + DELTA_DEF(entity_state_s, rendercolor.b), + DELTA_DEF(entity_state_s, weaponmodel), + DELTA_DEF(entity_state_s, gaitsequence), + DELTA_DEF(entity_state_s, mins[0]), + DELTA_DEF(entity_state_s, mins[1]), + DELTA_DEF(entity_state_s, mins[2]), + DELTA_DEF(entity_state_s, maxs[0]), + DELTA_DEF(entity_state_s, maxs[1]), + DELTA_DEF(entity_state_s, maxs[2]), + DELTA_DEF(entity_state_s, aiment), + DELTA_DEF(entity_state_s, basevelocity[0]), + DELTA_DEF(entity_state_s, basevelocity[1]), + DELTA_DEF(entity_state_s, basevelocity[2]), + DELTA_DEF(entity_state_s, friction), + DELTA_DEF(entity_state_s, gravity), + DELTA_DEF(entity_state_s, spectator), + DELTA_DEF(entity_state_s, velocity[0]), + DELTA_DEF(entity_state_s, velocity[1]), + DELTA_DEF(entity_state_s, velocity[2]), + DELTA_DEF(entity_state_s, team), + DELTA_DEF(entity_state_s, playerclass), + DELTA_DEF(entity_state_s, health), + DELTA_DEF(entity_state_s, usehull), + DELTA_DEF(entity_state_s, oldbuttons), + DELTA_DEF(entity_state_s, onground), + DELTA_DEF(entity_state_s, iStepLeft), + DELTA_DEF(entity_state_s, flFallVelocity), + DELTA_DEF(entity_state_s, weaponanim), + DELTA_DEF(entity_state_s, eflags), + DELTA_DEF(entity_state_s, iuser1), + DELTA_DEF(entity_state_s, iuser2), + DELTA_DEF(entity_state_s, iuser3), + DELTA_DEF(entity_state_s, iuser4), + DELTA_DEF(entity_state_s, fuser1), + DELTA_DEF(entity_state_s, fuser2), + DELTA_DEF(entity_state_s, fuser3), + DELTA_DEF(entity_state_s, fuser4), + DELTA_DEF(entity_state_s, vuser1[0]), + DELTA_DEF(entity_state_s, vuser1[1]), + DELTA_DEF(entity_state_s, vuser1[2]), + DELTA_DEF(entity_state_s, vuser2[0]), + DELTA_DEF(entity_state_s, vuser2[1]), + DELTA_DEF(entity_state_s, vuser2[2]), + DELTA_DEF(entity_state_s, vuser3[0]), + DELTA_DEF(entity_state_s, vuser3[1]), + DELTA_DEF(entity_state_s, vuser3[2]), + DELTA_DEF(entity_state_s, vuser4[0]), + DELTA_DEF(entity_state_s, vuser4[1]), + DELTA_DEF(entity_state_s, vuser4[2]) +}; + +delta_definition_t g_UsercmdDataDefinition[] = +{ + DELTA_DEF(usercmd_s, lerp_msec), + DELTA_DEF(usercmd_s, msec), + DELTA_DEF(usercmd_s, lightlevel), + DELTA_DEF(usercmd_s, viewangles[0]), + DELTA_DEF(usercmd_s, viewangles[1]), + DELTA_DEF(usercmd_s, viewangles[2]), + DELTA_DEF(usercmd_s, buttons), + DELTA_DEF(usercmd_s, forwardmove), + DELTA_DEF(usercmd_s, sidemove), + DELTA_DEF(usercmd_s, upmove), + DELTA_DEF(usercmd_s, impulse), + DELTA_DEF(usercmd_s, weaponselect), + DELTA_DEF(usercmd_s, impact_index), + DELTA_DEF(usercmd_s, impact_position[0]), + DELTA_DEF(usercmd_s, impact_position[1]), + DELTA_DEF(usercmd_s, impact_position[2]) +}; + +delta_definition_t g_WeaponDataDefinition[] = +{ + DELTA_DEF(weapon_data_s, m_iId), + DELTA_DEF(weapon_data_s, m_iClip), + DELTA_DEF(weapon_data_s, m_flNextPrimaryAttack), + DELTA_DEF(weapon_data_s, m_flNextSecondaryAttack), + DELTA_DEF(weapon_data_s, m_flTimeWeaponIdle), + DELTA_DEF(weapon_data_s, m_fInReload), + DELTA_DEF(weapon_data_s, m_fInSpecialReload), + DELTA_DEF(weapon_data_s, m_flNextReload), + DELTA_DEF(weapon_data_s, m_flPumpTime), + DELTA_DEF(weapon_data_s, m_fReloadTime), + DELTA_DEF(weapon_data_s, m_fAimedDamage), + DELTA_DEF(weapon_data_s, m_fNextAimBonus), + DELTA_DEF(weapon_data_s, m_fInZoom), + DELTA_DEF(weapon_data_s, m_iWeaponState), + DELTA_DEF(weapon_data_s, iuser1), + DELTA_DEF(weapon_data_s, iuser2), + DELTA_DEF(weapon_data_s, iuser3), + DELTA_DEF(weapon_data_s, iuser4), + DELTA_DEF(weapon_data_s, fuser1), + DELTA_DEF(weapon_data_s, fuser2), + DELTA_DEF(weapon_data_s, fuser3), + DELTA_DEF(weapon_data_s, fuser4) +}; + +delta_definition_t g_ClientDataDefinition[] = +{ + DELTA_DEF(clientdata_s, origin[0]), + DELTA_DEF(clientdata_s, origin[1]), + DELTA_DEF(clientdata_s, origin[2]), + DELTA_DEF(clientdata_s, velocity[0]), + DELTA_DEF(clientdata_s, velocity[1]), + DELTA_DEF(clientdata_s, velocity[2]), + DELTA_DEF(clientdata_s, viewmodel), + DELTA_DEF(clientdata_s, punchangle[0]), + DELTA_DEF(clientdata_s, punchangle[1]), + DELTA_DEF(clientdata_s, punchangle[2]), + DELTA_DEF(clientdata_s, flags), + DELTA_DEF(clientdata_s, waterlevel), + DELTA_DEF(clientdata_s, watertype), + DELTA_DEF(clientdata_s, view_ofs[0]), + DELTA_DEF(clientdata_s, view_ofs[1]), + DELTA_DEF(clientdata_s, view_ofs[2]), + DELTA_DEF(clientdata_s, health), + DELTA_DEF(clientdata_s, bInDuck), + DELTA_DEF(clientdata_s, weapons), + DELTA_DEF(clientdata_s, flTimeStepSound), + DELTA_DEF(clientdata_s, flDuckTime), + DELTA_DEF(clientdata_s, flSwimTime), + DELTA_DEF(clientdata_s, waterjumptime), + DELTA_DEF(clientdata_s, maxspeed), + DELTA_DEF(clientdata_s, m_iId), + DELTA_DEF(clientdata_s, ammo_nails), + DELTA_DEF(clientdata_s, ammo_shells), + DELTA_DEF(clientdata_s, ammo_cells), + DELTA_DEF(clientdata_s, ammo_rockets), + DELTA_DEF(clientdata_s, m_flNextAttack), + DELTA_DEF(clientdata_s, physinfo), + DELTA_DEF(clientdata_s, fov), + DELTA_DEF(clientdata_s, weaponanim), + DELTA_DEF(clientdata_s, tfstate), + DELTA_DEF(clientdata_s, pushmsec), + DELTA_DEF(clientdata_s, deadflag), + DELTA_DEF(clientdata_s, iuser1), + DELTA_DEF(clientdata_s, iuser2), + DELTA_DEF(clientdata_s, iuser3), + DELTA_DEF(clientdata_s, iuser4), + DELTA_DEF(clientdata_s, fuser1), + DELTA_DEF(clientdata_s, fuser2), + DELTA_DEF(clientdata_s, fuser3), + DELTA_DEF(clientdata_s, fuser4), + DELTA_DEF(clientdata_s, vuser1[0]), + DELTA_DEF(clientdata_s, vuser1[1]), + DELTA_DEF(clientdata_s, vuser1[2]), + DELTA_DEF(clientdata_s, vuser2[0]), + DELTA_DEF(clientdata_s, vuser2[1]), + DELTA_DEF(clientdata_s, vuser2[2]), + DELTA_DEF(clientdata_s, vuser3[0]), + DELTA_DEF(clientdata_s, vuser3[1]), + DELTA_DEF(clientdata_s, vuser3[2]), + DELTA_DEF(clientdata_s, vuser4[0]), + DELTA_DEF(clientdata_s, vuser4[1]), + DELTA_DEF(clientdata_s, vuser4[2]) +}; + +delta_description_t *DELTA_FindField(delta_t *pFields, const char *pszField) +{ + for (int i = 0; i < pFields->fieldCount; i++) + { + if (_stricmp(pFields->pdd[i].fieldName, pszField) == 0) { + return &pFields->pdd[i]; + } + } + + return nullptr; +} + +int DELTA_FindFieldIndex(delta_t *pFields, const char *fieldname) +{ + for (int i = 0; i < pFields->fieldCount; i++) + { + if (_stricmp(pFields->pdd[i].fieldName, fieldname) == 0) { + return i; + } + } + + return -1; +} + +void DELTA_SetField(delta_t *pFields, const char *fieldname) +{ + delta_description_t *pTest = DELTA_FindField(pFields, fieldname); + if (pTest) { + pTest->flags |= FDT_MARK; + } +} + +void DELTA_UnsetField(delta_t *pFields, const char *fieldname) +{ + delta_description_t *pTest = DELTA_FindField(pFields, fieldname); + if (pTest) { + pTest->flags &= ~FDT_MARK; + } +} + +void DELTA_SetFieldByIndex(delta_t *pFields, int fieldNumber) +{ + pFields->pdd[fieldNumber].flags |= FDT_MARK; +} + +void DELTA_UnsetFieldByIndex(delta_t *pFields, int fieldNumber) +{ + pFields->pdd[fieldNumber].flags &= ~FDT_MARK; +} + +void DELTA_ClearFlags(delta_t *pFields) +{ + for (int i = 0; i < pFields->fieldCount; i++) { + pFields->pdd[i].flags = 0; + } +} + +int DELTA_CountSendFields(delta_t *pFields) +{ + int i, c; + for (i = 0, c = 0; i < pFields->fieldCount; i++) + { + auto pitem = &pFields->pdd[i]; + if (pitem->flags & FDT_MARK) { + pitem->stats.sendcount++; + c++; + } + } + + return c; +} + +void DELTA_MarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields) +{ + int i; + char *st1, *st2; + delta_description_t *pTest; + int fieldType; + int fieldCount = pFields->fieldCount; + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + fieldType = pTest->fieldType & ~DT_SIGNED; + switch (fieldType) + { + case DT_BYTE: + if (from[pTest->fieldOffset] != to[pTest->fieldOffset]) + pTest->flags |= FDT_MARK; + break; + case DT_SHORT: + if (*(uint16 *)&from[pTest->fieldOffset] != *(uint16 *)&to[pTest->fieldOffset]) + pTest->flags |= FDT_MARK; + break; + case DT_FLOAT: + case DT_INTEGER: + case DT_ANGLE: + if (*(uint32 *)&from[pTest->fieldOffset] != *(uint32 *)&to[pTest->fieldOffset]) + pTest->flags |= FDT_MARK; + break; + case DT_TIMEWINDOW_8: + case DT_TIMEWINDOW_BIG: + if (*(uint32 *)&from[pTest->fieldOffset] != *(uint32 *)&to[pTest->fieldOffset]) + pTest->flags |= FDT_MARK; + break; + case DT_STRING: + st1 = (char *)&from[pTest->fieldOffset]; + st2 = (char *)&to[pTest->fieldOffset]; + + // Not sure why it is case insensitive, but it looks so + if (!(!*st1 && !*st2 || *st1 && *st2 && !_stricmp(st1, st2))) { + pTest->flags |= FDT_MARK; + } + break; + default: + break; + } + } + + if (pFields->conditionalencode) { + pFields->conditionalencode(pFields, from, to); + } +} + +void DELTA_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount) +{ + int i; + int lastbit = -1; + int fieldCount = pFields->fieldCount; + + memset(bits, 0, 8); + + for (i = fieldCount - 1; i >= 0; i--) + { + if (pFields->pdd[i].flags & FDT_MARK) + { + if (lastbit == -1) { + lastbit = i; + } + + bits[i > 31 ? 1 : 0] |= 1 << (i & 0x1f); + } + } + + // fix for bad bytecount when no fields are marked + if (lastbit == -1) { + *bytecount = 0; + return; + } + + *bytecount = (lastbit >> 3) + 1; +} + +void DELTA_WriteMarkedFields(BitBuffer *stream, unsigned char *from, unsigned char *to, delta_t *pFields) +{ + int i; + delta_description_t *pTest; + int fieldSign; + int fieldType; + + float f2; + int fieldCount = pFields->fieldCount; + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + if (!(pTest->flags & FDT_MARK)) + continue; + + fieldSign = pTest->fieldType & DT_SIGNED; + fieldType = pTest->fieldType & ~DT_SIGNED; + switch (fieldType) + { + case DT_BYTE: + if (fieldSign) + { + int8 si8 = *(int8 *)&to[pTest->fieldOffset]; + si8 = (int8)((double)si8 * pTest->premultiply); + stream->WriteSBits(si8, pTest->significant_bits); + } + else + { + uint8 i8 = *(uint8 *)&to[pTest->fieldOffset]; + i8 = (uint8)((double)i8 * pTest->premultiply); + stream->WriteBits(i8, pTest->significant_bits); + } + break; + case DT_SHORT: + if (fieldSign) + { + int16 si16 = *(int16 *)&to[pTest->fieldOffset]; + si16 = (int16)((double)si16 * pTest->premultiply); + stream->WriteSBits(si16, pTest->significant_bits); + } + else + { + uint16 i16 = *(uint16 *)&to[pTest->fieldOffset]; + i16 = (uint16)((double)i16 * pTest->premultiply); + stream->WriteBits(i16, pTest->significant_bits); + } + break; + case DT_FLOAT: + { + double val = (double)(*(float *)&to[pTest->fieldOffset]) * pTest->premultiply; + if (fieldSign) + { + stream->WriteSBits((int32)val, pTest->significant_bits); + } + else + { + stream->WriteBits((uint32)val, pTest->significant_bits); + } + break; + } + case DT_INTEGER: + { + if (fieldSign) + { + int32 signedInt = *(int32 *)&to[pTest->fieldOffset]; + if (pTest->premultiply < 0.9999 || pTest->premultiply > 1.0001) { + signedInt = (int32)((double)signedInt * pTest->premultiply); + } + + stream->WriteSBits(signedInt, pTest->significant_bits); + } + else + { + uint32 unsignedInt = *(uint32 *)&to[pTest->fieldOffset]; + if (pTest->premultiply < 0.9999 || pTest->premultiply > 1.0001) { + unsignedInt = (uint32)((double)unsignedInt * pTest->premultiply); + } + + stream->WriteBits(unsignedInt, pTest->significant_bits); + } + break; + } + case DT_ANGLE: + f2 = *(float *)&to[pTest->fieldOffset]; + stream->WriteBitAngle(f2, pTest->significant_bits); + break; + case DT_TIMEWINDOW_8: + { + f2 = *(float *)&to[pTest->fieldOffset]; + if (g_large_Time_Buffers) { + stream->WriteFloat(f2); + } else { + int32 twVal = (int)(g_delta_Time * 100.0) - (int)(f2 * 100.0); + stream->WriteSBits(twVal, 8); + } + break; + } + case DT_TIMEWINDOW_BIG: + { + f2 = *(float *)&to[pTest->fieldOffset]; + if (g_large_Time_Buffers) { + stream->WriteFloat(f2); + } else { + int32 twVal = (int)(g_delta_Time * pTest->premultiply) - (int)(f2 * pTest->premultiply); + stream->WriteSBits((int32)twVal, pTest->significant_bits); + } + break; + } + case DT_STRING: + stream->WriteBitString((const char *)&to[pTest->fieldOffset]); + break; + default: + break; + } + } +} + +int DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields) +{ + DELTA_ClearFlags(pFields); + DELTA_MarkSendFields(from, to, pFields); + + return DELTA_CountSendFields(pFields); +} + +void DELTA_WriteHeader(BitBuffer *stream, deltacallback_t *header) +{ + int delta = header->num - header->numbase; + if (header->full) + { + if (delta == 1) + { + stream->WriteBit(1); + } + else + { + stream->WriteBit(0); + if (delta <= 0 || delta >= 64) + { + stream->WriteBit(1); + stream->WriteBits(header->num, 11); + } + else + { + stream->WriteBit(0); + stream->WriteBits(delta, 6); + } + } + } + else + { + stream->WriteBit(header->remove != 0); + if (delta <= 0 || delta >= 64) + { + stream->WriteBit(1); + stream->WriteBits(header->num, 11); + } + else + { + stream->WriteBit(0); + stream->WriteBits(delta, 6); + } + } + + header->numbase = header->num; + if (!header->remove) + { + stream->WriteBit(header->custom != 0); + if (header->instanced_baseline) + { + if (header->newbl) + { + stream->WriteBit(1); + stream->WriteBits(header->newblindex, 6); + } + else + { + stream->WriteBit(0); + } + } + if (header->full && !header->newbl) + { + if (header->offset) + { + stream->WriteBit(1); + stream->WriteBits(header->offset, 6); + } + else + { + stream->WriteBit(0); + } + } + } +} + +qboolean DELTA_WriteDelta(BitBuffer *stream, unsigned char *from, unsigned char *to, bool force, delta_t *pFields, deltacallback_t *header) +{ + int i; + int bytecount; + int bits[2]; + + if (!DELTA_CheckDelta(from, to, pFields) && !force) { + return FALSE; + } + + DELTA_SetSendFlagBits(pFields, bits, &bytecount); + + if (header) { + DELTA_WriteHeader(stream, header); + } + + stream->WriteBits(bytecount, 3); + for (i = 0; i < bytecount; i++) { + stream->WriteBits(((byte *)bits)[i], 8); + } + + DELTA_WriteMarkedFields(stream, from, to, pFields); + return TRUE; +} + +int DELTA_ParseDelta(BitBuffer *stream, unsigned char *from, unsigned char *to, delta_t *pFields) +{ + delta_description_t *pTest; + int i; + int bits[2]; // this is a limit with 64 fields max in delta + int nbytes; + int bitfieldnumber; + int fieldCount = pFields->fieldCount; + int fieldType; + int fieldSign; + + double d2; + float t; + int addt; + char *st2; + char c; + int startbit; + + startbit = stream->CurrentBit(); + memset(bits, 0, sizeof(bits)); + + nbytes = stream->ReadBits(3); + for (i = 0; i < nbytes; i++) { + ((byte *)bits)[i] = stream->ReadBits(8); + } + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + fieldType = pTest->fieldType & ~DT_SIGNED; + + bitfieldnumber = (1 << (i & 0x1F)); + if (!(bitfieldnumber & bits[i > 31])) + { + // Field was not sent to us, just transfer info from the "from" + switch (fieldType) + { + case DT_BYTE: + to[pTest->fieldOffset] = from[pTest->fieldOffset]; + break; + case DT_SHORT: + *(uint16 *)&to[pTest->fieldOffset] = *(uint16 *)&from[pTest->fieldOffset]; + break; + case DT_FLOAT: + case DT_INTEGER: + case DT_ANGLE: + case DT_TIMEWINDOW_8: + case DT_TIMEWINDOW_BIG: + *(uint32 *)&to[pTest->fieldOffset] = *(uint32 *)&from[pTest->fieldOffset]; + break; + case DT_STRING: + strcpy((char *)&to[pTest->fieldOffset], (char *)&from[pTest->fieldOffset]); + break; + default: + break; + } + continue; + } + + pTest->stats.receivedcount++; + fieldSign = pTest->fieldType & DT_SIGNED; + + switch (fieldType) + { + case DT_BYTE: + if (fieldSign) + { + d2 = (double)stream->ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#if !defined(HLTV) + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(int8 *)&to[pTest->fieldOffset] = (int8)d2; + } + else + { + d2 = (double)stream->ReadBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#if !defined(HLTV) + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(uint8 *)&to[pTest->fieldOffset] = (uint8)d2; + } + break; + case DT_SHORT: + if (fieldSign) + { + d2 = (double)stream->ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#if !defined(HLTV) + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(int16 *)&to[pTest->fieldOffset] = (int16)d2; + } + else + { + d2 = (double)stream->ReadBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#if !defined(HLTV) + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(uint16 *)&to[pTest->fieldOffset] = (uint16)d2; + } + break; + case DT_FLOAT: + if (fieldSign) + { + d2 = (double)stream->ReadSBits(pTest->significant_bits); + } + else + { + d2 = (double)stream->ReadBits(pTest->significant_bits); + } + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#if !defined(HLTV) + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(float *)&to[pTest->fieldOffset] = (float)d2; + break; + case DT_INTEGER: + if (fieldSign) + { + d2 = (double)stream->ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#if !defined(HLTV) + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(int32 *)&to[pTest->fieldOffset] = (int32)d2; + } + else + { + d2 = (double)stream->ReadBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + d2 = d2 / pTest->premultiply; + } +#if !defined(HLTV) + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) { + d2 = d2 * pTest->postmultiply; + } +#endif + *(uint32 *)&to[pTest->fieldOffset] = (uint32)d2; + } + break; + case DT_ANGLE: + *(float *)&to[pTest->fieldOffset] = stream->ReadBitAngle(pTest->significant_bits); + break; + case DT_TIMEWINDOW_8: + if (g_large_Time_Buffers) { + t = stream->ReadFloat(); + } + else { + addt = stream->ReadSBits(8); + t = (float)((g_delta_Time * 100.0 - addt) / 100.0); + } + *(float *)&to[pTest->fieldOffset] = t; + break; + case DT_TIMEWINDOW_BIG: + if (g_large_Time_Buffers) { + t = stream->ReadFloat(); + } + else { + addt = stream->ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) { + t = (float)((g_delta_Time * pTest->premultiply - addt) / pTest->premultiply); + } + else { + t = (float)(g_delta_Time - addt); + } + } + + *(float *)&to[pTest->fieldOffset] = t; + break; + case DT_STRING: + st2 = (char *)&to[pTest->fieldOffset]; + do + { + c = stream->ReadBits(8); + *st2++ = c; + } while (c); + break; + default: + break; + } + } + + return stream->CurrentBit() - startbit; +} + +int DELTA_TestDelta(unsigned char *from, unsigned char *to, delta_t *pFields) +{ + int i; + char *st1, *st2; + delta_description_t *pTest; + int fieldType; + int fieldCount = pFields->fieldCount; + int length = 0; + bool different; + int neededBits = 0; + int highestBit = -1; + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + different = false; + fieldType = pTest->fieldType & ~DT_SIGNED; + + switch (fieldType) + { + case DT_BYTE: + different = from[pTest->fieldOffset] != to[pTest->fieldOffset]; + break; + case DT_SHORT: + different = *(uint16 *)&from[pTest->fieldOffset] != *(uint16 *)&to[pTest->fieldOffset]; + break; + case DT_FLOAT: + case DT_INTEGER: + case DT_ANGLE: + different = *(uint32 *)&from[pTest->fieldOffset] != *(uint32 *)&to[pTest->fieldOffset]; + break; + // don't use multiplier when checking, to increase performance + // check values binary like it does in jit + case DT_TIMEWINDOW_8: + case DT_TIMEWINDOW_BIG: + different = (*(int32 *)&from[pTest->fieldOffset]) != (*(int32 *)&to[pTest->fieldOffset]); + break; + case DT_STRING: + st1 = (char *)&from[pTest->fieldOffset]; + st2 = (char *)&to[pTest->fieldOffset]; + + // Not sure why it is case insensitive, but it looks so + if (!(!*st1 && !*st2 || *st1 && *st2 && !_stricmp(st1, st2))) + { + different = true; + length = strlen(st2) * 8; + pTest->flags |= FDT_MARK; + } + break; + default: + break; + } + + if (different) + { + highestBit = i; + neededBits += (fieldType == DT_STRING) ? length + 8 : pTest->significant_bits; + } + } + + if (highestBit != -1) { + neededBits += highestBit / 8 * 8 + 8; + } + + return neededBits; +} + +void DELTA_AddEncoder(char *name, encoder_t conditionalencode) +{ + delta_encoder_t *delta = (delta_encoder_t *)Mem_ZeroMalloc(sizeof(delta_encoder_t)); + delta->name = _strdup(name); + delta->conditionalencode = conditionalencode; + delta->next = g_encoders; + g_encoders = delta; +} + +void DELTA_ClearEncoders() +{ + delta_encoder_t *n, *p = g_encoders; + while (p) + { + n = p->next; + free(p->name); + free(p); + p = n; + } + + g_encoders = nullptr; +} + +encoder_t DELTA_LookupEncoder(char *name) +{ + delta_encoder_t *p = g_encoders; + while (p) + { + if (_stricmp(name, p->name) == 0) { + return p->conditionalencode; + } + + p = p->next; + } + + return nullptr; +} + +int DELTA_CountLinks(delta_link_t *plinks) +{ + delta_link_t *p = plinks; + + int c; + for (c = 0; p; c++) { + p = p->next; + } + + return c; +} + +void DELTA_ReverseLinks(delta_link_t **plinks) +{ + delta_link_t *n, *p = *plinks; + delta_link_t *newlist = nullptr; + + while (p) + { + n = p->next; + p->next = newlist; + newlist = p; + p = n; + } + + *plinks = newlist; +} + +void DELTA_ClearLinks(delta_link_t **plinks) +{ + delta_link_t *n, *p = *plinks; + while (p) + { + n = p->next; + free(p); + p = n; + } + *plinks = 0; +} + +delta_t *DELTA_BuildFromLinks(delta_link_t **pplinks) +{ + delta_description_t *pdesc, *pcur; + delta_t *pdelta; + delta_link_t *p; + int count; + + pdelta = (delta_t *)Mem_ZeroMalloc(sizeof(delta_t)); + DELTA_ReverseLinks(pplinks); + count = DELTA_CountLinks(*pplinks); + + if (count > DELTA_MAX_FIELDS) { + return nullptr; + } + + pdesc = (delta_description_t *)Mem_ZeroMalloc(sizeof(delta_description_t) * count); + + for (p = *pplinks, pcur = pdesc; p; p = p->next, pcur++) + { + memcpy(pcur, p->delta, sizeof(delta_description_t)); + free(p->delta); + p->delta = nullptr; + } + + DELTA_ClearLinks(pplinks); + + pdelta->dynamic = 1; + pdelta->fieldCount = count; + pdelta->pdd = pdesc; + + return pdelta; +} + +int DELTA_FindOffset(int count, delta_definition_t *pdef, char *fieldname) +{ + for (int i = 0; i < count; i++) + { + if (_stricmp(fieldname, pdef[i].fieldName) == 0) { + return pdef[i].fieldOffset; + } + } + + return 0; +} + +bool DELTA_ParseType(delta_description_t *pdelta, char **pstream) +{ + // Read the stream till we hit the end + while (*pstream = COM_Parse(*pstream), com_token[0] != 0) + { + if (!_stricmp(com_token, ",")) + return true; // end of type description + + if (!_stricmp(com_token, "|")) + continue; // skip | token + + // Determine field type + if (!_stricmp(com_token, "DT_SIGNED")) + pdelta->fieldType |= DT_SIGNED; + else if (!_stricmp(com_token, "DT_BYTE")) + pdelta->fieldType |= DT_BYTE; + else if (!_stricmp(com_token, "DT_SHORT")) + pdelta->fieldType |= DT_SHORT; + else if (!_stricmp(com_token, "DT_FLOAT")) + pdelta->fieldType |= DT_FLOAT; + else if (!_stricmp(com_token, "DT_INTEGER")) + pdelta->fieldType |= DT_INTEGER; + else if (!_stricmp(com_token, "DT_ANGLE")) + pdelta->fieldType |= DT_ANGLE; + else if (!_stricmp(com_token, "DT_TIMEWINDOW_8")) + pdelta->fieldType |= DT_TIMEWINDOW_8; + else if (!_stricmp(com_token, "DT_TIMEWINDOW_BIG")) + pdelta->fieldType |= DT_TIMEWINDOW_BIG; + else if (!_stricmp(com_token, "DT_STRING")) + pdelta->fieldType |= DT_STRING; + else + { + return false; + } + } + + // We are hit the end of the stream + return false; +} + +bool DELTA_ParseField(int count, delta_definition_t *pdefinition, delta_link_t *pField, char **pstream) +{ + bool readpost = false; + if (_stricmp(com_token, "DEFINE_DELTA")) + { + if (_stricmp(com_token, "DEFINE_DELTA_POST") != 0) { + return false; + } + + readpost = true; + } + + *pstream = COM_Parse(*pstream); + if (_stricmp(com_token, "(")) + { + return false; + } + + *pstream = COM_Parse(*pstream); + if (com_token[0] == '\0') + { + return false; + } + + strncpy(pField->delta->fieldName, com_token, sizeof(pField->delta->fieldName) - 1); + pField->delta->fieldName[sizeof(pField->delta->fieldName) - 1] = '\0'; + + pField->delta->fieldOffset = DELTA_FindOffset(count, pdefinition, com_token); + + *pstream = COM_Parse(*pstream); + if (!DELTA_ParseType(pField->delta, pstream)) { + return false; + } + + *pstream = COM_Parse(*pstream); + pField->delta->fieldSize = 1; + pField->delta->significant_bits = atoi(com_token); + *pstream = COM_Parse(*pstream); + *pstream = COM_Parse(*pstream); + pField->delta->premultiply = (float)atof(com_token); + + if (readpost) + { + *pstream = COM_Parse(*pstream); + *pstream = COM_Parse(*pstream); + pField->delta->postmultiply = (float)atof(com_token); + } + else + { + pField->delta->postmultiply = 1.0; + } + + *pstream = COM_Parse(*pstream); + if (_stricmp(com_token, ")")) + { + return false; + } + + *pstream = COM_Parse(*pstream); + if (_stricmp(com_token, ",")) { + COM_UngetToken(); + } + + return true; +} + +void DELTA_FreeDescription(delta_t **ppdesc) +{ + if (ppdesc && *ppdesc) + { + if ((*ppdesc)->dynamic) { + free((*ppdesc)->pdd); + } + + free(*ppdesc); + *ppdesc = nullptr; + } +} + +void DELTA_AddDefinition(char *name, delta_definition_t *pdef, int numelements) +{ + delta_definition_list_t *p = g_defs; + while (p) + { + if (_stricmp(name, p->ptypename) == 0) { + break; + } + + p = p->next; + } + + if (!p) + { + p = (delta_definition_list_t *)Mem_ZeroMalloc(sizeof(delta_definition_list_t)); + p->ptypename = _strdup(name); + p->next = g_defs; + g_defs = p; + } + + p->pdefinition = pdef; + p->numelements = numelements; +} + +void DELTA_ClearDefinitions() +{ + delta_definition_list_t *n, *p = g_defs; + while (p) + { + n = p->next; + free(p->ptypename); + free(p); + p = n; + } + + g_defs = nullptr; +} + +delta_definition_t *DELTA_FindDefinition(char *name, int *count) +{ + *count = 0; + + delta_definition_list_t *p = g_defs; + while (p) + { + if (!_stricmp(name, p->ptypename)) + { + *count = p->numelements; + return p->pdefinition; + } + + p = p->next; + } + + return nullptr; +} + +void DELTA_SkipDescription(char **pstream) +{ + *pstream = COM_Parse(*pstream); + do + { + *pstream = COM_Parse(*pstream); + if (com_token[0] == '\0') { + return; + } + } + while (_stricmp(com_token, "}")); +} + +bool DELTA_ParseOneField(char **ppstream, delta_link_t **pplist, int count, delta_definition_t *pdefinition) +{ + delta_link_t *newlink; + delta_link_t link; + + while (true) + { + if (!_stricmp(com_token, "}")) + { + COM_UngetToken(); + break; + } + + *ppstream = COM_Parse(*ppstream); + if (com_token[0] == '\0') { + break; + } + + memset(&link, 0, sizeof(link)); + link.delta = (delta_description_t *)Mem_ZeroMalloc(sizeof(delta_description_t)); + if (!DELTA_ParseField(count, pdefinition, &link, ppstream)) { + return false; + } + + newlink = (delta_link_t *)Mem_ZeroMalloc(sizeof(delta_link_t)); + newlink->delta = link.delta; + newlink->next = *pplist; + *pplist = newlink; + } + + return true; +} + +bool DELTA_ParseDescription(char *name, delta_t **ppdesc, char *pstream) +{ + delta_link_t *links = nullptr; + delta_definition_t *pdefinition; + char encoder[32] = ""; + char source[32]; + int count = 0; + + if (!ppdesc) { + return false; + } + + *ppdesc = nullptr; + + if (!pstream) { + return false; + } + + while (true) + { + // Parse delta name + pstream = COM_Parse(pstream); + if (com_token[0] == '\0') { + break; + } + + if (_stricmp(com_token, name)) + { + DELTA_SkipDescription(&pstream); + } + else + { + pdefinition = DELTA_FindDefinition(com_token, &count); + if (!pdefinition) { + return false; + } + + // Parse source of conditional encoder + pstream = COM_Parse(pstream); + if (com_token[0] == '\0') { + return false; + } + + if (_stricmp(com_token, "none")) + { + strncpy(source, com_token, sizeof(source) - 1); + source[sizeof(source) - 1] = '\0'; + + // Parse custom encoder function name + pstream = COM_Parse(pstream); + if (com_token[0] == '\0') { + return false; + } + + strncpy(encoder, com_token, sizeof(encoder) - 1); + encoder[sizeof(encoder) - 1] = '\0'; + } + + // Parse fields + while (true) + { + pstream = COM_Parse(pstream); + if (com_token[0] == '\0') { + break; + } + + if (!_stricmp(com_token, "}")) { + break; + } + + if (_stricmp(com_token, "{")) { + return false; + } + + if (!DELTA_ParseOneField(&pstream, &links, count, pdefinition)) { + return false; + } + } + } + } + + *ppdesc = DELTA_BuildFromLinks(&links); + + if (encoder[0]) + { + strncpy((*ppdesc)->conditionalencodename, encoder, sizeof((*ppdesc)->conditionalencodename) - 1); + (*ppdesc)->conditionalencodename[sizeof((*ppdesc)->conditionalencodename) - 1] = '\0'; + (*ppdesc)->conditionalencode = nullptr; + } + + return true; +} + +bool DELTA_Load(char *name, delta_t **ppdesc, char *pszFile) +{ + return false; +} + +void DELTA_RegisterDescription(char *name) +{ + delta_registry_t *p = (delta_registry_t *)Mem_ZeroMalloc(sizeof(delta_registry_t)); + p->next = g_deltaregistry; + g_deltaregistry = p; + p->name = _strdup(name); + p->pdesc = 0; +} + +void DELTA_ClearRegistrations() +{ + delta_registry_t *n, *p = g_deltaregistry; + while (p) + { + n = p->next; + free(p->name); + + if (p->pdesc) { + DELTA_FreeDescription(&p->pdesc); + } + + free(p); + p = n; + } + + g_deltaregistry = nullptr; +} + +delta_t **DELTA_LookupRegistration(char *name) +{ + delta_registry_t *delta = g_deltaregistry; + while (delta) + { + if (_stricmp(delta->name, name) == 0) { + return &delta->pdesc; + } + + delta = delta->next; + } + + return nullptr; +} + +void DELTA_ClearStats(delta_t *p) +{ + if (!p) { + return; + } + + for (int i = 0; i < p->fieldCount; i++) + { + p->pdd[i].stats.sendcount = 0; + p->pdd[i].stats.receivedcount = 0; + } +} + +void DELTA_Init() +{ + g_defs = nullptr; + g_encoders = nullptr; + g_deltaregistry = nullptr; + + DELTA_AddDefinition("clientdata_t", g_ClientDataDefinition, ARRAYSIZE(g_ClientDataDefinition)); + DELTA_AddDefinition("weapon_data_t", g_WeaponDataDefinition, ARRAYSIZE(g_WeaponDataDefinition)); + DELTA_AddDefinition("usercmd_t", g_UsercmdDataDefinition, ARRAYSIZE(g_UsercmdDataDefinition)); + DELTA_AddDefinition("entity_state_t", g_EntityDataDefinition, ARRAYSIZE(g_EntityDataDefinition)); + DELTA_AddDefinition("entity_state_player_t", g_EntityDataDefinition, ARRAYSIZE(g_EntityDataDefinition)); + DELTA_AddDefinition("custom_entity_state_t", g_EntityDataDefinition, ARRAYSIZE(g_EntityDataDefinition)); + DELTA_AddDefinition("event_t", g_EventDataDefinition, ARRAYSIZE(g_EventDataDefinition)); + + DELTA_RegisterDescription("clientdata_t"); + DELTA_RegisterDescription("entity_state_t"); + DELTA_RegisterDescription("entity_state_player_t"); + DELTA_RegisterDescription("custom_entity_state_t"); + DELTA_RegisterDescription("usercmd_t"); + DELTA_RegisterDescription("weapon_data_t"); + DELTA_RegisterDescription("event_t"); + + g_large_Time_Buffers = false; +} + +void DELTA_UpdateDescriptions() +{ + g_pplayerdelta = *DELTA_LookupRegistration("entity_state_player_t"); + g_pentitydelta = *DELTA_LookupRegistration("entity_state_t"); + g_pcustomentitydelta = *DELTA_LookupRegistration("custom_entity_state_t"); + g_pclientdelta = *DELTA_LookupRegistration("clientdata_t"); + g_pweapondelta = *DELTA_LookupRegistration("weapon_data_t"); + g_peventdelta = *DELTA_LookupRegistration("event_t"); +} + +void DELTA_Shutdown() +{ + DELTA_ClearEncoders(); + DELTA_ClearDefinitions(); + DELTA_ClearRegistrations(); +} + +void DELTA_SetTime(double time) +{ + g_delta_Time = time; +} + +void DELTA_SetLargeTimeBufferSize(bool bigBuffers) +{ + g_large_Time_Buffers = bigBuffers; +} + +bool World::IsDeltaEncoder() const +{ + if (g_pcustomentitydelta + && g_pentitydelta + && g_pplayerdelta) { + return true; + } + + return false; +} + +delta_t *World::GetDeltaEncoder(int index, bool custom) +{ + if (custom) { + return (delta_t *)g_pcustomentitydelta; + } + else if (IsPlayerIndex(index)) { + return (delta_t *)g_pplayerdelta; + } + + return (delta_t *)g_pentitydelta; +} + +delta_t *World::GetEventDelta() const { + return g_peventdelta; +} + +delta_t *World::GetClientDelta() const { + return g_pclientdelta; +} + +delta_t *World::GetEntityDelta() const { + return g_pentitydelta; +} + +delta_t *World::GetWeaponDelta() const { + return g_pweapondelta; +} + +#endif // HOOK_HLTV diff --git a/rehlds/hookers/HLTV/Core/DeltaEx.h b/rehlds/hookers/HLTV/Core/DeltaEx.h new file mode 100644 index 0000000..06db8ed --- /dev/null +++ b/rehlds/hookers/HLTV/Core/DeltaEx.h @@ -0,0 +1,163 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#ifdef HOOK_HLTV + +#include "event_args.h" + +#define g_defs (*pg_defs) +#define g_encoders (*pg_encoders) +#define g_deltaregistry (*pg_deltaregistry) + +#define g_pplayerdelta (*pg_pplayerdelta) +#define g_pentitydelta (*pg_pentitydelta) +#define g_pcustomentitydelta (*pg_pcustomentitydelta) +#define g_pclientdelta (*pg_pclientdelta) +#define g_pweapondelta (*pg_pweapondelta) +#define g_peventdelta (*pg_peventdelta) + +#define g_delta_Time (*pg_delta_Time) +#define g_large_Time_Buffers (*pg_large_Time_Buffers) + +typedef struct delta_link_s +{ + struct delta_link_s *next; + delta_description_t *delta; +} delta_link_t; + +typedef struct delta_definition_s +{ + char *fieldName; + size_t fieldOffset; +} delta_definition_t; + +typedef struct delta_definition_list_s +{ + struct delta_definition_list_s *next; + char *ptypename; + int numelements; + delta_definition_t *pdefinition; +} delta_definition_list_t; + +typedef struct delta_registry_s +{ + struct delta_registry_s *next; + char *name; + delta_t *pdesc; +} delta_registry_t; + +namespace Delta { + #define m_MetaDelta g_MetaDelta + extern delta_t g_MetaDelta[]; +}; + +#define m_EntityDelta g_pentitydelta +#define m_PlayerDelta g_pplayerdelta +#define m_CustomentityDelta g_pcustomentitydelta + +#define m_ClientDelta g_pclientdelta +#define m_WeaponDelta g_pweapondelta +#define m_EventDelta g_peventdelta + +extern delta_definition_list_t *g_defs; +extern delta_encoder_t *g_encoders; +extern delta_registry_t *g_deltaregistry; + +extern delta_t *g_pentitydelta; +extern delta_t *g_pplayerdelta; +extern delta_t *g_pcustomentitydelta; +extern delta_t *g_pclientdelta; +extern delta_t *g_pweapondelta; +extern delta_t *g_peventdelta; + +extern double g_delta_Time; +extern bool g_large_Time_Buffers; + +delta_description_t *DELTA_FindField(delta_t *pFields, const char *pszField); +int DELTA_FindFieldIndex(delta_t *pFields, const char *fieldname); +void DELTA_SetField(delta_t *pFields, const char *fieldname); +void DELTA_UnsetField(delta_t *pFields, const char *fieldname); +void DELTA_SetFieldByIndex(delta_t *pFields, int fieldNumber); +void DELTA_UnsetFieldByIndex(delta_t *pFields, int fieldNumber); +void DELTA_ClearFlags(delta_t *pFields); +int DELTA_CountSendFields(delta_t *pFields); +void DELTA_MarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields); +void DELTA_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount); +void DELTA_WriteMarkedFields(BitBuffer *stream, unsigned char *from, unsigned char *to, delta_t *pFields); +int DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields); +void DELTA_WriteHeader(BitBuffer *stream, deltacallback_t *header); +qboolean DELTA_WriteDelta(BitBuffer *stream, unsigned char *from, unsigned char *to, bool force, delta_t *pFields, deltacallback_t *header = nullptr); +int DELTA_ParseDelta(BitBuffer *stream, unsigned char *from, unsigned char *to, delta_t *pFields); +int DELTA_TestDelta(unsigned char *from, unsigned char *to, delta_t *pFields); +void DELTA_AddEncoder(char *name, encoder_t conditionalencode); +void DELTA_ClearEncoders(); +encoder_t DELTA_LookupEncoder(char *name); +int DELTA_CountLinks(delta_link_t *plinks); +void DELTA_ReverseLinks(delta_link_t **plinks); +void DELTA_ClearLinks(delta_link_t **plinks); +delta_t *DELTA_BuildFromLinks(delta_link_t **pplinks); +int DELTA_FindOffset(int count, delta_definition_t *pdef, char *fieldname); +bool DELTA_ParseType(delta_description_t *pdelta, char **pstream); +bool DELTA_ParseField(int count, delta_definition_t *pdefinition, delta_link_t *pField, char **pstream); +void DELTA_FreeDescription(delta_t **ppdesc); +void DELTA_AddDefinition(char *name, delta_definition_t *pdef, int numelements); +void DELTA_ClearDefinitions(); +delta_definition_t *DELTA_FindDefinition(char *name, int *count); +void DELTA_SkipDescription(char **pstream); +bool DELTA_ParseOneField(char **ppstream, delta_link_t **pplist, int count, delta_definition_t *pdefinition); +bool DELTA_ParseDescription(char *name, delta_t **ppdesc, char *pstream); +bool DELTA_Load(char *name, delta_t **ppdesc, char *pszFile); +void DELTA_RegisterDescription(char *name); +void DELTA_ClearRegistrations(); +delta_t **DELTA_LookupRegistration(char *name); +void DELTA_ClearStats(delta_t *p); +void DELTA_Init(); +void DELTA_UpdateDescriptions(); +void DELTA_Shutdown(); +void DELTA_SetTime(double time); +void DELTA_SetLargeTimeBufferSize(bool bigBuffers); + +class DeltaWrapper { +public: + void Init(IBaseSystem *system) { DELTA_Init(); } + void Shutdown() { DELTA_Shutdown(); } + void UpdateDescriptions() { DELTA_UpdateDescriptions(); } + void WriteHeader(BitBuffer *stream, deltacallback_t *header) { DELTA_WriteHeader(stream, header); } + bool WriteDelta(BitBuffer *stream, unsigned char *from, unsigned char *to, bool force, delta_t *pFields, deltacallback_t *header = nullptr) { return DELTA_WriteDelta(stream, from, to, force, pFields, header) ? true : false; } + int ParseDelta(BitBuffer *stream, unsigned char *from, unsigned char *to, delta_t *pFields) { return DELTA_ParseDelta(stream, from, to, pFields); } + void SetTime(double time) { DELTA_SetTime(time); } + void SetLargeTimeBufferSize(bool bigBuffers) { DELTA_SetLargeTimeBufferSize(bigBuffers); } + int TestDelta(unsigned char *from, unsigned char *to, delta_t *pFields) { return DELTA_TestDelta(from, to, pFields); } + delta_t **LookupRegistration(char *name) { return DELTA_LookupRegistration(name); } + void FreeDescription(delta_t **ppdesc) { DELTA_FreeDescription(ppdesc); } + delta_registry_t *GetRegistry() const { return g_deltaregistry; } +}; + +#endif // HOOK_HLTV diff --git a/rehlds/hookers/HLTV/Core/hooklist.cpp b/rehlds/hookers/HLTV/Core/hooklist.cpp new file mode 100644 index 0000000..d306a03 --- /dev/null +++ b/rehlds/hookers/HLTV/Core/hooklist.cpp @@ -0,0 +1,617 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#ifdef HOOK_HLTV + +// Hooks stuff +#include "hookers/memory.cpp" +#include "hookers/hooker.cpp" + +//#define Mem_region +//#define World_region +//#define Server_region +//#define Network_region +//#define NetSocket_region +//#define BSPModel_region +//#define Delta_region +//#define ObjectDictionary_region +//#define ObjectList_region +//#define BitBuffer_region +//#define Function_References_region +//#define Data_References_region + +FunctionHook g_FunctionHooks[] = +{ + // DO NOT DISABLE, other functions depends on memory allocation routines +#ifndef Mem_region + + HOOK_DEF(0x01D21F5F, malloc_wrapper), + HOOK_DEF(0x01D21E4E, free_wrapper), + HOOK_DEF(0x01D30145, strdup_wrapper), + HOOK_DEF(0x01D21F71, __nh_malloc_wrapper), + + HOOK_DEF(0x01D043C0, Mem_ZeroMalloc), + //HOOK_DEF(0x0, Mem_Malloc), + //HOOK_DEF(0x0, Mem_Realloc), + //HOOK_DEF(0x0, Mem_Calloc), + //HOOK_DEF(0x0, Mem_Strdup), + //HOOK_DEF(0x0, Mem_Free), + + //HOOK_DEF(0x0, realloc_wrapper), + //HOOK_DEF(0x0, calloc_wrapper), + +#endif // Mem_region + +#ifndef World_region + + // World virtual functions + HOOK_VIRTUAL_DEF(0x01D14DA0, World::Init), + HOOK_VIRTUAL_DEF(0x01D15470, World::RunFrame), + HOOK_VIRTUAL_DEF(0x01D154F0, World::ReceiveSignal), + HOOK_VIRTUAL_DEF(0x01D15490, World::ExecuteCommand), + HOOK_VIRTUAL_DEF(0x01D15500, World::RegisterListener), + HOOK_VIRTUAL_DEF(0x01D15530, World::RemoveListener), + HOOK_VIRTUAL_DEF(0x01D15570, World::GetSystem), + HOOK_VIRTUAL_DEF(0x01D15580, World::GetSerial), + HOOK_VIRTUAL_DEF(0x01D17380, World::GetStatusLine), + HOOK_VIRTUAL_DEF(0x01D17370, World::GetType), + HOOK_VIRTUAL_DEF(0x01D15590, World::GetName), + HOOK_VIRTUAL_DEF(0x01D155C0, World::GetState), + HOOK_VIRTUAL_DEF(0x01D15620, World::GetVersion), + HOOK_VIRTUAL_DEF(0x01D14F70, World::ShutDown), + HOOK_VIRTUAL_DEF(0x01D175D0, World::GetTime), + HOOK_VIRTUAL_DEF(0x01D186A0, World::GetGameServerAddress), + HOOK_VIRTUAL_DEF(0x01D186B0, World::GetLevelName), + HOOK_VIRTUAL_DEF(0x01D186F0, World::GetGameDir), + HOOK_VIRTUAL_DEF(0x01D16470, World::GetFrameByTime), + HOOK_VIRTUAL_DEF(0x01D16420, World::GetFrameBySeqNr), + HOOK_VIRTUAL_DEF(0x01D16450, World::GetLastFrame), + HOOK_VIRTUAL_DEF(0x01D16460, World::GetFirstFrame), + HOOK_VIRTUAL_DEF(0x01D18700, World::GetServerCount), + HOOK_VIRTUAL_DEF(0x01D18670, World::GetSlotNumber), + HOOK_VIRTUAL_DEF(0x01D18710, World::GetMaxClients), + HOOK_VIRTUAL_DEF(0x01D15840, World::GetNumPlayers), + HOOK_VIRTUAL_DEF(0x01D186C0, World::GetWorldModel), + HOOK_VIRTUAL_DEF(0x01D18350, World::GetServerInfoString), + HOOK_VIRTUAL_DEF(0x01D18360, World::GetPlayerInfoString), + HOOK_VIRTUAL_DEF(0x01D15450, World::GetUserMsg), + HOOK_VIRTUAL_DEF(0x01D15A60, World::GetHostName), + HOOK_VIRTUAL_DEF(0x01D189A0, World::GetServerInfo), + HOOK_VIRTUAL_DEF(0x01D15510, World::IsPlayerIndex), + HOOK_VIRTUAL_DEF(0x01D18660, World::IsVoiceEnabled), + HOOK_VIRTUAL_DEF(0x01D15870, World::IsActive), + HOOK_VIRTUAL_DEF(0x01D18190, World::IsPaused), + HOOK_VIRTUAL_DEF(0x01D181A0, World::IsComplete), + HOOK_VIRTUAL_DEF(0x01D18D20, World::IsHLTV), + HOOK_VIRTUAL_DEF(0x01D15010, World::Reset), + HOOK_VIRTUAL_DEF(0x01D158A0, World::SetServerInfoString), + HOOK_VIRTUAL_DEF(0x01D18C30, World::UpdateServerInfo), + HOOK_VIRTUAL_DEF(0x01D18150, World::SetPaused), + HOOK_VIRTUAL_DEF(0x01D15630, World::SetTime), + HOOK_VIRTUAL_DEF(0x01D181B0, World::SetBufferSize), + HOOK_VIRTUAL_DEF(0x01D18690, World::SetVoiceEnabled), + HOOK_VIRTUAL_DEF(0x01D18130, World::SetMoveVars), + HOOK_VIRTUAL_DEF(0x01D18320, World::SetCDInfo), + HOOK_VIRTUAL_DEF(0x01D18D10, World::SetHLTV), + HOOK_VIRTUAL_DEF(0x01D183B0, World::SetExtraInfo), + HOOK_VIRTUAL_DEF(0x01D18680, World::SetViewEntity), + HOOK_VIRTUAL_DEF(0x01D18340, World::SetGameServerAddress), + HOOK_VIRTUAL_DEF(0x01D15680, World::SetHostName), + HOOK_VIRTUAL_DEF(0x01D15760, World::NewGame), + HOOK_VIRTUAL_DEF(0x01D17490, World::FinishGame), + HOOK_VIRTUAL_DEF(0x01D18720, World::SaveAsDemo), + HOOK_VIRTUAL_DEF(0x01D174C0, World::StopGame), + HOOK_VIRTUAL_DEF(0x01D17560, World::FindUserMsgByName), + HOOK_VIRTUAL_DEF(0x01D181F0, World::ParseDeltaDescription), + HOOK_VIRTUAL_DEF(0x01D18420, World::ParseBaseline), + HOOK_VIRTUAL_DEF(0x01D183F0, World::ParseEvent), + HOOK_VIRTUAL_DEF(0x01D16990, World::ParseClientData), + HOOK_VIRTUAL_DEF(0x01D18070, World::SetServerInfo, void(int, CRC32_t, unsigned char *, int, int, int, char *, char *, char *)), + HOOK_VIRTUAL_DEF(0x01D17470, World::SetServerInfo, void(serverinfo_t *)), + HOOK_VIRTUAL_DEF(0x01D16740, World::GetUncompressedFrame, bool(unsigned int, frame_t *)), + HOOK_VIRTUAL_DEF(0x01D17A60, World::UncompressEntitiesFromStream, bool(frame_t *, BitBuffer *)), + HOOK_VIRTUAL_DEF(0x01D175E0, World::UncompressEntitiesFromStream, bool(frame_t *, BitBuffer *, unsigned int)), + HOOK_VIRTUAL_DEF(0x01D167F0, World::GetClientData, bool(frame_t *, clientdata_t *)), + HOOK_VIRTUAL_DEF(0x01D167B0, World::GetClientData, bool(unsigned int, clientdata_t *)), + HOOK_VIRTUAL_DEF(0x01D160A0, World::AddFrame), + HOOK_VIRTUAL_DEF(0x01D153B0, World::AddResource), + HOOK_VIRTUAL_DEF(0x01D156E0, World::AddLightStyle), + HOOK_VIRTUAL_DEF(0x01D17520, World::AddSignonData), + HOOK_VIRTUAL_DEF(0x01D15130, World::AddUserMessage), + HOOK_VIRTUAL_DEF(0x01D154A0, World::AddBaselineEntity), + HOOK_VIRTUAL_DEF(0x01D155D0, World::AddInstancedBaselineEntity), + HOOK_VIRTUAL_DEF(0x01D151F0, World::UpdatePlayer), + HOOK_VIRTUAL_DEF(0x01D164C0, World::WriteFrame), + HOOK_VIRTUAL_DEF(0x01D17CB0, World::WriteNewData), + HOOK_VIRTUAL_DEF(0x01D16030, World::WriteClientUpdate), + HOOK_VIRTUAL_DEF(0x01D15D20, World::WriteMovevars), + HOOK_VIRTUAL_DEF(0x01D174F0, World::WriteSigonData), + HOOK_VIRTUAL_DEF(0x01D15A20, World::WriteLightStyles), + HOOK_VIRTUAL_DEF(0x01D17D80, World::RemoveFrames), + HOOK_VIRTUAL_DEF(0x01D17ED0, World::DuplicateFrames), + HOOK_VIRTUAL_DEF(0x01D17EF0, World::MoveFrames), + HOOK_VIRTUAL_DEF(0x01D17F10, World::RevertFrames), + + // World non-virtual functions + HOOK_DEF(0x01D16BA0, World::CompressFrame), + HOOK_DEF(0x01D16A80, World::ParseDeltaHeader), + HOOK_DEF(0x01D150D0, World::SetMaxClients), + HOOK_DEF(0x01D17D30, World::GetBufferedGameTime), + HOOK_DEF(0x01D15800, World::ConnectionComplete), + HOOK_DEF(0x01D15F00, World::WriteResources), + HOOK_DEF(0x01D15C60, World::WriteDeltaDescriptions), + HOOK_DEF(0x01D15EB0, World::WriteRegisteredUserMessages), + HOOK_DEF(0x01D158B0, World::WriteBaseline), + HOOK_DEF(0x01D15A80, World::WriteServerinfo), + HOOK_DEF(0x01D170E0, World::WritePacketEntities), + HOOK_DEF(0x01D189B0, World::WriteDeltaEntities), + HOOK_DEF(0x01D15790, World::SetState), + HOOK_DEF(0x01D15100, World::ClearUserMessages), + HOOK_DEF(0x01D17430, World::ClearServerInfo), + HOOK_DEF(0x01D15410, World::ClearResources), + HOOK_DEF(0x01D155A0, World::ClearInstancedBaseline), + HOOK_DEF(0x01D15540, World::ClearBaseline), + HOOK_DEF(0x01D156C0, World::ClearLightStyles), + HOOK_DEF(0x01D15880, World::ClearPlayers), + HOOK_DEF(0x01D17F30, World::ClearFrames), + HOOK_DEF(0x01D16E80, World::ClearEntityCache), + HOOK_DEF(0x01D16F30, World::GetFrameFromCache), + HOOK_DEF(0x01D17010, World::GetDeltaFromCache), + HOOK_DEF(0x01D17F90, World::CheckFrameBufferSize), + HOOK_DEF(0x01D18000, World::ReorderFrameTimes), + HOOK_DEF(0x01D16D20, World::FindBestBaseline), + HOOK_DEF(0x01D18A60, World::RearrangeFrame), + HOOK_DEF(0x01D16880, World::GetUncompressedFrame, bool(frame_t *deltaFrame, frame_t *frame)), + + //HOOK_DEF(0x01D17D00, World::SetName), // NOXREF + //HOOK_DEF(0x0, World::SetDirector), // NOXREF + //HOOK_DEF(0x0, World::SetTimeScale), // NOXREF + //HOOK_DEF(0x0, World::SetGameGroupAddress), // NOXREF + //HOOK_DEF(0x0, World::GetDirector), // NOXREF + //HOOK_DEF(0x0, World::WriteCustomDecals), // NOXREF + +#endif // World_region + +#ifndef Server_region + + // IServer virtual functions + HOOK_VIRTUAL_DEF(0x01D106B0, Server::Init), + HOOK_VIRTUAL_DEF(0x01D10C10, Server::RunFrame), + HOOK_VIRTUAL_DEF(0x01D10A90, Server::ExecuteCommand), + HOOK_VIRTUAL_DEF(0x01D13870, Server::GetStatusLine), + HOOK_VIRTUAL_DEF(0x01D137F0, Server::GetType), + HOOK_VIRTUAL_DEF(0x01D10B80, Server::ShutDown), + HOOK_VIRTUAL_DEF(0x01D14220, Server::Connect), + HOOK_VIRTUAL_DEF(0x01D142F0, Server::LoadDemo), + HOOK_VIRTUAL_DEF(0x01D13E40, Server::Reconnect), + HOOK_VIRTUAL_DEF(0x01D13EA0, Server::Disconnect), + HOOK_VIRTUAL_DEF(0x01D14620, Server::Retry), + HOOK_VIRTUAL_DEF(0x01D14680, Server::StopRetry), + HOOK_VIRTUAL_DEF(0x01D14430, Server::SendStringCommand), + HOOK_VIRTUAL_DEF(0x01D14470, Server::SendHLTVCommand), + HOOK_VIRTUAL_DEF(0x01D140C0, Server::IsConnected), + HOOK_VIRTUAL_DEF(0x01D140D0, Server::IsDemoFile), + HOOK_VIRTUAL_DEF(0x01D140E0, Server::IsGameServer), + HOOK_VIRTUAL_DEF(0x01D140F0, Server::IsRelayProxy), + HOOK_VIRTUAL_DEF(0x01D11260, Server::IsVoiceBlocking), + HOOK_VIRTUAL_DEF(0x01D13A70, Server::SetProxy), + HOOK_VIRTUAL_DEF(0x01D13A90, Server::SetDirector), + HOOK_VIRTUAL_DEF(0x01D137A0, Server::SetPlayerName), + HOOK_VIRTUAL_DEF(0x01D146B0, Server::SetDelayReconnect), + HOOK_VIRTUAL_DEF(0x01D14690, Server::SetAutoRetry), + HOOK_VIRTUAL_DEF(0x01D11270, Server::SetVoiceBlocking), + HOOK_VIRTUAL_DEF(0x01D11280, Server::SetRate), + HOOK_VIRTUAL_DEF(0x01D112D0, Server::SetUpdateRate), + HOOK_VIRTUAL_DEF(0x01D14390, Server::SetUserInfo), + HOOK_VIRTUAL_DEF(0x01D13770, Server::SetProtocol), + HOOK_VIRTUAL_DEF(0x01D109C0, Server::SetGameDirectory), + HOOK_VIRTUAL_DEF(0x01D13730, Server::GetRate), + HOOK_VIRTUAL_DEF(0x01D13740, Server::GetUpdateRate), + HOOK_VIRTUAL_DEF(0x01D13720, Server::GetServerInfoString), + HOOK_VIRTUAL_DEF(0x01D137D0, Server::GetPlayerName), + + // Server virtual functions + HOOK_VIRTUAL_DEF(0x01D145A0, Server::GetTime), + HOOK_VIRTUAL_DEF(0x01D13800, Server::GetWorld), + HOOK_VIRTUAL_DEF(0x01D13830, Server::GetDemoFileName), + HOOK_VIRTUAL_DEF(0x01D13810, Server::GetAddress), + HOOK_VIRTUAL_DEF(0x01D13750, Server::GetAutoRetry), + HOOK_VIRTUAL_DEF(0x01D13850, Server::GetHostName), + HOOK_VIRTUAL_DEF(0x01D13860, Server::GetPacketLoss), + HOOK_VIRTUAL_DEF(0x01D13760, Server::GetProtocol), + + // Server non-virtual functions + HOOK_DEF(0x01D14190, Server::CheckAutoRetry), + HOOK_DEF(0x01D145B0, Server::CheckConnection), + HOOK_DEF(0x01D141F0, Server::ScheduleAutoRetry), + HOOK_DEF(0x01D11750, Server::AcceptConnection), + HOOK_DEF(0x01D116C0, Server::AcceptBadPassword), + HOOK_DEF(0x01D11700, Server::AcceptRejection), + HOOK_DEF(0x01D117D0, Server::AcceptRedirect), + HOOK_DEF(0x01D11460, Server::SendConnectPacket), + HOOK_DEF(0x01D132F0, Server::SendServerCommands), + HOOK_DEF(0x01D11320, Server::SetState), + HOOK_DEF(0x01D10AB0, Server::Challenge), + HOOK_DEF(0x01D146C0, Server::Reset), + HOOK_DEF(0x01D11170, Server::AcceptChallenge), + HOOK_DEF(0x01D14050, Server::SendUserVar), + HOOK_DEF(0x01D10F70, Server::ProcessMessage), + HOOK_DEF(0x01D147B0, Server::ProcessEntityUpdate), + HOOK_DEF(0x01D10DA0, Server::ProcessConnectionlessMessage), + HOOK_DEF(0x01D12EF0, Server::ClearFrame), + HOOK_DEF(0x01D139E0, Server::ParseHLTV), + HOOK_DEF(0x01D13AA0, Server::ParseDirector), + HOOK_DEF(0x01D12CA0, Server::ParseFileTransferFailed), + HOOK_DEF(0x01D13B80, Server::ParseInfo), + HOOK_DEF(0x01D136E0, Server::ParseParticle), + HOOK_DEF(0x01D136B0, Server::ParseRoomType), + HOOK_DEF(0x01D13610, Server::ParseSpawnStaticSound), + HOOK_DEF(0x01D13580, Server::ParseEventReliable), + HOOK_DEF(0x01D13510, Server::ParsePings), + HOOK_DEF(0x01D12CE0, Server::ParseSignonNum), + HOOK_DEF(0x01D12FB0, Server::ParseUserMessage), + HOOK_DEF(0x01D134E0, Server::ParseStopSound), + HOOK_DEF(0x01D13410, Server::ParseEvent), + HOOK_DEF(0x01D13340, Server::ParseSound), + HOOK_DEF(0x01D13240, Server::ParseDeltaPacketEntities), + HOOK_DEF(0x01D131A0, Server::ParsePacketEntities), + HOOK_DEF(0x01D12DF0, Server::ParseCustomization), + HOOK_DEF(0x01D12010, Server::ParseCrosshairAngle), + HOOK_DEF(0x01D12050, Server::ParseSoundFade), + HOOK_DEF(0x01D12C10, Server::ParseDisconnect), + HOOK_DEF(0x01D12C00, Server::ParseChoke), + HOOK_DEF(0x01D12AC0, Server::ParseSetAngle), + HOOK_DEF(0x01D12B60, Server::ParseAddAngle), + HOOK_DEF(0x01D12A40, Server::ParseLightStyle), + HOOK_DEF(0x01D12A20, Server::ParseTime), + HOOK_DEF(0x01D129F0, Server::ParseVersion), + HOOK_DEF(0x01D129D0, Server::ParseBaseline), + HOOK_DEF(0x01D12860, Server::ParseTempEntity), + HOOK_DEF(0x01D12650, Server::ParseResourceList), + HOOK_DEF(0x01D12590, Server::ParseUpdateUserInfo), + HOOK_DEF(0x01D12150, Server::ParseStuffText), + HOOK_DEF(0x01D120C0, Server::ParseNewUserMsg), + HOOK_DEF(0x01D11F80, Server::ParseResourceRequest), + HOOK_DEF(0x01D11F00, Server::ParseSetView), + HOOK_DEF(0x01D11E90, Server::ParseCDTrack), + HOOK_DEF(0x01D11EC0, Server::ParseRestore), + HOOK_DEF(0x01D11CC0, Server::ParseMoveVars), + HOOK_DEF(0x01D11C60, Server::ParseDeltaDescription), + HOOK_DEF(0x01D119F0, Server::ParseServerinfo), + HOOK_DEF(0x01D119D0, Server::ParseBad), + HOOK_DEF(0x01D119C0, Server::ParseNop), + HOOK_DEF(0x01D11850, Server::ParsePrint), + HOOK_DEF(0x01D11880, Server::ParseVoiceInit), + HOOK_DEF(0x01D11940, Server::ParseVoiceData), + HOOK_DEF(0x01D144F0, Server::ParseTimeScale), + HOOK_DEF(0x01D144C0, Server::ParseSendExtraInfo), + HOOK_DEF(0x01D14100, Server::ParseCenterPrint), + HOOK_DEF(0x01D143D0, Server::ParseSetPause), + HOOK_DEF(0x01D14020, Server::ParseCutscene), + HOOK_DEF(0x01D12140, Server::ParseWeaponAnim), + HOOK_DEF(0x01D11C80, Server::ParseDecalName), + HOOK_DEF(0x01D13FF0, Server::ParseFinale), + HOOK_DEF(0x01D13FC0, Server::ParseIntermission), + HOOK_DEF(0x01D13F50, Server::ParseClientData), + HOOK_DEF(0x01D14570, Server::ParseResourceLocation), + HOOK_DEF(0x01D14820, Server::ParseSendCvarValue), + HOOK_DEF(0x01D14830, Server::ParseSendCvarValue2), + //HOOK_DEF(0x01D14740, Server::GetCmdName), // NOXREF + +#endif // Server_region + +#ifndef Network_region + + // Network virtual functions + HOOK_VIRTUAL_DEF(0x01D0E040, Network::Init), + HOOK_VIRTUAL_DEF(0x01D0E480, Network::RunFrame), + HOOK_VIRTUAL_DEF(0x01D0E5B0, Network::ReceiveSignal), + HOOK_VIRTUAL_DEF(0x01D0E210, Network::ExecuteCommand), + HOOK_VIRTUAL_DEF(0x01D0E5C0, Network::RegisterListener), + HOOK_VIRTUAL_DEF(0x01D0E670, Network::RemoveListener), + HOOK_VIRTUAL_DEF(0x01D0E680, Network::GetSystem), + HOOK_VIRTUAL_DEF(0x01D0E690, Network::GetSerial), + HOOK_VIRTUAL_DEF(0x01D0E4D0, Network::GetStatusLine), + HOOK_VIRTUAL_DEF(0x01D0E3B0, Network::GetType), + HOOK_VIRTUAL_DEF(0x01D0E6B0, Network::GetName), + HOOK_VIRTUAL_DEF(0x01D0E810, Network::GetState), + HOOK_VIRTUAL_DEF(0x01D0E820, Network::GetVersion), + HOOK_VIRTUAL_DEF(0x01D0E250, Network::ShutDown), + HOOK_VIRTUAL_DEF(0x01D0E2E0, Network::CreateSocket), + HOOK_VIRTUAL_DEF(0x01D0E3A0, Network::RemoveSocket), + HOOK_VIRTUAL_DEF(0x01D0E4C0, Network::GetLocalAddress), + HOOK_VIRTUAL_DEF(0x01D0E6C0, Network::ResolveAddress), + HOOK_VIRTUAL_DEF(0x01D0E530, Network::GetFlowStats), + HOOK_VIRTUAL_DEF(0x01D0E6A0, Network::GetLastErrorCode), + HOOK_VIRTUAL_DEF(0x01D0E830, Network::GetErrorText), + HOOK_VIRTUAL_DEF(0x01D0E2E0, Network::CreateSocket), + HOOK_VIRTUAL_DEF(0x01D0E3A0, Network::RemoveSocket), + HOOK_VIRTUAL_DEF(0x01D0E4C0, Network::GetLocalAddress), + HOOK_VIRTUAL_DEF(0x01D0E6C0, Network::ResolveAddress), + HOOK_VIRTUAL_DEF(0x01D0E530, Network::GetFlowStats), + HOOK_VIRTUAL_DEF(0x01D0E6A0, Network::GetLastErrorCode), + HOOK_VIRTUAL_DEF(0x01D0E830, Network::GetErrorText), + + // Network non-virtual functions + HOOK_DEF(0x01D0EAE0, Network::UpdateStats), + HOOK_DEF(0x01D0E440, Network::GetSocket), + HOOK_DEF(0x01D0E400, Network::SendData), + HOOK_DEF(0x01D0E3C0, Network::ReceiveData), + +#endif // Network_region + +#ifndef NetSocket_region + + // Network virtual functions + HOOK_VIRTUAL_DEF(0x01D0D940, NetSocket::ReceivePacket), + HOOK_VIRTUAL_DEF(0x01D0D950, NetSocket::FreePacket), + HOOK_VIRTUAL_DEF(0x01D0D980, NetSocket::AddPacket), + HOOK_VIRTUAL_DEF(0x01D0D000, NetSocket::AddChannel), + HOOK_VIRTUAL_DEF(0x01D0D010, NetSocket::RemoveChannel), + HOOK_VIRTUAL_DEF(0x01D0D310, NetSocket::GetNetwork), + HOOK_VIRTUAL_DEF(0x01D0D8D0, NetSocket::OutOfBandPrintf), + HOOK_VIRTUAL_DEF(0x01D0DA30, NetSocket::Flush), + HOOK_VIRTUAL_DEF(0x01D0D8A0, NetSocket::GetFlowStats), + HOOK_VIRTUAL_DEF(0x01D0D610, NetSocket::LeaveGroup), + HOOK_VIRTUAL_DEF(0x01D0D570, NetSocket::JoinGroup), + HOOK_VIRTUAL_DEF(0x01D0D500, NetSocket::Close), + HOOK_VIRTUAL_DEF(0x01D0DCB0, NetSocket::GetPort), + + HOOK_VIRTUAL_DEF(0x01D0D160, NetSocket::SendPacket, bool(NetPacket *)), + HOOK_VIRTUAL_DEF(0x01D0D190, NetSocket::SendPacket, bool(NetAddress *, const void *, int)), + + // Network non-virtual functions + HOOK_DEF(0x01D0DAC0, NetSocket::Create), + HOOK_DEF(0x01D0DCC0, NetSocket::UpdateStats), + HOOK_DEF(0x01D0D6B0, NetSocket::DrainChannels), + HOOK_DEF(0x01D0D020, NetSocket::DispatchIncoming), + HOOK_DEF(0x01D0D330, NetSocket::ReceivePacketIntern), + HOOK_DEF(0x01D0DD50, NetSocket::SendLong), + HOOK_DEF(0x01D0DE70, NetSocket::SendShort), + HOOK_DEF(0x01D0D730, NetSocket::GetLong), + +#endif // NetSocket_region + +#ifndef Delta_region + + HOOK_DEF(0x01D06740, DELTA_Init), + HOOK_DEF(0x01D06810, DELTA_UpdateDescriptions), + HOOK_DEF(0x01D06880, DELTA_Shutdown), + HOOK_DEF(0x01D06890, DELTA_SetTime), + HOOK_DEF(0x01D068B0, DELTA_SetLargeTimeBufferSize), + HOOK_DEF(0x01D04AF0, DELTA_FindField), + HOOK_DEF(0x01D04C10, DELTA_ClearFlags), + HOOK_DEF(0x01D04C40, DELTA_CountSendFields), + HOOK_DEF(0x01D04C80, DELTA_MarkSendFields), + HOOK_DEF(0x01D04E80, DELTA_SetSendFlagBits), + HOOK_DEF(0x01D04EF0, DELTA_WriteMarkedFields), + HOOK_DEF(0x01D052A0, DELTA_WriteHeader), + HOOK_DEF(0x01D053C0, DELTA_WriteDelta), + HOOK_DEF(0x01D05470, DELTA_ParseDelta), + HOOK_DEF(0x01D05A30, DELTA_TestDelta), + HOOK_DEF(0x01D05CA0, DELTA_AddEncoder), + HOOK_DEF(0x01D05CE0, DELTA_ClearEncoders), + HOOK_DEF(0x01D05D60, DELTA_CountLinks), + HOOK_DEF(0x01D05D80, DELTA_ReverseLinks), + HOOK_DEF(0x01D05DA0, DELTA_ClearLinks), + HOOK_DEF(0x01D05DD0, DELTA_BuildFromLinks), + HOOK_DEF(0x01D05E80, DELTA_FindOffset), + HOOK_DEF(0x01D05EC0, DELTA_ParseType), + HOOK_DEF(0x01D06050, DELTA_ParseField), + HOOK_DEF(0x01D06200, DELTA_FreeDescription), + HOOK_DEF(0x01D06240, DELTA_AddDefinition), + HOOK_DEF(0x01D062A0, DELTA_ClearDefinitions), + HOOK_DEF(0x01D062E0, DELTA_FindDefinition), + HOOK_DEF(0x01D06330, DELTA_SkipDescription), + HOOK_DEF(0x01D06380, DELTA_ParseOneField), + HOOK_DEF(0x01D06640, DELTA_RegisterDescription), + HOOK_DEF(0x01D06670, DELTA_ClearRegistrations), + HOOK_DEF(0x01D066C0, DELTA_LookupRegistration), + + //HOOK_DEF(0x01D06700, DELTA_ClearStats), // NOXREF + //HOOK_DEF(0x01D06430, DELTA_ParseDescription), // NOXREF + //HOOK_DEF(0x01D06630, DELTA_Load), // NOXREF + //HOOK_DEF(0x01D04B40, DELTA_FindFieldIndex), // NOXREF + //HOOK_DEF(0x01D04B90, DELTA_SetField), // NOXREF + //HOOK_DEF(0x01D04BB0, DELTA_UnsetField), // NOXREF + //HOOK_DEF(0x01D04BD0, DELTA_SetFieldByIndex), // NOXREF + //HOOK_DEF(0x01D04BF0, DELTA_UnsetFieldByIndex), // NOXREF + //HOOK_DEF(0x01D05270, DELTA_CheckDelta), // NOXREF + //HOOK_DEF(0x01D05D20, DELTA_LookupEncoder), // NOXREF + +#endif // Delta_region + +#ifndef ObjectDictionary_region + + HOOK_DEF(0x01D0ECA0, MethodThunk::Constructor), + HOOK_DEF(0x01D0ECE0, MethodThunk::Destructor), + + HOOK_VIRTUAL_DEF(0x01D0F220, ObjectDictionary::Init, void()), + HOOK_VIRTUAL_DEF(0x01D0F290, ObjectDictionary::Add, bool(void *)), + HOOK_VIRTUAL_DEF(0x01D0F050, ObjectDictionary::Remove), + HOOK_VIRTUAL_DEF(0x01D0ED10, ObjectDictionary::Clear), + HOOK_VIRTUAL_DEF(0x01D0F310, ObjectDictionary::GetFirst), + HOOK_VIRTUAL_DEF(0x01D0F5B0, ObjectDictionary::GetNext), + HOOK_VIRTUAL_DEF(0x01D0F2A0, ObjectDictionary::CountElements), + HOOK_VIRTUAL_DEF(0x01D0F2C0, ObjectDictionary::Contains), + HOOK_VIRTUAL_DEF(0x01D0F2B0, ObjectDictionary::IsEmpty), + + HOOK_DEF(0x01D0F250, ObjectDictionary::Init, void(int)), // NOXREF + HOOK_DEF(0x01D0ED90, ObjectDictionary::Add, bool(void *, float)), + HOOK_DEF(0x01D0F4D0, ObjectDictionary::AddToCache, void(ObjectDictionary::entry_t *, float)), + HOOK_DEF(0x01D0F490, ObjectDictionary::AddToCache, void(ObjectDictionary::entry_t *)), + HOOK_DEF(0x01D0F340, ObjectDictionary::ChangeKey), + HOOK_DEF(0x01D0F0D0, ObjectDictionary::RemoveKey), + HOOK_DEF(0x01D0F590, ObjectDictionary::FindClosestKey), + HOOK_DEF(0x01D0F5D0, ObjectDictionary::FindExactKey), + HOOK_DEF(0x01D0F320, ObjectDictionary::GetLast), + HOOK_DEF(0x01D0F510, ObjectDictionary::FindKeyInCache), + HOOK_DEF(0x01D0F550, ObjectDictionary::FindObjectInCache), + HOOK_DEF(0x01D0EF60, ObjectDictionary::ClearCache), + HOOK_DEF(0x01D0F130, ObjectDictionary::CheckSize), + HOOK_DEF(0x01D0EF80, ObjectDictionary::RemoveIndex), + HOOK_DEF(0x01D0F010, ObjectDictionary::RemoveIndexRange), + HOOK_DEF(0x01D0EE60, ObjectDictionary::FindClosestAsIndex), + //HOOK_DEF(0x0, ObjectDictionary::RemoveRange), // NOXREF + //HOOK_DEF(0x01D0F440, ObjectDictionary::UnsafeChangeKey), // NOXREF + //HOOK_DEF(0x01D0F090, ObjectDictionary::RemoveSingle), // NOXREF + +#endif // ObjectDictionary_region + +#ifndef ObjectList_region + + HOOK_DEF(0x01D0F610, MethodThunk::Constructor), + HOOK_DEF(0x01D0F650, MethodThunk::Destructor), + + HOOK_VIRTUAL_DEF(0x01D0F8D0, ObjectList::Init), + HOOK_VIRTUAL_DEF(0x01D0F920, ObjectList::Add), + HOOK_VIRTUAL_DEF(0x01D0F850, ObjectList::Remove), + HOOK_VIRTUAL_DEF(0x01D0F800, ObjectList::Clear), + HOOK_VIRTUAL_DEF(0x01D0F8E0, ObjectList::GetFirst), + HOOK_VIRTUAL_DEF(0x01D0F900, ObjectList::GetNext), + HOOK_VIRTUAL_DEF(0x01D0F7C0, ObjectList::CountElements), + HOOK_VIRTUAL_DEF(0x01D0F7D0, ObjectList::Contains), + HOOK_VIRTUAL_DEF(0x01D0F7B0, ObjectList::IsEmpty), + + HOOK_DEF(0x01D0F760, ObjectList::RemoveTail), + HOOK_DEF(0x01D0F6C0, ObjectList::RemoveHead), + HOOK_DEF(0x01D0F710, ObjectList::AddTail), + HOOK_DEF(0x01D0F670, ObjectList::AddHead), + +#endif // ObjectList_region + +#ifndef BitBuffer_region + + HOOK_DEF(0x01D015A0, MethodThunk::Destructor), + HOOK_DEF(0x01D01530, (MethodThunk::Constructor), void()), + HOOK_DEF(0x01D015B0, (MethodThunk::Constructor), void(unsigned int)), + HOOK_DEF(0x01D01570, (MethodThunk::Constructor), void(void *, unsigned int)), + + HOOK_DEF(0x01D015E0, BitBuffer::Resize), + HOOK_DEF(0x01D01630, BitBuffer::Clear), + HOOK_DEF(0x01D01670, BitBuffer::Reset), + HOOK_DEF(0x01D01690, BitBuffer::Free), + HOOK_DEF(0x01D01840, BitBuffer::PeekBits), + HOOK_DEF(0x01D01EF0, BitBuffer::CurrentSize), + HOOK_DEF(0x01D02300, BitBuffer::FastClear), + HOOK_DEF(0x01D02350, BitBuffer::ConcatBuffer), + HOOK_DEF(0x01D02210, BitBuffer::SkipBytes), + HOOK_DEF(0x01D01660, BitBuffer::CurrentBit), + HOOK_DEF(0x01D01F10, BitBuffer::SpaceLeft), + HOOK_DEF(0x01D01F20, BitBuffer::AlignByte), + HOOK_DEF(0x01D02090, BitBuffer::StartBitMode), + HOOK_DEF(0x01D020A0, BitBuffer::EndBitMode), + HOOK_DEF(0x01D020E0, BitBuffer::SetBuffer), + HOOK_DEF(0x01D02240, BitBuffer::SkipBits), + HOOK_DEF(0x01D022D0, BitBuffer::SkipString), + + // Read + HOOK_DEF(0x01D016D0, BitBuffer::ReadBits), + HOOK_DEF(0x01D017B0, BitBuffer::ReadBit), + HOOK_DEF(0x01D01870, BitBuffer::ReadChar), + HOOK_DEF(0x01D01880, BitBuffer::ReadByte), + HOOK_DEF(0x01D01890, BitBuffer::ReadShort), + HOOK_DEF(0x01D018A0, BitBuffer::ReadWord), + HOOK_DEF(0x01D018B0, BitBuffer::ReadLong), + HOOK_DEF(0x01D018C0, BitBuffer::ReadFloat), + HOOK_DEF(0x01D018E0, BitBuffer::ReadBuf), + HOOK_DEF(0x01D019C0, BitBuffer::ReadString), + HOOK_DEF(0x01D01A00, BitBuffer::ReadStringLine), // NOXREF + HOOK_DEF(0x01D02020, BitBuffer::ReadBitString), + HOOK_DEF(0x01D020B0, BitBuffer::ReadBitData), + HOOK_DEF(0x01D02110, BitBuffer::ReadBitVec3Coord), + HOOK_DEF(0x01D02170, BitBuffer::ReadBitCoord), + HOOK_DEF(0x01D021F0, BitBuffer::ReadCoord), + HOOK_DEF(0x01D01A40, BitBuffer::ReadAngle), // NOXREF + HOOK_DEF(0x01D01A60, BitBuffer::ReadHiresAngle), // NOXREF + HOOK_DEF(0x01D01F40, BitBuffer::ReadSBits), + HOOK_DEF(0x01D01F70, BitBuffer::ReadBitAngle), + + // Write + HOOK_DEF(0x01D01D90, BitBuffer::WriteBuf, void(const void *, int)), + HOOK_DEF(0x01D01990, BitBuffer::WriteBuf, void(BitBuffer *, int)), + + HOOK_DEF(0x01D01A80, BitBuffer::WriteBit), + HOOK_DEF(0x01D01B50, BitBuffer::WriteBits), + HOOK_DEF(0x01D01C70, BitBuffer::WriteSBits), + HOOK_DEF(0x01D01CD0, BitBuffer::WriteChar), + HOOK_DEF(0x01D01CE0, BitBuffer::WriteByte), + HOOK_DEF(0x01D01CF0, BitBuffer::WriteShort), + HOOK_DEF(0x01D01D00, BitBuffer::WriteWord), + HOOK_DEF(0x01D01D10, BitBuffer::WriteLong), + HOOK_DEF(0x01D01D20, BitBuffer::WriteFloat), + HOOK_DEF(0x01D01D50, BitBuffer::WriteString), + HOOK_DEF(0x01D02370, BitBuffer::WriteCoord), + HOOK_DEF(0x01D01E60, BitBuffer::WriteBitData), + HOOK_DEF(0x01D01E90, BitBuffer::WriteAngle), // NOXREF + HOOK_DEF(0x01D01EC0, BitBuffer::WriteHiresAngle), // NOXREF + HOOK_DEF(0x01D01FB0, BitBuffer::WriteBitAngle), + HOOK_DEF(0x01D02050, BitBuffer::WriteBitString), + +#endif // BitBuffer_region + + { NULL, NULL, NULL }, +}; + +AddressRef g_FunctionRefs[] = +{ +#ifndef Function_References_region + +#endif // Function_References_region + + { NULL, NULL, NULL }, +}; + +AddressRef g_DataRefs[] = +{ +#ifndef Data_References_region + + GLOBALVAR_LINK(0x01D45708, "_ZL6g_defs", pg_defs), + GLOBALVAR_LINK(0x01D4570C, "_ZL10g_encoders", pg_encoders), + GLOBALVAR_LINK(0x01D45710, "g_deltaregistry", pg_deltaregistry), + GLOBALVAR_LINK(0x01D456F0, "g_pplayerdelta", pg_pplayerdelta), + GLOBALVAR_LINK(0x01D456F4, "g_pentitydelta", pg_pentitydelta), + GLOBALVAR_LINK(0x01D456F8, "g_pcustomentitydelta", pg_pcustomentitydelta), + GLOBALVAR_LINK(0x01D456FC, "g_pclientdelta", pg_pclientdelta), + GLOBALVAR_LINK(0x01D45700, "g_pweapondelta", pg_pweapondelta), + GLOBALVAR_LINK(0x01D45704, "g_peventdelta", pg_peventdelta), + GLOBALVAR_LINK(0x01D456E8, "g_delta_Time", pg_delta_Time), + GLOBALVAR_LINK(0x01D456E0, "g_large_Time_Buffers", pg_large_Time_Buffers), + GLOBALVAR_LINK(0x01D46870, "g_DownloadURL", pg_DownloadURL), + + GLOBALVAR_LINK(0x01D442C8, "com_token", pcom_token), + GLOBALVAR_LINK(0x01D456C8, "s_com_token_unget", ps_com_token_unget), + +#endif // Data_References_region + + { NULL, NULL, NULL }, +}; + +#endif // HOOK_HLTV diff --git a/rehlds/hookers/HLTV/Core/hooklist.h b/rehlds/hookers/HLTV/Core/hooklist.h new file mode 100644 index 0000000..fcdf32b --- /dev/null +++ b/rehlds/hookers/HLTV/Core/hooklist.h @@ -0,0 +1,18 @@ +#pragma once + +#ifdef HOOK_HLTV + +#include "hookers/memory.h" +#include "hookers/helper.h" +#include "hookers/hooker.h" + +#define rehlds_syserror HLTV_SysError + +#define com_token (*pcom_token) +#define s_com_token_unget (*ps_com_token_unget) +#define g_DownloadURL (*pg_DownloadURL) + +extern char com_token[COM_TOKEN_LEN]; +extern qboolean s_com_token_unget; + +#endif // HOOK_HLTV diff --git a/rehlds/hookers/HLTV/Core/main.cpp b/rehlds/hookers/HLTV/Core/main.cpp new file mode 100644 index 0000000..7c4b3a8 --- /dev/null +++ b/rehlds/hookers/HLTV/Core/main.cpp @@ -0,0 +1,102 @@ +#include "precompiled.h" + +#if defined(HOOK_HLTV) +#define ORIGINAL_CORE_DLL_NAME "core2.dll" + +CSysModule *g_pOriginalCoreModule = NULL; +CreateInterfaceFn g_OriginalCoreFactory = NULL; +ISystemModule *g_pOriginalServer = NULL; +ISystemModule *g_pOriginalWorld = NULL; +ISystemModule *g_pOriginalNetwork = NULL; + +IBaseInterface *CreateCoreInterface() +{ + if (g_pOriginalServer) { + return g_pOriginalServer; + } + + if (g_pOriginalCoreModule) + { + g_OriginalCoreFactory = Sys_GetFactory(g_pOriginalCoreModule); + if (g_OriginalCoreFactory) + { + int returnCode = 0; + g_pOriginalServer = reinterpret_cast(g_OriginalCoreFactory(SERVER_INTERFACE_VERSION, &returnCode)); + return g_pOriginalServer; + } + } + + return NULL; +} + +IBaseInterface *CreateWorldInterface() +{ + if (g_pOriginalWorld) { + return g_pOriginalWorld; + } + + if (g_pOriginalCoreModule) + { + g_OriginalCoreFactory = Sys_GetFactory(g_pOriginalCoreModule); + if (g_OriginalCoreFactory) + { + int returnCode = 0; + g_pOriginalWorld = reinterpret_cast(g_OriginalCoreFactory(WORLD_INTERFACE_VERSION, &returnCode)); + return g_pOriginalWorld; + } + } + + return NULL; +} + +IBaseInterface *CreateNetworkInterface() +{ + if (g_pOriginalNetwork) { + return g_pOriginalNetwork; + } + + if (g_pOriginalCoreModule) + { + g_OriginalCoreFactory = Sys_GetFactory(g_pOriginalCoreModule); + if (g_OriginalCoreFactory) + { + int returnCode = 0; + g_pOriginalNetwork = reinterpret_cast(g_OriginalCoreFactory(NETWORK_INTERFACE_VERSION, &returnCode)); + return g_pOriginalNetwork; + } + } + + return NULL; +} + +InterfaceReg iface_Server = InterfaceReg(CreateCoreInterface, SERVER_INTERFACE_VERSION); +InterfaceReg iface_World = InterfaceReg(CreateWorldInterface, WORLD_INTERFACE_VERSION); +InterfaceReg iface_Network= InterfaceReg(CreateNetworkInterface, NETWORK_INTERFACE_VERSION); + +// DLL entry point +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + g_pOriginalCoreModule = Sys_LoadModule(ORIGINAL_CORE_DLL_NAME); + size_t addr = (size_t)Sys_GetProcAddress(ORIGINAL_CORE_DLL_NAME, CREATEINTERFACE_PROCNAME); + HookModule("hltv.exe", addr); + } + else if (fdwReason == DLL_PROCESS_DETACH) + { + if (g_pOriginalCoreModule) + { + Sys_UnloadModule(g_pOriginalCoreModule); + g_pOriginalCoreModule = NULL; + g_OriginalCoreFactory = NULL; + + g_pOriginalServer = NULL; + g_pOriginalWorld = NULL; + g_pOriginalNetwork = NULL; + } + } + + return TRUE; +} + +#endif // #if defined(HOOK_HLTV) diff --git a/rehlds/hookers/HLTV/DemoPlayer/hooklist.cpp b/rehlds/hookers/HLTV/DemoPlayer/hooklist.cpp new file mode 100644 index 0000000..ad0011e --- /dev/null +++ b/rehlds/hookers/HLTV/DemoPlayer/hooklist.cpp @@ -0,0 +1,152 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +// Hooks stuff +#include "hookers/memory.cpp" +#include "hookers/hooker.cpp" + +//#define Mem_region +//#define Function_References_region +//#define Data_References_region + +FunctionHook g_FunctionHooks[] = +{ + // DO NOT DISABLE, other functions depends on memory allocation routines +#ifndef Mem_region + + HOOK_DEF(0x01D07C0F, malloc_wrapper), + HOOK_DEF(0x01D07AFE, free_wrapper), + HOOK_DEF(0x01D14F4D, strdup_wrapper), + HOOK_DEF(0x01D07C21, __nh_malloc_wrapper), + + HOOK_DEF(0x01D02510, Mem_ZeroMalloc), + //HOOK_DEF(0x0, Mem_Malloc), + //HOOK_DEF(0x0, Mem_Realloc), + //HOOK_DEF(0x0, Mem_Calloc), + //HOOK_DEF(0x0, Mem_Strdup), + //HOOK_DEF(0x0, Mem_Free), + + //HOOK_DEF(0x0, realloc_wrapper), + //HOOK_DEF(0x0, calloc_wrapper), + +#endif // Mem_region + +#ifndef DemoPlayer_Region + + // BaseSystemModule virtual function + //HOOK_VIRTUAL_DEF(0x01D032A0, DemoPlayer::RegisterListener), + //HOOK_VIRTUAL_DEF(0x01D03360, DemoPlayer::RemoveListener), + //HOOK_VIRTUAL_DEF(0x1D033700, DemoPlayer::GetSystem), + //HOOK_VIRTUAL_DEF(0x01D03380, DemoPlayer::GetSerial), + //HOOK_VIRTUAL_DEF(0x01D03390, DemoPlayer::GetName), + //HOOK_VIRTUAL_DEF(0x01D033A0, DemoPlayer::GetState), + //HOOK_VIRTUAL_DEF(0x01D033F0, DemoPlayer::GetVersion), + + // DemoPlayer virtual function + HOOK_VIRTUAL_DEF(0x01D03670, DemoPlayer::Init), + HOOK_VIRTUAL_DEF(0x01D04180, DemoPlayer::RunFrame), + HOOK_VIRTUAL_DEF(0x01D042E0, DemoPlayer::ReceiveSignal), + HOOK_VIRTUAL_DEF(0x01D02FA0, DemoPlayer::ExecuteCommand), + HOOK_VIRTUAL_DEF(0x01D02F70, DemoPlayer::GetStatusLine), + HOOK_VIRTUAL_DEF(0x01D02F60, DemoPlayer::GetType), + HOOK_VIRTUAL_DEF(0x01D04490, DemoPlayer::ShutDown), + HOOK_VIRTUAL_DEF(0x01D04400, DemoPlayer::NewGame), + HOOK_VIRTUAL_DEF(0x01D03410, DemoPlayer::GetModName), + HOOK_VIRTUAL_DEF(0x01D03420, DemoPlayer::WriteCommands), + HOOK_VIRTUAL_DEF(0x01D03570, DemoPlayer::AddCommand), + HOOK_VIRTUAL_DEF(0x01D035F0, DemoPlayer::RemoveCommand), + HOOK_VIRTUAL_DEF(0x01D04640, DemoPlayer::GetLastCommand), + HOOK_VIRTUAL_DEF(0x01D03660, DemoPlayer::GetCommands), + HOOK_VIRTUAL_DEF(0x01D03900, DemoPlayer::SetWorldTime), + HOOK_VIRTUAL_DEF(0x01D03940, DemoPlayer::SetTimeScale), + HOOK_VIRTUAL_DEF(0x01D039B0, DemoPlayer::SetPaused), + HOOK_VIRTUAL_DEF(0x01D039C0, DemoPlayer::SetEditMode), + HOOK_VIRTUAL_DEF(0x01D03A20, DemoPlayer::SetMasterMode), + HOOK_VIRTUAL_DEF(0x01D03A40, DemoPlayer::IsPaused), + HOOK_VIRTUAL_DEF(0x01D02F30, DemoPlayer::IsLoading), + HOOK_VIRTUAL_DEF(0x01D02F50, DemoPlayer::IsActive), + HOOK_VIRTUAL_DEF(0x01D039D0, DemoPlayer::IsEditMode), + HOOK_VIRTUAL_DEF(0x01D03A30, DemoPlayer::IsMasterMode), + HOOK_VIRTUAL_DEF(0x01D04560, DemoPlayer::RemoveFrames), + HOOK_VIRTUAL_DEF(0x01D04570, DemoPlayer::ExecuteDirectorCmd), + HOOK_VIRTUAL_DEF(0x01D02ED0, DemoPlayer::GetWorldTime), + HOOK_VIRTUAL_DEF(0x01D02EE0, DemoPlayer::GetStartTime), + HOOK_VIRTUAL_DEF(0x01D02F00, DemoPlayer::GetEndTime), + HOOK_VIRTUAL_DEF(0x01D03400, DemoPlayer::GetTimeScale), + HOOK_VIRTUAL_DEF(0x01D02F80, DemoPlayer::GetWorld), + HOOK_VIRTUAL_DEF(0x01D04630, DemoPlayer::GetFileName), + HOOK_VIRTUAL_DEF(0x01D02E60, DemoPlayer::SaveGame), + HOOK_VIRTUAL_DEF(0x01D04650, DemoPlayer::LoadGame), + HOOK_VIRTUAL_DEF(0x01D039E0, DemoPlayer::Stop), + HOOK_VIRTUAL_DEF(0x01D03A10, DemoPlayer::ForceHLTV), + HOOK_VIRTUAL_DEF(0x01D03A50, DemoPlayer::GetDemoViewInfo), + HOOK_VIRTUAL_DEF(0x01D03F90, DemoPlayer::ReadDemoMessage), + HOOK_VIRTUAL_DEF(0x01D04130, DemoPlayer::ReadNetchanState), + HOOK_VIRTUAL_DEF(0x01D02F90, DemoPlayer::GetDirector), // NOXREF + + // DemoPlayer non-virtual function + //HOOK_DEF(0x01D02F20, DemoPlayer::GetPlayerTime), // NOXREF + //HOOK_DEF(0x01D04500, DemoPlayer::FormatTime), // NOXREF + HOOK_DEF(0x01D041B0, DemoPlayer::RunClocks), + HOOK_DEF(0x01D046F0, DemoPlayer::WriteDatagram), + HOOK_DEF(0x01D03D30, DemoPlayer::WriteSpawn), + HOOK_DEF(0x01D03F50, DemoPlayer::ReindexCommands), + HOOK_DEF(0x01D03DC0, DemoPlayer::WriteCameraPath), + HOOK_DEF(0x01D04840, DemoPlayer::ExecuteDemoFileCommands), + HOOK_DEF(0x01D03030, DemoPlayer::CMD_Jump), + HOOK_DEF(0x01D030E0, DemoPlayer::CMD_ForceHLTV), + HOOK_DEF(0x01D031F0, DemoPlayer::CMD_Pause), + HOOK_DEF(0x01D032B0, DemoPlayer::CMD_Speed), + HOOK_DEF(0x01D033B0, DemoPlayer::CMD_Start), + HOOK_DEF(0x01D03170, DemoPlayer::CMD_Save), + +#endif // DemoPlayer_Region + + { NULL, NULL, NULL }, +}; + +AddressRef g_FunctionRefs[] = +{ +#ifndef Function_References_region + +#endif // Function_References_region + + { NULL, NULL, NULL }, +}; + +AddressRef g_DataRefs[] = +{ +#ifndef Data_References_region + + +#endif // Data_References_region + + { NULL, NULL, NULL }, +}; diff --git a/rehlds/hookers/HLTV/DemoPlayer/hooklist.h b/rehlds/hookers/HLTV/DemoPlayer/hooklist.h new file mode 100644 index 0000000..d030ec9 --- /dev/null +++ b/rehlds/hookers/HLTV/DemoPlayer/hooklist.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef HOOK_HLTV + +#include "hookers/memory.h" +#include "hookers/helper.h" +#include "hookers/hooker.h" + +#define rehlds_syserror HLTV_SysError + +#endif // HOOK_HLTV diff --git a/rehlds/hookers/HLTV/DemoPlayer/main.cpp b/rehlds/hookers/HLTV/DemoPlayer/main.cpp new file mode 100644 index 0000000..0837c3c --- /dev/null +++ b/rehlds/hookers/HLTV/DemoPlayer/main.cpp @@ -0,0 +1,55 @@ +#include "precompiled.h" + +#if defined(HOOK_HLTV) +#define ORIGINAL_DEMOPLAYER_DLL_NAME "DemoPlayer2.dll" + +CSysModule *g_pOriginalDemoPlayerModule = NULL; +CreateInterfaceFn g_OriginalDemoPlayerFactory = NULL; +ISystemModule *g_pOriginalDemoPlayer = NULL; + +IBaseInterface *CreateDemoPlayerInterface() +{ + if (g_pOriginalDemoPlayer) { + return g_pOriginalDemoPlayer; + } + + if (g_pOriginalDemoPlayerModule) + { + g_OriginalDemoPlayerFactory = Sys_GetFactory(g_pOriginalDemoPlayerModule); + if (g_OriginalDemoPlayerFactory) + { + int returnCode = 0; + g_pOriginalDemoPlayer = reinterpret_cast(g_OriginalDemoPlayerFactory(DEMOPLAYER_INTERFACE_VERSION, &returnCode)); + return g_pOriginalDemoPlayer; + } + } + + return NULL; +} + +InterfaceReg iface = InterfaceReg(CreateDemoPlayerInterface, DEMOPLAYER_INTERFACE_VERSION); + +// DLL entry point +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + g_pOriginalDemoPlayerModule = Sys_LoadModule(ORIGINAL_DEMOPLAYER_DLL_NAME); + size_t addr = (size_t)Sys_GetProcAddress(ORIGINAL_DEMOPLAYER_DLL_NAME, CREATEINTERFACE_PROCNAME); + HookModule("hltv.exe", addr); + } + else if (fdwReason == DLL_PROCESS_DETACH) + { + if (g_pOriginalDemoPlayerModule) + { + Sys_UnloadModule(g_pOriginalDemoPlayerModule); + g_pOriginalDemoPlayerModule = NULL; + g_OriginalDemoPlayerFactory = NULL; + g_pOriginalDemoPlayer = NULL; + } + } + + return TRUE; +} + +#endif // #if defined(HOOK_HLTV) diff --git a/rehlds/hookers/HLTV/Proxy/hooklist.cpp b/rehlds/hookers/HLTV/Proxy/hooklist.cpp new file mode 100644 index 0000000..2fb1ca5 --- /dev/null +++ b/rehlds/hookers/HLTV/Proxy/hooklist.cpp @@ -0,0 +1,427 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#ifdef HOOK_HLTV + +// Hooks stuff +#include "hookers/memory.cpp" +#include "hookers/hooker.cpp" + +//#define Mem_region +//#define Proxy_region +//#define BaseClient_region +//#define BitBuffer_region +//#define NetChannel_region +//#define Master_region +//#define Function_References_region +//#define Data_References_region + +FunctionHook g_FunctionHooks[] = +{ + // DO NOT DISABLE, other functions depends on memory allocation routines +#ifndef Mem_region + + HOOK_DEF(0x01D20F3F, malloc_wrapper), + HOOK_DEF(0x01D20E2E, free_wrapper), + HOOK_DEF(0x01D3078C, strdup_wrapper), + HOOK_DEF(0x01D20F51, __nh_malloc_wrapper), + + HOOK_DEF(0x01D03EF0, Mem_ZeroMalloc), + //HOOK_DEF(0x0, Mem_Malloc), + //HOOK_DEF(0x0, Mem_Realloc), + //HOOK_DEF(0x0, Mem_Calloc), + //HOOK_DEF(0x0, Mem_Strdup), + //HOOK_DEF(0x0, Mem_Free), + + //HOOK_DEF(0x0, realloc_wrapper), + //HOOK_DEF(0x0, calloc_wrapper), + +#endif // Mem_region + +#ifndef Proxy_region + + // virtual functions - BaseSystemModule + HOOK_VIRTUAL_DEF(0x01D16010, Proxy::Init), + HOOK_VIRTUAL_DEF(0x01D16020, Proxy::RunFrame), + HOOK_VIRTUAL_DEF(0x01D16030, Proxy::ReceiveSignal), + HOOK_VIRTUAL_DEF(0x01D16040, Proxy::ExecuteCommand), + HOOK_VIRTUAL_DEF(0x01D16090, Proxy::GetStatusLine), + HOOK_VIRTUAL_DEF(0x01D160A0, Proxy::GetType), + HOOK_VIRTUAL_DEF(0x01D160E0, Proxy::ShutDown), + + // virtual functions - Proxy + HOOK_VIRTUAL_DEF(0x01D115D0, Proxy::Reset), + HOOK_VIRTUAL_DEF(0x01D11620, Proxy::Broadcast), + HOOK_VIRTUAL_DEF(0x01D14FE0, Proxy::IncreaseCheering), + HOOK_VIRTUAL_DEF(0x01D11600, Proxy::ParseStatusMsg), + HOOK_VIRTUAL_DEF(0x01D11610, Proxy::ParseStatusReport), + HOOK_VIRTUAL_DEF(0x01D12FF0, Proxy::ProcessConnectionlessMessage), + HOOK_VIRTUAL_DEF(0x01D14780, Proxy::ChatCommentator), + HOOK_VIRTUAL_DEF(0x01D137B0, Proxy::ChatSpectator), + HOOK_VIRTUAL_DEF(0x01D11370, Proxy::CountLocalClients), + HOOK_VIRTUAL_DEF(0x01D143B0, Proxy::AddResource), + HOOK_VIRTUAL_DEF(0x01D11570, Proxy::IsLanOnly), + HOOK_VIRTUAL_DEF(0x01D13A00, Proxy::IsMaster), + HOOK_VIRTUAL_DEF(0x01D11580, Proxy::IsActive), + HOOK_VIRTUAL_DEF(0x01D114F0, Proxy::IsPublicGame), + HOOK_VIRTUAL_DEF(0x01D11500, Proxy::IsPasswordProtected), + HOOK_VIRTUAL_DEF(0x01D11510, Proxy::IsStressed), + HOOK_VIRTUAL_DEF(0x01D154A0, Proxy::SetDelay), + HOOK_VIRTUAL_DEF(0x01D15540, Proxy::SetClientTime), + HOOK_VIRTUAL_DEF(0x01D15580, Proxy::SetClientTimeScale), + HOOK_VIRTUAL_DEF(0x01D15430, Proxy::SetMaxRate), + HOOK_VIRTUAL_DEF(0x01D118D0, Proxy::SetMaxLoss), + HOOK_VIRTUAL_DEF(0x01D15470, Proxy::SetMaxUpdateRate), + HOOK_VIRTUAL_DEF(0x01D11870, Proxy::SetMaxClients), + HOOK_VIRTUAL_DEF(0x01D11930, Proxy::SetRegion), + HOOK_VIRTUAL_DEF(0x01D14FA0, Proxy::GetDelay), + HOOK_VIRTUAL_DEF(0x01D14FC0, Proxy::GetSpectatorTime), + HOOK_VIRTUAL_DEF(0x01D14FD0, Proxy::GetProxyTime), + HOOK_VIRTUAL_DEF(0x01D11920, Proxy::GetMaxClients), + HOOK_VIRTUAL_DEF(0x01D10EF0, Proxy::GetWorld), + HOOK_VIRTUAL_DEF(0x01D10F00, Proxy::GetServer), + HOOK_VIRTUAL_DEF(0x01D10F10, Proxy::GetDirector), + HOOK_VIRTUAL_DEF(0x01D10F20, Proxy::GetSocket), + HOOK_VIRTUAL_DEF(0x01D10F30, Proxy::GetChatMode), + HOOK_VIRTUAL_DEF(0x01D113C0, Proxy::GetStatistics), + HOOK_VIRTUAL_DEF(0x01D113D0, Proxy::GetMaxRate), + HOOK_VIRTUAL_DEF(0x01D113E0, Proxy::GetMaxUpdateRate), + HOOK_VIRTUAL_DEF(0x01D14420, Proxy::GetResource), + HOOK_VIRTUAL_DEF(0x01D11550, Proxy::GetDispatchMode), + HOOK_VIRTUAL_DEF(0x01D115A0, Proxy::GetRegion), + HOOK_VIRTUAL_DEF(0x01D10EE0, Proxy::GetClients), + HOOK_VIRTUAL_DEF(0x01D113F0, Proxy::WriteSignonData), + + // non-virtual functions - Proxy + HOOK_DEF(0x01D12BD0, Proxy::ReplyServiceChallenge), + HOOK_DEF(0x01D115B0, Proxy::ReplyListen), + HOOK_DEF(0x01D10900, Proxy::ReplyConnect), + HOOK_DEF(0x01D10890, Proxy::ReplyRules), + HOOK_DEF(0x01D10820, Proxy::ReplyPlayers), + HOOK_DEF(0x01D10770, Proxy::ReplyInfo), + HOOK_DEF(0x01D10720, Proxy::ReplyInfoString), + HOOK_DEF(0x01D106D0, Proxy::ReplyChallenge), + HOOK_DEF(0x01D105F0, Proxy::ReplyPing), + HOOK_DEF(0x01D12F50, Proxy::ExecuteRcon), + HOOK_DEF(0x01D13B70, Proxy::ReconnectClients), + HOOK_DEF(0x01D129A0, Proxy::SendRcon), + HOOK_DEF(0x01D10DD0, Proxy::RejectConnection), + HOOK_DEF(0x01D10F40, Proxy::UpdateStatusLine), + HOOK_DEF(0x01D14220, Proxy::DispatchClient), + HOOK_DEF(0x01D13FA0, Proxy::IsValidPassword), + HOOK_DEF(0x01D13E50, Proxy::WriteHUDMsg), + HOOK_DEF(0x01D150D0, Proxy::ExecuteLoopCommands), + HOOK_DEF(0x01D12A30, Proxy::GetChallengeNumber), + HOOK_DEF(0x01D12B60, Proxy::CheckChallenge), + HOOK_DEF(0x01D15150, Proxy::CreateServerInfoString), + HOOK_DEF(0x01D13A10, Proxy::CheckDirectorModule), + HOOK_DEF(0x01D158B0, Proxy::RunClocks), + HOOK_DEF(0x01D156B0, Proxy::NewGameStarted), + HOOK_DEF(0x01D12CC0, Proxy::NewServerConnection), + HOOK_DEF(0x01D15620, Proxy::BroadcastPaused), + HOOK_DEF(0x01D12E80, Proxy::BroadcastRetryMessage), + HOOK_DEF(0x01D12EE0, Proxy::StopBroadcast), + HOOK_DEF(0x01D15A10, Proxy::DisconnectClients), + HOOK_DEF(0x01D14350, Proxy::FreeResource), + HOOK_DEF(0x01D14380, Proxy::ClearResources), + HOOK_DEF(0x01D142C0, Proxy::LoadResourceFromFile), + HOOK_DEF(0x01D14800, Proxy::IsBanned), + HOOK_DEF(0x01D15A60, Proxy::UpdateInfoMessages), + + HOOK_DEF(0x01D12860, Proxy::CMD_Rcon), + HOOK_DEF(0x01D11EF0, Proxy::CMD_ServerCmd), + HOOK_DEF(0x01D11F90, Proxy::CMD_ClientCmd), + HOOK_DEF(0x01D127D0, Proxy::CMD_RconPassword), + HOOK_DEF(0x01D12700, Proxy::CMD_RconAddress), + HOOK_DEF(0x01D11700, Proxy::CMD_Say), + HOOK_DEF(0x01D11C10, Proxy::CMD_Msg), + HOOK_DEF(0x01D10D40, Proxy::CMD_Clients), + HOOK_DEF(0x01D13920, Proxy::CMD_Kick), + HOOK_DEF(0x01D13650, Proxy::CMD_ChatMode), + HOOK_DEF(0x01D13DA0, Proxy::CMD_PublicGame), + HOOK_DEF(0x01D13BB0, Proxy::CMD_OffLineText), + HOOK_DEF(0x01D14550, Proxy::CMD_AdminPassword), + HOOK_DEF(0x01D14470, Proxy::CMD_SignOnCommands), + HOOK_DEF(0x01D13EE0, Proxy::CMD_SpectatorPassword), + HOOK_DEF(0x01D140B0, Proxy::CMD_DispatchMode), + HOOK_DEF(0x01D14F00, Proxy::CMD_CheeringThreshold), + HOOK_DEF(0x01D10610, Proxy::CMD_Ping), + HOOK_DEF(0x01D12C00, Proxy::CMD_ProxyPassword), + HOOK_DEF(0x01D11E50, Proxy::CMD_MaxRate), + HOOK_DEF(0x01D12570, Proxy::CMD_LoopCmd), + HOOK_DEF(0x01D117C0, Proxy::CMD_MaxClients), + HOOK_DEF(0x01D14610, Proxy::CMD_LocalMsg), + HOOK_DEF(0x01D11A50, Proxy::CMD_Connect), + HOOK_DEF(0x01D139F0, Proxy::CMD_Disconnect), + HOOK_DEF(0x01D14180, Proxy::CMD_PlayDemo), + HOOK_DEF(0x01D11940, Proxy::CMD_Delay), + HOOK_DEF(0x01D119E0, Proxy::CMD_Stop), + HOOK_DEF(0x01D12480, Proxy::CMD_Record), + HOOK_DEF(0x01D12530, Proxy::CMD_StopRecording), + HOOK_DEF(0x01D123C0, Proxy::CMD_BlockVoice), + HOOK_DEF(0x01D11B20, Proxy::CMD_Name), + HOOK_DEF(0x01D120B0, Proxy::CMD_Rate), + HOOK_DEF(0x01D12300, Proxy::CMD_Updaterate), + HOOK_DEF(0x01D12220, Proxy::CMD_HostName), + HOOK_DEF(0x01D13CC0, Proxy::CMD_AddResource), + HOOK_DEF(0x01D13C60, Proxy::CMD_Resources), + HOOK_DEF(0x01D14DD0, Proxy::CMD_BannerFile), + HOOK_DEF(0x01D14AF0, Proxy::CMD_Bann), + HOOK_DEF(0x01D14850, Proxy::CMD_AddFakeClients), + HOOK_DEF(0x01D14CD0, Proxy::CMD_Retry), + HOOK_DEF(0x01D14D00, Proxy::CMD_AutoRetry), + HOOK_DEF(0x01D14C40, Proxy::CMD_ServerPassword), + HOOK_DEF(0x01D11040, Proxy::CMD_Status), + HOOK_DEF(0x01D13710, Proxy::CMD_MaxQueries), + HOOK_DEF(0x01D12170, Proxy::CMD_Players), + HOOK_DEF(0x01D14C00, Proxy::CMD_ClearBanns), + HOOK_DEF(0x01D149B0, Proxy::CMD_MaxLoss), + HOOK_DEF(0x01D11D80, Proxy::CMD_Protocol), + HOOK_DEF(0x01D14A50, Proxy::CMD_Region), + + //HOOK_DEF(0x01D12E70, Proxy::GetModVersion), // NOXREF + //HOOK_DEF(0x0, Proxy::CMD_InformPlayers), // NOXREF + //HOOK_DEF(0x0, Proxy::CMD_MaxUpdateRate), // NOXREF + +#endif // Proxy_region + +#ifndef BaseClient_region + + // IClient + HOOK_VIRTUAL_DEF(0x01D01670, BaseClient::Connect), + HOOK_VIRTUAL_DEF(0x01D02790, BaseClient::Send), + HOOK_VIRTUAL_DEF(0x01D01830, BaseClient::Disconnect), + HOOK_VIRTUAL_DEF(0x01D023F0, BaseClient::Reconnect), + HOOK_VIRTUAL_DEF(0x01D023C0, BaseClient::SetWorld), + HOOK_VIRTUAL_DEF(0x01D027D0, BaseClient::GetClientType), + HOOK_VIRTUAL_DEF(0x01D01810, BaseClient::GetClientName), + HOOK_VIRTUAL_DEF(0x01D01820, BaseClient::GetUserInfo), + HOOK_VIRTUAL_DEF(0x01D027C0, BaseClient::GetAddress), + HOOK_VIRTUAL_DEF(0x01D02420, BaseClient::IsActive), + HOOK_VIRTUAL_DEF(0x01D026F0, BaseClient::IsHearingVoices), + HOOK_VIRTUAL_DEF(0x01D02730, BaseClient::HasChatEnabled), + HOOK_VIRTUAL_DEF(0x01D02760, BaseClient::DownloadFailed), + HOOK_VIRTUAL_DEF(0x01D02740, BaseClient::DownloadFile), + HOOK_VIRTUAL_DEF(0x01D025C0, BaseClient::UpdateVoiceMask), + HOOK_VIRTUAL_DEF(0x01D02580, BaseClient::QueryVoiceEnabled), + HOOK_VIRTUAL_DEF(0x01D02470, BaseClient::SetName), + HOOK_VIRTUAL_DEF(0x01D02100, BaseClient::WriteSpawn), + HOOK_VIRTUAL_DEF(0x01D02180, BaseClient::WriteDatagram), + HOOK_VIRTUAL_DEF(0x01D027F0, BaseClient::SendDatagram), + HOOK_VIRTUAL_DEF(0x01D02820, BaseClient::Reset), + HOOK_VIRTUAL_DEF(0x01D02020, BaseClient::SetState), + HOOK_VIRTUAL_DEF(0x01D01F20, BaseClient::ReplyNew), + HOOK_VIRTUAL_DEF(0x01D01E50, BaseClient::ReplySpawn), + HOOK_VIRTUAL_DEF(0x01D01F90, BaseClient::ReplyFullUpdate), + HOOK_VIRTUAL_DEF(0x01D01E10, BaseClient::PrintfToClient), + HOOK_VIRTUAL_DEF(0x01D01D00, BaseClient::UpdateUserInfo), + HOOK_VIRTUAL_DEF(0x01D01900, BaseClient::ParseStringCmd), + HOOK_VIRTUAL_DEF(0x01D018C0, BaseClient::ParseNop), + HOOK_VIRTUAL_DEF(0x01D018D0, BaseClient::ParseBad), + HOOK_VIRTUAL_DEF(0x01D02450, BaseClient::ParseMove), + HOOK_VIRTUAL_DEF(0x01D02430, BaseClient::ParseVoiceData), + HOOK_VIRTUAL_DEF(0x01D02530, BaseClient::ParseHLTV), + HOOK_VIRTUAL_DEF(0x01D022E0, BaseClient::ParseDelta), + HOOK_VIRTUAL_DEF(0x01D02540, BaseClient::ParseCvarValue), + HOOK_VIRTUAL_DEF(0x01D02550, BaseClient::ParseCvarValue2), + HOOK_VIRTUAL_DEF(0x01D01740, BaseClient::ProcessMessage), + HOOK_VIRTUAL_DEF(0x01D01920, BaseClient::ProcessStringCmd), + + // BaseSystemModule + HOOK_VIRTUAL_DEF(0x01D02950, BaseClient::Init), + HOOK_VIRTUAL_DEF(0x01D02960, BaseClient::RunFrame), + HOOK_VIRTUAL_DEF(0x01D02330, BaseClient::GetStatusLine), + HOOK_VIRTUAL_DEF(0x01D16CE0, BaseClient::GetType), + HOOK_VIRTUAL_DEF(0x01D02A20, BaseClient::ShutDown), + +#endif // BaseClient_region + +#ifndef BitBuffer_region + + HOOK_DEF(0x01D02F80, MethodThunk::Destructor), + HOOK_DEF(0x01D02F10, (MethodThunk::Constructor), void()), + HOOK_DEF(0x01D02F90, (MethodThunk::Constructor), void(unsigned int)), + HOOK_DEF(0x01D02F50, (MethodThunk::Constructor), void(void *, unsigned int)), + + HOOK_DEF(0x01D02FC0, BitBuffer::Resize), + HOOK_DEF(0x01D03010, BitBuffer::Clear), + HOOK_DEF(0x01D03050, BitBuffer::Reset), + HOOK_DEF(0x01D03070, BitBuffer::Free), + HOOK_DEF(0x01D03220, BitBuffer::PeekBits), + HOOK_DEF(0x01D038D0, BitBuffer::CurrentSize), + HOOK_DEF(0x01D03CE0, BitBuffer::FastClear), + HOOK_DEF(0x01D03D30, BitBuffer::ConcatBuffer), + HOOK_DEF(0x01D03BF0, BitBuffer::SkipBytes), + HOOK_DEF(0x01D03040, BitBuffer::CurrentBit), // NOXREF + HOOK_DEF(0x01D038F0, BitBuffer::SpaceLeft), // NOXREF + HOOK_DEF(0x01D03900, BitBuffer::AlignByte), // NOXREF + HOOK_DEF(0x01D03A70, BitBuffer::StartBitMode), // NOXREF + HOOK_DEF(0x01D03A80, BitBuffer::EndBitMode), // NOXREF + HOOK_DEF(0x01D03AC0, BitBuffer::SetBuffer), // NOXREF + HOOK_DEF(0x01D03C20, BitBuffer::SkipBits), // NOXREF + HOOK_DEF(0x01D03CB0, BitBuffer::SkipString), // NOXREF + + // Read + HOOK_DEF(0x01D030B0, BitBuffer::ReadBits), + HOOK_DEF(0x01D03190, BitBuffer::ReadBit), + HOOK_DEF(0x01D03250, BitBuffer::ReadChar), + HOOK_DEF(0x01D03260, BitBuffer::ReadByte), + HOOK_DEF(0x01D03270, BitBuffer::ReadShort), + HOOK_DEF(0x01D03280, BitBuffer::ReadWord), + HOOK_DEF(0x01D03290, BitBuffer::ReadLong), + HOOK_DEF(0x01D032A0, BitBuffer::ReadFloat), + HOOK_DEF(0x01D032C0, BitBuffer::ReadBuf), + HOOK_DEF(0x01D033A0, BitBuffer::ReadString), + HOOK_DEF(0x01D033E0, BitBuffer::ReadStringLine), + HOOK_DEF(0x01D03A00, BitBuffer::ReadBitString), + HOOK_DEF(0x01D03A90, BitBuffer::ReadBitData), + HOOK_DEF(0x01D03AF0, BitBuffer::ReadBitVec3Coord), + HOOK_DEF(0x01D03B50, BitBuffer::ReadBitCoord), + HOOK_DEF(0x01D03BD0, BitBuffer::ReadCoord), + HOOK_DEF(0x01D03420, BitBuffer::ReadAngle), // NOXREF + HOOK_DEF(0x01D03440, BitBuffer::ReadHiresAngle), // NOXREF + HOOK_DEF(0x01D03920, BitBuffer::ReadSBits), // NOXREF + HOOK_DEF(0x01D03950, BitBuffer::ReadBitAngle), // NOXREF + + // Write + HOOK_DEF(0x01D03770, BitBuffer::WriteBuf, void(const void *, int)), + HOOK_DEF(0x01D03370, BitBuffer::WriteBuf, void(BitBuffer *, int)), + + HOOK_DEF(0x01D03460, BitBuffer::WriteBit), + HOOK_DEF(0x01D03530, BitBuffer::WriteBits), + HOOK_DEF(0x01D03650, BitBuffer::WriteSBits), // NOXREF + HOOK_DEF(0x01D036B0, BitBuffer::WriteChar), + HOOK_DEF(0x01D036C0, BitBuffer::WriteByte), + HOOK_DEF(0x01D036D0, BitBuffer::WriteShort), + HOOK_DEF(0x01D036E0, BitBuffer::WriteWord), + HOOK_DEF(0x01D036F0, BitBuffer::WriteLong), + HOOK_DEF(0x01D03700, BitBuffer::WriteFloat), + HOOK_DEF(0x01D03730, BitBuffer::WriteString), + HOOK_DEF(0x01D03D50, BitBuffer::WriteCoord), + HOOK_DEF(0x01D03840, BitBuffer::WriteBitData), // NOXREF + HOOK_DEF(0x01D03870, BitBuffer::WriteAngle), // NOXREF + HOOK_DEF(0x01D038A0, BitBuffer::WriteHiresAngle), // NOXREF + HOOK_DEF(0x01D03990, BitBuffer::WriteBitAngle), // NOXREF + HOOK_DEF(0x01D03A30, BitBuffer::WriteBitString), // NOXREF + +#endif // BitBuffer_region + +#ifndef NetChannel_region + + // virtual functions + HOOK_VIRTUAL_DEF(0x01D0C7E0, NetChannel::Create), + HOOK_VIRTUAL_DEF(0x01D0DC20, NetChannel::GetTargetAddress), + HOOK_VIRTUAL_DEF(0x01D0C8C0, NetChannel::Close), + HOOK_VIRTUAL_DEF(0x01D0C6E0, NetChannel::Clear), + HOOK_VIRTUAL_DEF(0x01D0C650, NetChannel::Reset), + HOOK_VIRTUAL_DEF(0x01D0DC40, NetChannel::IsConnected), + HOOK_VIRTUAL_DEF(0x01D0C8F0, NetChannel::IsReadyToSend), + HOOK_VIRTUAL_DEF(0x01D0DD60, NetChannel::IsCrashed), + HOOK_VIRTUAL_DEF(0x01D0DC70, NetChannel::IsTimedOut), + HOOK_VIRTUAL_DEF(0x01D0DC30, NetChannel::IsFakeChannel), + HOOK_VIRTUAL_DEF(0x01D0DC10, NetChannel::KeepAlive), + HOOK_VIRTUAL_DEF(0x01D0DB90, NetChannel::SetRate), + + HOOK_VIRTUAL_DEF(0x01D0D9F0, NetChannel::SetUpdateRate), + HOOK_VIRTUAL_DEF(0x01D0DC50, NetChannel::SetTimeOut), + HOOK_VIRTUAL_DEF(0x01D0DC00, NetChannel::SetKeepAlive), + HOOK_VIRTUAL_DEF(0x01D0DCB0, NetChannel::GetIdleTime), + HOOK_VIRTUAL_DEF(0x01D0DCC0, NetChannel::GetRate), + HOOK_VIRTUAL_DEF(0x01D0DCD0, NetChannel::GetUpdateRate), + HOOK_VIRTUAL_DEF(0x01D0DCE0, NetChannel::GetLoss), + + HOOK_VIRTUAL_DEF(0x01D0C9E0, NetChannel::TransmitOutgoing), + HOOK_VIRTUAL_DEF(0x01D0D130, NetChannel::ProcessIncoming), + HOOK_VIRTUAL_DEF(0x01D0DCF0, NetChannel::FakeAcknowledgement), + HOOK_VIRTUAL_DEF(0x01D0C480, NetChannel::OutOfBandPrintf), + + // non-virtual functions + HOOK_DEF(0x01D0C400, NetChannel::UnlinkFragment), + HOOK_DEF(0x01D0C530, NetChannel::ClearFragbufs), + HOOK_DEF(0x01D0C560, NetChannel::ClearFragments), + HOOK_DEF(0x01D0C5D0, NetChannel::FlushIncoming), + HOOK_DEF(0x01D0C910, NetChannel::UpdateFlow), + HOOK_DEF(0x01D0D030, NetChannel::FindBufferById), + HOOK_DEF(0x01D0D090, NetChannel::CheckForCompletion), + HOOK_DEF(0x01D0D620, NetChannel::FragSend), + HOOK_DEF(0x01D0D670, NetChannel::AddBufferToList), + HOOK_DEF(0x01D0D6C0, NetChannel::CreateFragmentsFromBuffer), + HOOK_DEF(0x01D0DD20, NetChannel::CreateFragmentsFromFile), + HOOK_DEF(0x01D0D970, NetChannel::AddFragbufToTail), + HOOK_DEF(0x01D0D9B0, NetChannel::GetPacket), + HOOK_DEF(0x01D0D9C0, NetChannel::FreePacket), + HOOK_DEF(0x01D0DA30, NetChannel::CopyNormalFragments), + HOOK_DEF(0x01D0DBD0, NetChannel::GetFlowStats), + HOOK_DEF(0x01D0DBC0, NetChannel::SetConnected), // NOXREF + HOOK_DEF(0x01D0DD70, NetChannel::CopyFileFragments), // NOXREF + +#endif // NetChannel_region + +#ifndef Master_region + + // virtual functions + HOOK_VIRTUAL_DEF(0x01D0A480, Master::Init), + HOOK_VIRTUAL_DEF(0x01D0A490, Master::RunFrame), + HOOK_VIRTUAL_DEF(0x01D0A4B0, Master::ExecuteCommand), + HOOK_VIRTUAL_DEF(0x01D0A500, Master::GetStatusLine), + HOOK_VIRTUAL_DEF(0x01D0A510, Master::GetType), + HOOK_VIRTUAL_DEF(0x01D0A550, Master::ShutDown), + + //HOOK_DEF(0x0, Master::InitializeSteam), // NOXREF + HOOK_DEF(0x01D0A230, Master::CMD_Heartbeat), + HOOK_DEF(0x01D0A260, Master::CMD_NoMaster), + HOOK_DEF(0x01D0A350, Master::CMD_ListMaster), + HOOK_DEF(0x01D0A3E0, Master::SendShutdown), + +#endif // Master_region + + { NULL, NULL, NULL }, +}; + +AddressRef g_FunctionRefs[] = +{ +#ifndef Function_References_region + +#endif // Function_References_region + + { NULL, NULL, NULL }, +}; + +AddressRef g_DataRefs[] = +{ +#ifndef Data_References_region + + +#endif // Data_References_region + + { NULL, NULL, NULL }, +}; + +#endif // HOOK_HLTV diff --git a/rehlds/hookers/HLTV/Proxy/hooklist.h b/rehlds/hookers/HLTV/Proxy/hooklist.h new file mode 100644 index 0000000..d030ec9 --- /dev/null +++ b/rehlds/hookers/HLTV/Proxy/hooklist.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef HOOK_HLTV + +#include "hookers/memory.h" +#include "hookers/helper.h" +#include "hookers/hooker.h" + +#define rehlds_syserror HLTV_SysError + +#endif // HOOK_HLTV diff --git a/rehlds/hookers/HLTV/Proxy/main.cpp b/rehlds/hookers/HLTV/Proxy/main.cpp new file mode 100644 index 0000000..a1528c3 --- /dev/null +++ b/rehlds/hookers/HLTV/Proxy/main.cpp @@ -0,0 +1,55 @@ +#include "precompiled.h" + +#if defined(HOOK_HLTV) +#define ORIGINAL_PROXY_DLL_NAME "proxy2.dll" + +CSysModule *g_pOriginalProxyModule = NULL; +CreateInterfaceFn g_OriginalProxyFactory = NULL; +ISystemModule *g_pOriginalProxy = NULL; + +IBaseInterface *CreateProxyInterface() +{ + if (g_pOriginalProxy) { + return g_pOriginalProxy; + } + + if (g_pOriginalProxyModule) + { + g_OriginalProxyFactory = Sys_GetFactory(g_pOriginalProxyModule); + if (g_OriginalProxyFactory) + { + int returnCode = 0; + g_pOriginalProxy = reinterpret_cast(g_OriginalProxyFactory(PROXY_INTERFACE_VERSION, &returnCode)); + return g_pOriginalProxy; + } + } + + return NULL; +} + +InterfaceReg iface = InterfaceReg(CreateProxyInterface, PROXY_INTERFACE_VERSION); + +// DLL entry point +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + g_pOriginalProxyModule = Sys_LoadModule(ORIGINAL_PROXY_DLL_NAME); + size_t addr = (size_t)Sys_GetProcAddress(ORIGINAL_PROXY_DLL_NAME, CREATEINTERFACE_PROCNAME); + HookModule("hltv.exe", addr); + } + else if (fdwReason == DLL_PROCESS_DETACH) + { + if (g_pOriginalProxyModule) + { + Sys_UnloadModule(g_pOriginalProxyModule); + g_pOriginalProxyModule = NULL; + g_OriginalProxyFactory = NULL; + g_pOriginalProxy = NULL; + } + } + + return TRUE; +} + +#endif // #if defined(HOOK_HLTV) diff --git a/rehlds/public/FileSystem.h b/rehlds/public/FileSystem.h index 41d26b5..8e202ba 100644 --- a/rehlds/public/FileSystem.h +++ b/rehlds/public/FileSystem.h @@ -1,20 +1,39 @@ -//========= Copyright � 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ -#ifndef FILESYSTEM_H -#define FILESYSTEM_H -#ifdef _WIN32 #pragma once -#endif #include "interface.h" #include #include +// There is only one instance of the IFileSystem interface, +// located in the filesystem_stdio library (filesystem_steam is obsolete). #ifdef _WIN32 #define STDIO_FILESYSTEM_LIB "filesystem_stdio.dll" #define STEAM_FILESYSTEM_LIB "filesystem_steam.dll" @@ -23,17 +42,13 @@ #define STEAM_FILESYSTEM_LIB "filesystem_steam.so" #endif // _WIN32 -//----------------------------------------------------------------------------- // Forward declarations -//----------------------------------------------------------------------------- -typedef FILE * FileHandle_t; +typedef FILE *FileHandle_t; typedef int FileFindHandle_t; typedef int WaitForResourcesHandle_t; +typedef void (*WarningFunc_t)(const char *fmt, ...); - -//----------------------------------------------------------------------------- // Enums used by the interface -//----------------------------------------------------------------------------- #ifndef FILESYSTEM_INTERNAL_H typedef enum { @@ -49,148 +64,138 @@ enum typedef enum { - // Don't print anything - FILESYSTEM_WARNING_QUIET = 0, - - // On shutdown, report names of files left unclosed - FILESYSTEM_WARNING_REPORTUNCLOSED, - - // Report number of times a file was opened, closed - FILESYSTEM_WARNING_REPORTUSAGE, - - // Report all open/close events to console ( !slow! ) - FILESYSTEM_WARNING_REPORTALLACCESSES + FILESYSTEM_WARNING_QUIET = 0, // Don't print anything + FILESYSTEM_WARNING_REPORTUNCLOSED, // On shutdown, report names of files left unclosed + FILESYSTEM_WARNING_REPORTUSAGE, // Report number of times a file was opened, closed + FILESYSTEM_WARNING_REPORTALLACCESSES // Report all open/close events to console (!slow!) } FileWarningLevel_t; -#define FILESYSTEM_INVALID_HANDLE ( FileHandle_t )0 -#endif +#define FILESYSTEM_INVALID_HANDLE (FileHandle_t)0 +#endif // FILESYSTEM_INTERNAL_H // turn off any windows defines #undef GetCurrentDirectory -//----------------------------------------------------------------------------- // Purpose: Main file system interface -//----------------------------------------------------------------------------- class IFileSystem : public IBaseInterface { public: // Mount and unmount the filesystem - virtual void Mount( void ) = 0; - virtual void Unmount( void ) = 0; + virtual void Mount() = 0; + virtual void Unmount() = 0; // Remove all search paths (including write path?) - virtual void RemoveAllSearchPaths( void ) = 0; + virtual void RemoveAllSearchPaths() = 0; // Add paths in priority order (mod dir, game dir, ....) // If one or more .pak files are in the specified directory, then they are // added after the file system path // If the path is the relative path to a .bsp file, then any previous .bsp file // override is cleared and the current .bsp is searched for an embedded PAK file - // and this file becomes the highest priority search path ( i.e., it's looked at first - // even before the mod's file system path ). - virtual void AddSearchPath( const char *pPath, const char *pathID ) = 0; - virtual bool RemoveSearchPath( const char *pPath ) = 0; + // and this file becomes the highest priority search path (i.e., it's looked at first + // even before the mod's file system path). + virtual void AddSearchPath(const char *pPath, const char *pathID) = 0; + virtual bool RemoveSearchPath(const char *pPath) = 0; // Deletes a file - virtual void RemoveFile( const char *pRelativePath, const char *pathID ) = 0; + virtual void RemoveFile(const char *pRelativePath, const char *pathID) = 0; // this isn't implementable on STEAM as is. - virtual void CreateDirHierarchy( const char *path, const char *pathID ) = 0; + virtual void CreateDirHierarchy(const char *path, const char *pathID) = 0; // File I/O and info - virtual bool FileExists( const char *pFileName ) = 0; - virtual bool IsDirectory( const char *pFileName ) = 0; + virtual bool FileExists(const char *pFileName) = 0; + virtual bool IsDirectory(const char *pFileName) = 0; // opens a file // if pathID is NULL, all paths will be searched for the file - virtual FileHandle_t Open( const char *pFileName, const char *pOptions, const char *pathID = 0L ) = 0; + virtual FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0L) = 0; - virtual void Close( FileHandle_t file ) = 0; + virtual void Close(FileHandle_t file) = 0; - virtual void Seek( FileHandle_t file, int pos, FileSystemSeek_t seekType ) = 0; - virtual unsigned int Tell( FileHandle_t file ) = 0; + virtual void Seek(FileHandle_t file, int pos, FileSystemSeek_t seekType) = 0; + virtual unsigned int Tell(FileHandle_t file) = 0; - virtual unsigned int Size( FileHandle_t file ) = 0; - virtual unsigned int Size( const char *pFileName ) = 0; + virtual unsigned int Size(FileHandle_t file) = 0; + virtual unsigned int Size(const char *pFileName) = 0; - virtual long GetFileTime( const char *pFileName ) = 0; - virtual void FileTimeToString( char* pStrip, int maxCharsIncludingTerminator, long fileTime ) = 0; + virtual long GetFileTime(const char *pFileName) = 0; + virtual void FileTimeToString(char *pStrip, int maxCharsIncludingTerminator, long fileTime) = 0; - virtual bool IsOk( FileHandle_t file ) = 0; + virtual bool IsOk(FileHandle_t file) = 0; - virtual void Flush( FileHandle_t file ) = 0; - virtual bool EndOfFile( FileHandle_t file ) = 0; + virtual void Flush(FileHandle_t file) = 0; + virtual bool EndOfFile(FileHandle_t file) = 0; - virtual int Read( void* pOutput, int size, FileHandle_t file ) = 0; - virtual int Write( void const* pInput, int size, FileHandle_t file ) = 0; - virtual char *ReadLine( char *pOutput, int maxChars, FileHandle_t file ) = 0; - virtual int FPrintf( FileHandle_t file, char *pFormat, ... ) = 0; + virtual int Read(void *pOutput, int size, FileHandle_t file) = 0; + virtual int Write(void const *pInput, int size, FileHandle_t file) = 0; + virtual char *ReadLine(char *pOutput, int maxChars, FileHandle_t file) = 0; + virtual int FPrintf(FileHandle_t file, char *pFormat, ...) = 0; // direct filesystem buffer access // returns a handle to a buffer containing the file data // this is the optimal way to access the complete data for a file, // since the file preloader has probably already got it in memory - virtual void *GetReadBuffer( FileHandle_t file, int *outBufferSize, bool failIfNotInCache ) = 0; - virtual void ReleaseReadBuffer( FileHandle_t file, void *readBuffer ) = 0; + virtual void *GetReadBuffer(FileHandle_t file, int *outBufferSize, bool failIfNotInCache) = 0; + virtual void ReleaseReadBuffer(FileHandle_t file, void *readBuffer) = 0; // FindFirst/FindNext - virtual const char *FindFirst( const char *pWildCard, FileFindHandle_t *pHandle, const char *pathID = 0L ) = 0; - virtual const char *FindNext( FileFindHandle_t handle ) = 0; - virtual bool FindIsDirectory( FileFindHandle_t handle ) = 0; - virtual void FindClose( FileFindHandle_t handle ) = 0; + virtual const char *FindFirst(const char *pWildCard, FileFindHandle_t *pHandle, const char *pathID = 0L) = 0; + virtual const char *FindNext(FileFindHandle_t handle) = 0; + virtual bool FindIsDirectory(FileFindHandle_t handle) = 0; + virtual void FindClose(FileFindHandle_t handle) = 0; - virtual void GetLocalCopy( const char *pFileName ) = 0; + virtual void GetLocalCopy(const char *pFileName) = 0; - virtual const char *GetLocalPath( const char *pFileName, char *pLocalPath, int localPathBufferSize ) = 0; + virtual const char *GetLocalPath(const char *pFileName, char *pLocalPath, int localPathBufferSize) = 0; // Note: This is sort of a secondary feature; but it's really useful to have it here - virtual char *ParseFile( char* pFileBytes, char* pToken, bool* pWasQuoted ) = 0; + virtual char *ParseFile(char *pFileBytes, char *pToken, bool *pWasQuoted) = 0; - // Returns true on success ( based on current list of search paths, otherwise false if it can't be resolved ) - virtual bool FullPathToRelativePath( const char *pFullpath, char *pRelative ) = 0; + // Returns true on success (based on current list of search paths, otherwise false if it can't be resolved) + virtual bool FullPathToRelativePath(const char *pFullpath, char *pRelative) = 0; // Gets the current working directory - virtual bool GetCurrentDirectory( char* pDirectory, int maxlen ) = 0; + virtual bool GetCurrentDirectory(char *pDirectory, int maxlen) = 0; // Dump to printf/OutputDebugString the list of files that have not been closed - virtual void PrintOpenedFiles( void ) = 0; + virtual void PrintOpenedFiles() = 0; - virtual void SetWarningFunc( void (*pfnWarning)( const char *fmt, ... ) ) = 0; - virtual void SetWarningLevel( FileWarningLevel_t level ) = 0; + virtual void SetWarningFunc(WarningFunc_t pfnWarning) = 0; + virtual void SetWarningLevel(FileWarningLevel_t level) = 0; - virtual void LogLevelLoadStarted( const char *name ) = 0; - virtual void LogLevelLoadFinished( const char *name ) = 0; - virtual int HintResourceNeed( const char *hintlist, int forgetEverything ) = 0; - virtual int PauseResourcePreloading( void ) = 0; - virtual int ResumeResourcePreloading( void ) = 0; - virtual int SetVBuf( FileHandle_t stream, char *buffer, int mode, long size ) = 0; - virtual void GetInterfaceVersion( char *p, int maxlen ) = 0; + virtual void LogLevelLoadStarted(const char *name) = 0; + virtual void LogLevelLoadFinished(const char *name) = 0; + virtual int HintResourceNeed(const char *hintlist, int forgetEverything) = 0; + virtual int PauseResourcePreloading() = 0; + virtual int ResumeResourcePreloading() = 0; + virtual int SetVBuf(FileHandle_t stream, char *buffer, int mode, long size) = 0; + virtual void GetInterfaceVersion(char *p, int maxlen) = 0; virtual bool IsFileImmediatelyAvailable(const char *pFileName) = 0; // starts waiting for resources to be available // returns FILESYSTEM_INVALID_HANDLE if there is nothing to wait on - virtual WaitForResourcesHandle_t WaitForResources( const char *resourcelist ) = 0; + virtual WaitForResourcesHandle_t WaitForResources(const char *resourcelist) = 0; + // get progress on waiting for resources; progress is a float [0, 1], complete is true on the waiting being done // returns false if no progress is available // any calls after complete is true or on an invalid handle will return false, 0.0f, true - virtual bool GetWaitForResourcesProgress( WaitForResourcesHandle_t handle, float *progress /* out */ , bool *complete /* out */ ) = 0; + virtual bool GetWaitForResourcesProgress(WaitForResourcesHandle_t handle, float *progress /* out */ , bool *complete /* out */) = 0; + // cancels a progress call - virtual void CancelWaitForResources( WaitForResourcesHandle_t handle ) = 0; + virtual void CancelWaitForResources(WaitForResourcesHandle_t handle) = 0; // returns true if the appID has all its caches fully preloaded - virtual bool IsAppReadyForOfflinePlay( int appID ) = 0; + virtual bool IsAppReadyForOfflinePlay(int appID) = 0; // interface for custom pack files > 4Gb - virtual bool AddPackFile( const char *fullpath, const char *pathID ) = 0; + virtual bool AddPackFile(const char *fullpath, const char *pathID) = 0; // open a file but force the data to come from the steam cache, NOT from disk - virtual FileHandle_t OpenFromCacheForRead( const char *pFileName, const char *pOptions, const char *pathID = 0L ) = 0; - - virtual void AddSearchPathNoWrite( const char *pPath, const char *pathID ) = 0; + virtual FileHandle_t OpenFromCacheForRead(const char *pFileName, const char *pOptions, const char *pathID = 0L) = 0; + virtual void AddSearchPathNoWrite(const char *pPath, const char *pathID) = 0; }; // Steam3/Src compat #define IBaseFileSystem IFileSystem #define FILESYSTEM_INTERFACE_VERSION "VFileSystem009" - -#endif // FILESYSTEM_H diff --git a/rehlds/public/HLTV/IBSPModel.h b/rehlds/public/HLTV/IBSPModel.h new file mode 100644 index 0000000..22a6438 --- /dev/null +++ b/rehlds/public/HLTV/IBSPModel.h @@ -0,0 +1,45 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +class IBaseSystem; +class IBSPModel { +public: + virtual ~IBSPModel() {}; + + virtual void Init(IBaseSystem *system) = 0; + virtual void Clear() = 0; + virtual bool Load(const char *name, bool minimal) = 0; + virtual bool IsValid() = 0; + virtual bool IsMinimal() = 0; + virtual void SetPVS(float *point) = 0; + virtual bool InPVS(float *point) = 0; + virtual bool TraceLine(float *start, float *end, float *impact) = 0; + virtual int TruePointContents(float *point) = 0; +}; diff --git a/rehlds/public/HLTV/IClient.h b/rehlds/public/HLTV/IClient.h new file mode 100644 index 0000000..fe51503 --- /dev/null +++ b/rehlds/public/HLTV/IClient.h @@ -0,0 +1,51 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +class IWorld; +class InfoString; +class IClient: virtual public ISystemModule { +public: + virtual ~IClient() {} + + virtual bool Connect(INetSocket *socket, NetAddress *adr, char *userinfo) = 0; + virtual void Send(unsigned char *data, int length, bool isReliable) = 0; + virtual void Disconnect(const char *reason = nullptr) = 0; + virtual void Reconnect() = 0; + virtual void SetWorld(IWorld *world) = 0; + virtual int GetClientType() = 0; + virtual char *GetClientName() = 0; + virtual InfoString *GetUserInfo() = 0; + virtual NetAddress *GetAddress() = 0; + virtual bool IsActive() = 0; + virtual bool IsHearingVoices() = 0; + virtual bool HasChatEnabled() = 0; +}; + +#define CLIENT_INTERFACE_VERSION "client001" diff --git a/rehlds/public/HLTV/IDirector.h b/rehlds/public/HLTV/IDirector.h new file mode 100644 index 0000000..b840662 --- /dev/null +++ b/rehlds/public/HLTV/IDirector.h @@ -0,0 +1,52 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "ISystemModule.h" + +class IWorld; +class IProxy; +class BitBuffer; +class DirectorCmd; +class IObjectContainer; + +class IDirector: virtual public ISystemModule { +public: + virtual ~IDirector() {} + + virtual void NewGame(IWorld *world, IProxy *proxy) = 0; + virtual char *GetModName() = 0; + virtual void WriteCommands(BitBuffer *stream, float startTime, float endTime) = 0; + virtual int AddCommand(DirectorCmd *cmd) = 0; + virtual bool RemoveCommand(int index) = 0; + virtual DirectorCmd *GetLastCommand() = 0; + virtual IObjectContainer *GetCommands() = 0; +}; + +#define DIRECTOR_INTERFACE_VERSION "director001" diff --git a/rehlds/public/HLTV/INetChannel.h b/rehlds/public/HLTV/INetChannel.h new file mode 100644 index 0000000..dad99f6 --- /dev/null +++ b/rehlds/public/HLTV/INetChannel.h @@ -0,0 +1,60 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +class INetSocket; +class IBaseSystem; +class INetChannel { +public: + virtual ~INetChannel() {} + + virtual bool Create(IBaseSystem *system, INetSocket *netsocket = nullptr, NetAddress *adr = nullptr) = 0; + virtual NetAddress *GetTargetAddress() = 0; + virtual void Close() = 0; + virtual void Clear() = 0; + virtual void Reset() = 0; + virtual bool IsConnected() = 0; + virtual bool IsReadyToSend() = 0; + virtual bool IsCrashed() = 0; + virtual bool IsTimedOut() = 0; + virtual bool IsFakeChannel() = 0; + virtual bool KeepAlive() = 0; + virtual void SetRate(int newRate) = 0; + virtual void SetUpdateRate(int newupdaterate) = 0; + virtual void SetTimeOut(float time) = 0; + virtual void SetKeepAlive(bool flag) = 0; + virtual float GetIdleTime() = 0; + virtual int GetRate() = 0; + virtual int GetUpdateRate() = 0; + virtual float GetLoss() = 0; + virtual void TransmitOutgoing() = 0; + virtual void ProcessIncoming(unsigned char *data, int size) = 0; + virtual void OutOfBandPrintf(const char *format, ...) = 0; + virtual void FakeAcknowledgement() = 0; +}; diff --git a/rehlds/public/HLTV/INetSocket.h b/rehlds/public/HLTV/INetSocket.h new file mode 100644 index 0000000..972d441 --- /dev/null +++ b/rehlds/public/HLTV/INetSocket.h @@ -0,0 +1,55 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +class INetwork; +class INetChannel; +class NetPacket; + +class INetSocket { +public: + virtual ~INetSocket() {}; + + virtual NetPacket *ReceivePacket() = 0; + virtual void FreePacket(NetPacket *packet) = 0; + virtual bool SendPacket(NetPacket *packet) = 0; + virtual bool SendPacket(NetAddress *to, const void *data, int length) = 0; + virtual void AddPacket(NetPacket *packet) = 0; + virtual bool AddChannel(INetChannel *channel) = 0; + virtual bool RemoveChannel(INetChannel *channel) = 0; + + virtual INetwork *GetNetwork() = 0; + virtual void OutOfBandPrintf(NetAddress *to, const char *format, ...) = 0; + virtual void Flush() = 0; + virtual void GetFlowStats(float *totalIn, float *totalOut) = 0; + virtual bool LeaveGroup(NetAddress *group) = 0; + virtual bool JoinGroup(NetAddress *group) = 0; + virtual void Close() = 0; + virtual int GetPort() = 0; +}; diff --git a/rehlds/public/HLTV/INetwork.h b/rehlds/public/HLTV/INetwork.h new file mode 100644 index 0000000..05c31a0 --- /dev/null +++ b/rehlds/public/HLTV/INetwork.h @@ -0,0 +1,62 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "ISystemModule.h" + +class INetSocket; +class INetwork { +public: + virtual ~INetwork() {}; + + virtual bool Init(IBaseSystem *system, int serial, char *name) = 0; + virtual void RunFrame(double time) = 0; + virtual void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) = 0; + virtual void ExecuteCommand(int commandID, char *commandLine) = 0; + virtual void RegisterListener(ISystemModule *module) = 0; + virtual void RemoveListener(ISystemModule *module) = 0; + virtual IBaseSystem *GetSystem() = 0; + virtual int GetSerial() = 0; + virtual char *GetStatusLine() = 0; + virtual char *GetType() = 0; + virtual char *GetName() = 0; + virtual int GetState() = 0; + virtual int GetVersion() = 0; + virtual void ShutDown() = 0; + + virtual INetSocket *CreateSocket(int port, bool reuse = false, bool loopback = false) = 0; + virtual bool RemoveSocket(INetSocket *netsocket) = 0; + virtual NetAddress *GetLocalAddress() = 0; + virtual bool ResolveAddress(char *string, NetAddress *address) = 0; + virtual void GetFlowStats(float *totalIn, float *totalOut) = 0; + virtual int GetLastErrorCode() = 0; + virtual char *GetErrorText(int code) = 0; +}; + +#define NETWORK_INTERFACE_VERSION "network001" diff --git a/rehlds/public/HLTV/IProxy.h b/rehlds/public/HLTV/IProxy.h new file mode 100644 index 0000000..6724897 --- /dev/null +++ b/rehlds/public/HLTV/IProxy.h @@ -0,0 +1,107 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "ISystemModule.h" +#include "custom.h" + +class IWorld; +class IServer; +class IDirector; +class INetSocket; +class BitBuffer; +class NetAddress; +class IObjectContainer; + +#define MAX_PROXY_CLIENTS 255 + +#define GROUP_CLIENT 0x00001 // Broadcast to client +#define GROUP_PROXY 0x00002 // Broadcast to proxy +#define GROUP_DEMO 0x00004 // Broadcast to demo file +#define GROUP_UNKNOWN 0x00008 // Broadcast to UNKNOWN: unused +#define GROUP_VOICE 0x00010 // Broadcast to voice enabled clients +#define GROUP_CHAT 0x00020 // Broadcast to chat enabled clients + +#define GROUP_CLIENT_ALL GROUP_CLIENT | GROUP_PROXY | GROUP_DEMO | GROUP_UNKNOWN + +enum ChatMode_e : int +{ + CHAT_OFF, // Spectators can't chat. + CHAT_LOCAL, // Only spectators connected to the same proxy can see their chat messages. + CHAT_GLOBAL, // All spectators can chat between each other (then Master and all Relay proxies must have set chatmode 2). +}; + +class IProxy: virtual public ISystemModule { +public: + virtual ~IProxy() {} + + virtual void Reset() = 0; + virtual void Broadcast(byte *data, int length, int groupType, bool isReliable) = 0; + virtual void IncreaseCheering(int votes) = 0; + virtual void ParseStatusMsg(BitBuffer *stream) = 0; + virtual void ParseStatusReport(NetAddress *from, BitBuffer *stream) = 0; + virtual bool ProcessConnectionlessMessage(NetAddress *from, BitBuffer *stream) = 0; + virtual void ChatCommentator(char *nick, char *text) = 0; + virtual void ChatSpectator(char *nick, char *text) = 0; + virtual void CountLocalClients(int &spectators, int &proxies) = 0; + virtual struct resource_s *AddResource(char *fileName, resourcetype_t type, char *asFileName = nullptr) = 0; + virtual bool IsLanOnly() = 0; + virtual bool IsMaster() = 0; + virtual bool IsActive() = 0; + virtual bool IsPublicGame() = 0; + virtual bool IsPasswordProtected() = 0; + virtual bool IsStressed() = 0; + virtual void SetDelay(float seconds) = 0; + virtual void SetClientTime(double time, bool relative) = 0; + virtual void SetClientTimeScale(float scale) = 0; + virtual void SetMaxRate(int rate) = 0; + virtual void SetMaxLoss(float maxloss) = 0; + virtual void SetMaxUpdateRate(int updaterate) = 0; + virtual bool SetMaxClients(int number) = 0; + virtual void SetRegion(unsigned char region) = 0; + virtual float GetDelay() = 0; + virtual double GetSpectatorTime() = 0; + virtual double GetProxyTime() = 0; + virtual int GetMaxClients() = 0; + virtual IWorld *GetWorld() = 0; + virtual IServer *GetServer() = 0; + virtual IDirector *GetDirector() = 0; + virtual INetSocket *GetSocket() = 0; + virtual ChatMode_e GetChatMode() = 0; + virtual void GetStatistics(int &proxies, int &slots, int &spectators) = 0; + virtual int GetMaxRate() = 0; + virtual int GetMaxUpdateRate() = 0; + virtual struct resource_s *GetResource(char *fileName) = 0; + virtual int GetDispatchMode() = 0; + virtual unsigned char GetRegion() = 0; + virtual IObjectContainer *GetClients() = 0; + virtual bool WriteSignonData(int type, BitBuffer *stream) = 0; +}; + +#define PROXY_INTERFACE_VERSION "proxy001" diff --git a/rehlds/public/HLTV/IServer.h b/rehlds/public/HLTV/IServer.h new file mode 100644 index 0000000..37640cf --- /dev/null +++ b/rehlds/public/HLTV/IServer.h @@ -0,0 +1,101 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "ISystemModule.h" + +class IWorld; +class IProxy; +class IDirector; +class INetSocket; +class ISystemModule; +class IBaseSystem; + +class NetAddress; +class InfoString; +class BitBuffer; + +class IServer { +public: + virtual ~IServer() {} + + virtual bool Init(IBaseSystem *system, int serial, char *name) = 0; + virtual void RunFrame(double time) = 0; + virtual void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) = 0; + virtual void ExecuteCommand(int commandID, char *commandLine) = 0; + virtual void RegisterListener(ISystemModule *module) = 0; + virtual void RemoveListener(ISystemModule *module) = 0; + virtual IBaseSystem *GetSystem() = 0; + virtual int GetSerial() = 0; + virtual char *GetStatusLine() = 0; + virtual char *GetType() = 0; + virtual char *GetName() = 0; + virtual int GetState() = 0; + virtual int GetVersion() = 0; + virtual void ShutDown() = 0; + + virtual bool Connect(IWorld *world, NetAddress *adr, INetSocket *socket) = 0; + virtual bool LoadDemo(IWorld *world, char *filename, bool forceHLTV, bool continuous) = 0; + virtual void Reconnect() = 0; + virtual void Disconnect() = 0; + virtual void Retry() = 0; + virtual void StopRetry() = 0; + virtual void SendStringCommand(char *command) = 0; + virtual void SendHLTVCommand(BitBuffer *msg) = 0; + virtual bool IsConnected() = 0; + virtual bool IsDemoFile() = 0; + virtual bool IsGameServer() = 0; + virtual bool IsRelayProxy() = 0; + virtual bool IsVoiceBlocking() = 0; + virtual void SetProxy(IProxy *proxy) = 0; + virtual void SetDirector(IDirector *director) = 0; + virtual void SetPlayerName(char *newName) = 0; + virtual void SetDelayReconnect(bool state) = 0; + virtual void SetAutoRetry(bool state) = 0; + virtual void SetVoiceBlocking(bool state) = 0; + virtual void SetRate(int rate) = 0; + virtual void SetUpdateRate(int updaterate) = 0; + virtual void SetUserInfo(char *key, char *value) = 0; + virtual bool SetProtocol(int version) = 0; + virtual void SetGameDirectory(const char *defaultDir, const char *gameDir = nullptr) = 0; + virtual int GetRate() = 0; + virtual int GetUpdateRate() = 0; + virtual InfoString *GetServerInfoString() = 0; + virtual char *GetPlayerName() = 0; + virtual float GetTime() = 0; + virtual IWorld *GetWorld() = 0; + virtual char *GetDemoFileName() = 0; + virtual NetAddress *GetAddress() = 0; + virtual char *GetHostName() = 0; + virtual bool GetAutoRetry() = 0; + virtual float GetPacketLoss() = 0; + virtual int GetProtocol() = 0; +}; + +#define SERVER_INTERFACE_VERSION "server001" diff --git a/rehlds/public/HLTV/IWorld.h b/rehlds/public/HLTV/IWorld.h new file mode 100644 index 0000000..8e24c26 --- /dev/null +++ b/rehlds/public/HLTV/IWorld.h @@ -0,0 +1,163 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "IBSPModel.h" +#include "IDirector.h" +#include "ISystemModule.h" +#include "common/ServerInfo.h" + +#include "pm_movevars.h" +#include "usermsg.h" +#include "entity_state.h" + +typedef struct frame_s +{ + float time; + unsigned int seqnr; + unsigned char *data; + void *entities; + unsigned int entitiesSize; + unsigned int entitynum; + void *clientData; + unsigned int clientDataSize; + unsigned char *events; + unsigned int eventsSize; + unsigned int eventnum; + unsigned char *reliableData; + unsigned int reliableDataSize; + unsigned char *unreliableData; + unsigned int unreliableDataSize; + unsigned char *userMessages; + unsigned int userMessagesSize; + unsigned char *voiceData; + unsigned int voiceDataSize; + unsigned char *demoData; + unsigned int demoDataSize; + void *demoInfo; + unsigned int delta; +} frame_t; + +class InfoString; +class NetAddress; + +class IWorld { +public: + virtual ~IWorld() {} + + virtual bool Init(IBaseSystem *system, int serial, char *name) = 0; + virtual void RunFrame(double time) = 0; + virtual void ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) = 0; + virtual void ExecuteCommand(int commandID, char *commandLine) = 0; + virtual void RegisterListener(ISystemModule *module) = 0; + virtual void RemoveListener(ISystemModule *module) = 0; + virtual IBaseSystem *GetSystem() = 0; + virtual int GetSerial() = 0; + virtual char *GetStatusLine() = 0; + virtual char *GetType() = 0; + virtual char *GetName() = 0; + virtual int GetState() = 0; + virtual int GetVersion() = 0; + virtual void ShutDown() = 0; + + virtual double GetTime() = 0; + virtual NetAddress *GetGameServerAddress() = 0; + virtual char *GetLevelName() = 0; + virtual char *GetGameDir() = 0; + virtual frame_t *GetFrameByTime(double time) = 0; + virtual frame_t *GetFrameBySeqNr(unsigned int seqnr) = 0; + virtual frame_t *GetLastFrame() = 0; + virtual frame_t *GetFirstFrame() = 0; + virtual int GetServerCount() = 0; + virtual int GetSlotNumber() = 0; + virtual int GetMaxClients() = 0; + virtual int GetNumPlayers() = 0; + virtual IBSPModel *GetWorldModel() = 0; + virtual InfoString *GetServerInfoString() = 0; + virtual bool GetPlayerInfoString(int playerNum, InfoString *infoString) = 0; + virtual UserMsg *GetUserMsg(int msgNumber) = 0; + virtual char *GetHostName() = 0; + virtual serverinfo_t *GetServerInfo() = 0; + virtual bool IsPlayerIndex(int index) = 0; + virtual bool IsVoiceEnabled() = 0; + virtual bool IsActive() = 0; + virtual bool IsPaused() = 0; + virtual bool IsComplete() = 0; + virtual bool IsHLTV() = 0; + virtual void Reset() = 0; + virtual void SetServerInfo(int protocol, CRC32_t nserverCRC, byte *nclientdllmd5, int nmaxclients, int nplayernum, int ngametype, char *ngamedir, char *nservername, char *nlevelname) = 0; + virtual void SetServerInfoString(char *infostring) = 0; + virtual void SetServerInfo(serverinfo_t *serverinfo) = 0; + virtual void UpdateServerInfo() = 0; + virtual void SetPaused(bool state) = 0; + virtual void SetTime(double newTime) = 0; + virtual void SetBufferSize(float seconds) = 0; + virtual void SetVoiceEnabled(bool state) = 0; + virtual void SetMoveVars(movevars_t *nmovevars) = 0; + virtual void SetCDInfo(int ncdtrack, int nlooptrack) = 0; + virtual void SetHLTV(bool state) = 0; + virtual void SetExtraInfo(char *nclientfallback, int nallowCheats) = 0; + virtual void SetViewEntity(int nviewentity) = 0; + virtual void SetGameServerAddress(NetAddress *address) = 0; + virtual void SetHostName(char *name) = 0; + virtual void NewGame(int newServerCount) = 0; + virtual void FinishGame() = 0; + virtual bool SaveAsDemo(char *filename, IDirector *director) = 0; + virtual void StopGame() = 0; + virtual int FindUserMsgByName(char *name) = 0; + virtual void ParseDeltaDescription(BitBuffer *stream) = 0; + virtual void ParseBaseline(BitBuffer *stream) = 0; + virtual void ParseEvent(BitBuffer *stream) = 0; + virtual void ParseClientData(BitBuffer *stream, unsigned int deltaSeqNr, BitBuffer *to, clientdata_t *clientData) = 0; + virtual bool GetUncompressedFrame(unsigned int seqNr, frame_t *frame) = 0; + virtual bool UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream) = 0; + virtual bool UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream, unsigned int from) = 0; + virtual bool GetClientData(unsigned int SeqNr, clientdata_t *clientData) = 0; + virtual bool GetClientData(frame_t *frame, clientdata_t *clientData) = 0; + virtual int AddFrame(frame_t *newFrame) = 0; + virtual bool AddResource(resource_t *resource) = 0; + virtual void AddLightStyle(int index, char *style) = 0; + virtual bool AddSignonData(unsigned char type, unsigned char *data, int size) = 0; + virtual bool AddUserMessage(int msgNumber, int size, char *name) = 0; + virtual void AddBaselineEntity(int index, entity_state_t *ent) = 0; + virtual void AddInstancedBaselineEntity(int index, entity_state_t *ent) = 0; + virtual void UpdatePlayer(int playerNum, int userId, char *infostring, char *hashedcdkey) = 0; + virtual void WriteFrame(frame_t *frame, unsigned int lastFrameSeqnr, BitBuffer *reliableStream, BitBuffer *unreliableStream, unsigned int deltaSeqNr, unsigned int clientDelta, bool addVoice) = 0; + virtual void WriteNewData(BitBuffer *stream) = 0; + virtual void WriteClientUpdate(BitBuffer *stream, int playerIndex) = 0; + virtual void WriteMovevars(BitBuffer *stream) = 0; + virtual void WriteSigonData(BitBuffer *stream) = 0; + virtual void WriteLightStyles(BitBuffer *stream) = 0; + virtual int RemoveFrames(unsigned int startSeqNr, unsigned int endSeqNr) = 0; + virtual int DuplicateFrames(unsigned int startSeqNr, unsigned int endSeqNr) = 0; + virtual int MoveFrames(unsigned int startSeqNr, unsigned int endSeqNr, double destSeqnr) = 0; + virtual int RevertFrames(unsigned int startSeqNr, unsigned int endSeqNr) = 0; +}; + +#define WORLD_INTERFACE_VERSION "world001" diff --git a/rehlds/public/engine_hlds_api.h b/rehlds/public/engine_hlds_api.h index 9613a0b..007237e 100644 --- a/rehlds/public/engine_hlds_api.h +++ b/rehlds/public/engine_hlds_api.h @@ -39,10 +39,9 @@ class IDedicatedServerAPI : public IBaseInterface { public: - virtual bool Init(char *basedir, char *cmdline, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory) = 0; - virtual int Shutdown(void) = 0; - virtual bool RunFrame(void) = 0; + virtual int Shutdown() = 0; + virtual bool RunFrame() = 0; virtual void AddConsoleText(char *text) = 0; virtual void UpdateStatus(float *fps, int *nActive, int *nMaxPlayers, char *pszMap) = 0; }; diff --git a/rehlds/public/idedicatedexports.h b/rehlds/public/idedicatedexports.h index 509cbbd..2444e22 100644 --- a/rehlds/public/idedicatedexports.h +++ b/rehlds/public/idedicatedexports.h @@ -1,25 +1,40 @@ -//========= Copyright 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ -#ifndef IDEDICATEDEXPORTS_H -#define IDEDICATEDEXPORTS_H -#ifdef _WIN32 #pragma once -#endif #include "interface.h" -class IDedicatedExports : IBaseInterface +class IDedicatedExports : public IBaseInterface { public: - virtual ~IDedicatedExports() { }; + virtual ~IDedicatedExports() {}; virtual void Sys_Printf(char *text) = 0; }; #define VENGINE_DEDICATEDEXPORTS_API_VERSION "VENGINE_DEDICATEDEXPORTS_API_VERSION001" - -#endif // IDEDICATEDEXPORTS_H diff --git a/rehlds/public/interface.cpp b/rehlds/public/interface.cpp index 2b62260..d5a35ad 100644 --- a/rehlds/public/interface.cpp +++ b/rehlds/public/interface.cpp @@ -1,26 +1,98 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + #include "interface.h" +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include "windows.h" +#endif // _WIN32 -#if !defined ( _WIN32 ) +// InterfaceReg +InterfaceReg *InterfaceReg::s_pInterfaceRegs = nullptr; + +InterfaceReg::InterfaceReg(InstantiateInterfaceFn fn, const char *pName) : m_pName(pName) +{ + m_CreateFn = fn; + m_pNext = s_pInterfaceRegs; + s_pInterfaceRegs = this; +} + +// This is the primary exported function by a dll, referenced by name via dynamic binding +// that exposes an opqaue function pointer to the interface. +// +// We have the Internal variant so Sys_GetFactoryThis() returns the correct internal +// symbol under GCC/Linux/Mac as CreateInterface is DLL_EXPORT so its global so the loaders +// on those OS's pick exactly 1 of the CreateInterface symbols to be the one that is process wide and +// all Sys_GetFactoryThis() calls find that one, which doesn't work. Using the internal walkthrough here +// makes sure Sys_GetFactoryThis() has the dll specific symbol and GetProcAddress() returns the module specific +// function for CreateInterface again getting the dll specific symbol we need. +EXPORT_FUNCTION IBaseInterface *CreateInterface(const char *pName, int *pReturnCode) +{ + InterfaceReg *pCur; + for (pCur = InterfaceReg::s_pInterfaceRegs; pCur; pCur = pCur->m_pNext) + { + if (strcmp(pCur->m_pName, pName) == 0) + { + if (pReturnCode) + { + *pReturnCode = IFACE_OK; + } + + return pCur->m_CreateFn(); + } + } + + if (pReturnCode) + { + *pReturnCode = IFACE_FAILED; + } + + return nullptr; +} + +#ifndef _WIN32 // Linux doesn't have this function so this emulates its functionality -// -// void *GetModuleHandle(const char *name) { void *handle; - - if (name == NULL) + if (name == nullptr) { // hmm, how can this be handled under linux.... // is it even needed? - return NULL; + return nullptr; } - if ((handle=dlopen(name, RTLD_NOW)) == NULL) + if ((handle = dlopen(name, RTLD_NOW)) == nullptr) { //printf("Error:%s\n",dlerror()); // couldn't open this file - return NULL; + return nullptr; } // read "man dlopen" for details @@ -29,121 +101,39 @@ void *GetModuleHandle(const char *name) dlclose(handle); return handle; } -#endif +#endif // _WIN32 -// ------------------------------------------------------------------------------------ // -// InterfaceReg. -// ------------------------------------------------------------------------------------ // -InterfaceReg *InterfaceReg::s_pInterfaceRegs = NULL; - - -InterfaceReg::InterfaceReg( InstantiateInterfaceFn fn, const char *pName ) : m_pName(pName) -{ - m_CreateFn = fn; - m_pNext = s_pInterfaceRegs; - s_pInterfaceRegs = this; -} - - - -// ------------------------------------------------------------------------------------ // -// CreateInterface. -// ------------------------------------------------------------------------------------ // -EXPORT_FUNCTION IBaseInterface *CreateInterface( const char *pName, int *pReturnCode ) -{ - InterfaceReg *pCur; - - for(pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext) - { - if(strcmp(pCur->m_pName, pName) == 0) - { - if ( pReturnCode ) - { - *pReturnCode = IFACE_OK; - } - return pCur->m_CreateFn(); - } - } - - if ( pReturnCode ) - { - *pReturnCode = IFACE_FAILED; - } - return NULL; -} - -#ifdef LINUX -static IBaseInterface *CreateInterfaceLocal( const char *pName, int *pReturnCode ) -{ - InterfaceReg *pCur; - - for(pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext) - { - if(strcmp(pCur->m_pName, pName) == 0) - { - if ( pReturnCode ) - { - *pReturnCode = IFACE_OK; - } - return pCur->m_CreateFn(); - } - } - - if ( pReturnCode ) - { - *pReturnCode = IFACE_FAILED; - } - return NULL; -} -#endif - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include "windows.h" -#endif - -//----------------------------------------------------------------------------- // Purpose: returns a pointer to a function, given a module // Input : pModuleName - module name // *pName - proc name -//----------------------------------------------------------------------------- -//static hlds_run wants to use this function -void *Sys_GetProcAddress( const char *pModuleName, const char *pName ) +//static hlds_run wants to use this function +void *Sys_GetProcAddress(const char *pModuleName, const char *pName) { - return GetProcAddress( GetModuleHandle(pModuleName), pName ); + return GetProcAddress(GetModuleHandle(pModuleName), pName); } -//----------------------------------------------------------------------------- // Purpose: returns a pointer to a function, given a module // Input : pModuleName - module name // *pName - proc name -//----------------------------------------------------------------------------- -// hlds_run wants to use this function -void *Sys_GetProcAddress( void *pModuleHandle, const char *pName ) +// hlds_run wants to use this function +void *Sys_GetProcAddress(void *pModuleHandle, const char *pName) { -#if defined ( _WIN32 ) - return GetProcAddress( (HINSTANCE)pModuleHandle, pName ); -#else - return GetProcAddress( pModuleHandle, pName ); -#endif + return GetProcAddress((HMODULE)pModuleHandle, pName); } -//----------------------------------------------------------------------------- // Purpose: Loads a DLL/component from disk and returns a handle to it // Input : *pModuleName - filename of the component // Output : opaque handle to the module (hides system dependency) -//----------------------------------------------------------------------------- CSysModule *Sys_LoadModule(const char *pModuleName) { -#if defined (_WIN32) +#ifdef _WIN32 HMODULE hDLL = LoadLibrary(pModuleName); #else - HMODULE hDLL = NULL; + HMODULE hDLL = nullptr; + char szAbsoluteModuleName[1024]; if (pModuleName[0] != '/') { char szCwd[1024]; - char szAbsoluteModuleName[1024]; - getcwd(szCwd, sizeof(szCwd)); if (szCwd[strlen(szCwd) - 1] == '/') szCwd[strlen(szCwd) - 1] = '\0'; @@ -153,118 +143,94 @@ CSysModule *Sys_LoadModule(const char *pModuleName) } else { + _snprintf(szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s", pModuleName); hDLL = dlopen(pModuleName, RTLD_NOW); } -#endif +#endif // _WIN32 - if(!hDLL) + if (!hDLL) { - char szPathModule[MAX_PATH]; - char szModuleName[64]; + char str[512]; - strncpy(szModuleName, pModuleName, sizeof szModuleName - 1); - szModuleName[sizeof szModuleName - 1] = '\0'; - - // remove extension if provided. - char *ext = strrchr(szModuleName, '.'); - if (ext) { - *ext = '\0'; - } - -#if defined (_WIN32) - _snprintf(szPathModule, sizeof(szPathModule), "%s.dll", szModuleName); - hDLL = LoadLibrary(szPathModule); +#if defined(_WIN32) + _snprintf(str, sizeof(str), "%s.dll", pModuleName); + hDLL = LoadLibrary(str); #elif defined(OSX) printf("Error: %s\n", dlerror()); - _snprintf(szPathModule, sizeof(szPathModule), "%s.dylib", szModuleName); - hDLL = dlopen(szPathModule, RTLD_NOW); + _snprintf(str, sizeof(str), "%s.dylib", szAbsoluteModuleName); + hDLL = dlopen(str, RTLD_NOW); #else printf("Error: %s\n", dlerror()); - _snprintf(szPathModule, sizeof(szPathModule), "%s.so", szModuleName); - hDLL = dlopen(szPathModule, RTLD_NOW); + _snprintf(str, sizeof(str), "%s.so", szAbsoluteModuleName); + hDLL = dlopen(str, RTLD_NOW); #endif } return reinterpret_cast(hDLL); } -//----------------------------------------------------------------------------- // Purpose: Unloads a DLL/component from // Input : *pModuleName - filename of the component // Output : opaque handle to the module (hides system dependency) -//----------------------------------------------------------------------------- -void Sys_UnloadModule( CSysModule *pModule ) +void Sys_UnloadModule(CSysModule *pModule) { - if ( !pModule ) + if (!pModule) return; HMODULE hDLL = reinterpret_cast(pModule); -#if defined ( _WIN32 ) - FreeLibrary( hDLL ); -#else - dlclose((void *)hDLL); -#endif +#ifdef _WIN32 + FreeLibrary(hDLL); +#else + dlclose(hDLL); +#endif // _WIN32 } -//----------------------------------------------------------------------------- // Purpose: returns a pointer to a function, given a module -// Input : module - windows HMODULE from Sys_LoadModule() +// Input : module - windows HMODULE from Sys_LoadModule() // *pName - proc name // Output : factory for this module -//----------------------------------------------------------------------------- -CreateInterfaceFn Sys_GetFactory( CSysModule *pModule ) +CreateInterfaceFn Sys_GetFactory(CSysModule *pModule) { - if ( !pModule ) - return NULL; + if (!pModule) + return nullptr; - HMODULE hDLL = reinterpret_cast(pModule); -#if defined ( _WIN32 ) - return reinterpret_cast(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME )); -#else -// Linux gives this error: -//../public/interface.cpp: In function `IBaseInterface *(*Sys_GetFactory -//(CSysModule *)) (const char *, int *)': -//../public/interface.cpp:154: ISO C++ forbids casting between -//pointer-to-function and pointer-to-object -// -// so lets get around it :) - return (CreateInterfaceFn)(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME )); -#endif + return reinterpret_cast(Sys_GetProcAddress(pModule, CREATEINTERFACE_PROCNAME)); } - - -//----------------------------------------------------------------------------- // Purpose: returns the instance of this module -// Output : interface_instance_t -//----------------------------------------------------------------------------- -CreateInterfaceFn Sys_GetFactoryThis( void ) +// Output : CreateInterfaceFn +CreateInterfaceFn Sys_GetFactoryThis() { -#ifdef LINUX - return CreateInterfaceLocal; -#else return CreateInterface; -#endif } -//----------------------------------------------------------------------------- // Purpose: returns the instance of the named module // Input : *pModuleName - name of the module -// Output : interface_instance_t - instance of that module -//----------------------------------------------------------------------------- -CreateInterfaceFn Sys_GetFactory( const char *pModuleName ) +// Output : CreateInterfaceFn - instance of that module +CreateInterfaceFn Sys_GetFactory(const char *pModuleName) { -#if defined ( _WIN32 ) - return static_cast( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) ); -#else -// Linux gives this error: -//../public/interface.cpp: In function `IBaseInterface *(*Sys_GetFactory -//(const char *)) (const char *, int *)': -//../public/interface.cpp:186: invalid static_cast from type `void *' to -//type `IBaseInterface *(*) (const char *, int *)' -// -// so lets use the old style cast. - return (CreateInterfaceFn)( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) ); -#endif + return reinterpret_cast(Sys_GetProcAddress(pModuleName, CREATEINTERFACE_PROCNAME)); +} + +// Purpose: finds a particular interface in the factory set +void *InitializeInterface(char const *interfaceName, CreateInterfaceFn *factoryList, int numFactories) +{ + void *retval; + + for (int i = 0; i < numFactories; i++) + { + CreateInterfaceFn factory = factoryList[ i ]; + if (!factory) + continue; + + retval = factory(interfaceName, nullptr); + if (retval) + return retval; + } + + // No provider for requested interface!!! + // assert(!"No provider for requested interface!!!"); + + return nullptr; } diff --git a/rehlds/public/interface.h b/rehlds/public/interface.h index cdd361e..dc424be 100644 --- a/rehlds/public/interface.h +++ b/rehlds/public/interface.h @@ -1,4 +1,3 @@ - // This header defines the interface convention used in the valve engine. // To make an interface and expose it: // 1. Derive from IBaseInterface. @@ -14,16 +13,11 @@ // for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and // expose it for the old interface. -//#if _MSC_VER >= 1300 // VC7 -//#include "tier1/interface.h" -//#else +#pragma once -#ifndef INTERFACE_H -#define INTERFACE_H +#ifndef _WIN32 -#if !defined ( _WIN32 ) - -#include // dlopen,dlclose, et al +#include // dlopen, dlclose, et al #include #define HMODULE void * @@ -31,7 +25,7 @@ #define _snprintf snprintf -#endif +#endif // _WIN32 void *Sys_GetProcAddress(const char *pModuleName, const char *pName); void *Sys_GetProcAddress(void *pModuleHandle, const char *pName); @@ -40,17 +34,13 @@ void *Sys_GetProcAddress(void *pModuleHandle, const char *pName); class IBaseInterface { public: - - virtual ~IBaseInterface() {} + virtual ~IBaseInterface() {} }; +#define CREATEINTERFACE_PROCNAME "CreateInterface" -#define CREATEINTERFACE_PROCNAME "CreateInterface" -typedef IBaseInterface* (*CreateInterfaceFn)(const char *pName, int *pReturnCode); - - -typedef IBaseInterface* (*InstantiateInterfaceFn)(); - +typedef IBaseInterface *(*CreateInterfaceFn)(const char *pName, int *pReturnCode); +typedef IBaseInterface *(*InstantiateInterfaceFn)(); // Used internally to register classes. class InterfaceReg @@ -60,19 +50,18 @@ public: public: - InstantiateInterfaceFn m_CreateFn; - const char *m_pName; + InstantiateInterfaceFn m_CreateFn; + const char *m_pName; - InterfaceReg *m_pNext; // For the global list. - static InterfaceReg *s_pInterfaceRegs; + InterfaceReg *m_pNext; // For the global list. + static InterfaceReg *s_pInterfaceRegs; }; - // Use this to expose an interface that can have multiple instances. // e.g.: -// EXPOSE_INTERFACE( CInterfaceImp, IInterface, "MyInterface001" ) +// EXPOSE_INTERFACE(CInterfaceImp, IInterface, "MyInterface001") // This will expose a class called CInterfaceImp that implements IInterface (a pure class) -// clients can receive a pointer to this class by calling CreateInterface( "MyInterface001" ) +// clients can receive a pointer to this class by calling CreateInterface("MyInterface001") // // In practice, the shared header file defines the interface (IInterface) and version name ("MyInterface001") // so that each component can use these names/vtables to communicate @@ -80,30 +69,28 @@ public: // A single class can support multiple interfaces through multiple inheritance // // Use this if you want to write the factory function. -#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName)\ static InterfaceReg __g_Create##className##_reg(functionName, versionName); -#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ - static IBaseInterface* __Create##className##_interface() {return (interfaceName *)new className;}\ - static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); +#define EXPOSE_INTERFACE(className, interfaceName, versionName)\ + static IBaseInterface *__Create##className##_interface() {return (interfaceName *)new className;}\ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName); // Use this to expose a singleton interface with a global variable you've created. -#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ - static IBaseInterface* __Create##className##interfaceName##_interface() {return (IBaseInterface *)&globalVarName;}\ +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName)\ + static IBaseInterface *__Create##className##interfaceName##_interface() {return (IBaseInterface *)&globalVarName;}\ static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); // Use this to expose a singleton interface. This creates the global variable for you automatically. -#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName)\ static className __g_##className##_singleton;\ EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) - #ifdef _WIN32 #define EXPORT_FUNCTION __declspec(dllexport) #else - #define EXPORT_FUNCTION __attribute__ ((visibility("default"))) -#endif - + #define EXPORT_FUNCTION __attribute__((visibility("default"))) +#endif // _WIN32 // This function is automatically exported and allows you to access any interfaces exposed with the above macros. // if pReturnCode is set, it will return one of the following values @@ -114,37 +101,23 @@ enum IFACE_FAILED }; - extern "C" { - EXPORT_FUNCTION IBaseInterface* CreateInterface(const char *pName, int *pReturnCode); + EXPORT_FUNCTION IBaseInterface *CreateInterface(const char *pName, int *pReturnCode); }; +extern CreateInterfaceFn Sys_GetFactoryThis(); -extern CreateInterfaceFn Sys_GetFactoryThis( void ); - - -//----------------------------------------------------------------------------- // UNDONE: This is obsolete, use the module load/unload/get instead!!! -//----------------------------------------------------------------------------- -extern CreateInterfaceFn Sys_GetFactory( const char *pModuleName ); - +extern CreateInterfaceFn Sys_GetFactory(const char *pModuleName); // load/unload components class CSysModule; -//----------------------------------------------------------------------------- // Load & Unload should be called in exactly one place for each module // The factory for that module should be passed on to dependent components for // proper versioning. -//----------------------------------------------------------------------------- -extern CSysModule *Sys_LoadModule( const char *pModuleName ); -extern void Sys_UnloadModule( CSysModule *pModule ); - -extern CreateInterfaceFn Sys_GetFactory( CSysModule *pModule ); - - -#endif -//#endif // MSVC 6.0 - - +extern CSysModule *Sys_LoadModule(const char *pModuleName); +extern void Sys_UnloadModule(CSysModule *pModule); +extern CreateInterfaceFn Sys_GetFactory(CSysModule *pModule); +extern void *InitializeInterface(char const *interfaceName, CreateInterfaceFn *factoryList, int numFactories); diff --git a/rehlds/public/rehlds/custom.h b/rehlds/public/rehlds/custom.h index 7422638..d2ebd48 100644 --- a/rehlds/public/rehlds/custom.h +++ b/rehlds/public/rehlds/custom.h @@ -63,7 +63,14 @@ typedef struct resourceinfo_s typedef struct resource_s { +#ifdef HOOK_HLTV + // NOTE HLTV: array szFileName declared on 260 cell, + // this changes necessary for compatibility hookers. + char szFileName[MAX_PATH]; +#else char szFileName[MAX_QPATH]; // File name to download/precache. +#endif // HOOK_HLTV + resourcetype_t type; // t_sound, t_skin, t_model, t_decal. int nIndex; // For t_decals int nDownloadSize; // Size in Bytes if this must be downloaded. diff --git a/rehlds/public/savegame_version.h b/rehlds/public/savegame_version.h index 51eb768..9cbbd91 100644 --- a/rehlds/public/savegame_version.h +++ b/rehlds/public/savegame_version.h @@ -1,20 +1,35 @@ -//========= Copyright 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ -#if !defined( SAVEGAME_VERSION_H ) -#define SAVEGAME_VERSION_H -#ifdef _WIN32 #pragma once -#endif #include "commonmacros.h" #define SAVEFILE_HEADER MAKEID('V','A','L','V') // little-endian "VALV" #define SAVEGAME_HEADER MAKEID('J','S','A','V') // little-endian "JSAV" -#define SAVEGAME_VERSION 0x0071 // Version 0.71 - -#endif // SAVEGAME_VERSION_H +#define SAVEGAME_VERSION 0x0071 // Version 0.71 diff --git a/rehlds/public/vgui/VGUI.h b/rehlds/public/vgui/VGUI.h index 50cf372..cdaed0d 100644 --- a/rehlds/public/vgui/VGUI.h +++ b/rehlds/public/vgui/VGUI.h @@ -1,12 +1,13 @@ -#ifndef VGUI_H -#define VGUI_H -#ifdef _WIN32 #pragma once -#endif + +#ifdef _WIN32 + #define VGUI2_LIB "vgui2.dll" +#else + #define VGUI2_LIB "vgui2.so" +#endif // _WIN32 namespace vgui2 { - // handle to an internal vgui panel // this is the only handle to a panel that is valid across dll boundaries typedef unsigned int VPANEL; @@ -26,6 +27,4 @@ const VPANEL NULL_PANEL = 0; const HFont INVALID_FONT = 0; const HPanel INVALID_PANEL = 0xffffffff; -} // namespace vgui - -#endif // VGUI_H +} // namespace vgui2 diff --git a/settings.gradle b/settings.gradle index 4879f1d..e8ab98c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,4 +3,5 @@ include 'dep/cppunitlite' include 'dep/bzip2' include 'rehlds' include 'rehlds/dedicated' +include 'rehlds/HLTV', 'rehlds/HLTV/Core', 'rehlds/HLTV/Proxy', 'rehlds/HLTV/Console', 'rehlds/HLTV/Director', 'rehlds/HLTV/DemoPlayer' include 'flightrec/decoder_api', 'flightrec/decoder' diff --git a/shared_gcc.gradle b/shared_gcc.gradle index 31159d8..2426a19 100644 --- a/shared_gcc.gradle +++ b/shared_gcc.gradle @@ -58,5 +58,6 @@ rootProject.ext.createGccConfig = { boolean release, BinaryKind binKind -> ) } + cfg.singleDefines('LINUX') return cfg } diff --git a/shared_icc.gradle b/shared_icc.gradle index 894a63c..036fa00 100644 --- a/shared_icc.gradle +++ b/shared_icc.gradle @@ -58,5 +58,6 @@ rootProject.ext.createIccConfig = { boolean release, BinaryKind binKind -> ) } + cfg.singleDefines('LINUX') return cfg }