From bb2bb4453f7b756dfc88dbe9510fa7bb1aa12a32 Mon Sep 17 00:00:00 2001 From: s1lent Date: Thu, 21 Sep 2017 23:43:22 +0700 Subject: [PATCH] Enhanced rechecker api --- Makefile | 15 +- common/BaseSystemModule.cpp | 154 ++++++++ common/BaseSystemModule.h | 75 ++++ common/IAdminServer.h | 54 +++ common/IBaseSystem.h | 91 +++++ common/IDemoPlayer.h | 93 +++++ common/IEngineWrapper.h | 71 ++++ common/IObjectContainer.h | 47 +++ common/ISystemModule.h | 57 +++ common/IVGuiModule.h | 76 ++++ common/ObjectDictionary.cpp | 515 ++++++++++++++++++++++++++ common/ObjectDictionary.h | 94 +++++ common/ObjectList.cpp | 259 +++++++++++++ common/ObjectList.h | 65 ++++ common/SteamAppStartUp.cpp | 211 +++++++++++ common/SteamAppStartUp.h | 37 ++ common/TextConsoleUnix.cpp | 324 ++++++++++++++++ common/TextConsoleUnix.h | 59 +++ common/TextConsoleWin32.cpp | 280 ++++++++++++++ common/TextConsoleWin32.h | 61 ++++ common/TokenLine.cpp | 132 +++++++ common/TokenLine.h | 51 +++ common/commandline.cpp | 354 ++++++++++++++++++ common/crc.h | 17 - common/entity_state.h | 5 +- common/enums.h | 7 +- common/hltv.h | 11 +- common/icommandline.h | 25 ++ common/kbutton.h | 3 - common/mathlib.h | 73 ++-- common/md5.h | 34 ++ common/netadr.h | 10 +- common/netapi.cpp | 208 +++++++++++ common/netapi.h | 25 ++ common/qlimits.h | 6 +- common/quakedef.h | 5 +- common/stdc++compat.cpp | 33 ++ common/textconsole.cpp | 394 ++++++++++++++++++++ common/textconsole.h | 93 +++++ common/vmodes.h | 2 - engine/cmd_rehlds.h | 2 +- engine/consistency.h | 11 +- engine/custom.h | 20 +- engine/eiface.h | 18 +- engine/maintypes.h | 24 +- engine/model.h | 4 +- engine/osconfig.h | 39 +- engine/rehlds_api.h | 4 +- engine/static_map.h | 2 +- engine/sys_shared.cpp | 4 +- msvc/rechecker.vcxproj | 8 +- msvc/rechecker.vcxproj.filters | 7 +- pm_shared/pm_defs.h | 2 +- public/FileSystem.h | 196 +++++----- public/engine_hlds_api.h | 12 +- public/engine_launcher_api.h | 14 +- public/icommandline.h | 47 +++ public/idedicatedexports.h | 43 ++- public/interface.cpp | 328 ++++++++--------- public/interface.h | 95 ++--- public/keydefs.h | 2 +- public/pman_particlemem.h | 2 +- public/savegame_version.h | 41 ++- public/tier0/dbg.cpp | 435 ++++++++++++++++++++++ public/tier0/dbg.h | 453 +++++++++++++++++++++++ public/tier0/mem.h | 37 ++ public/tier0/memalloc.h | 77 ++++ public/tier0/memdbgoff.h | 21 ++ public/tier0/memdbgon.h | 93 +++++ public/tier0/platform.h | 630 ++++++++++++++++++++++++++++++++ public/tier0/platform_linux.cpp | 59 +++ public/tier0/platform_win32.cpp | 95 +++++ public/utlbuffer.cpp | 2 +- public/utlmemory.h | 2 +- public/utlrbtree.h | 2 +- src/cmdexec.cpp | 8 +- src/cmdexec.h | 4 +- src/config.cpp | 4 +- src/config.h | 2 +- src/dllapi.cpp | 11 +- src/engine_api.cpp | 6 +- src/engine_rehlds.cpp | 12 +- src/hookchains_impl.cpp | 20 +- src/hookchains_impl.h | 50 +-- src/main.cpp | 54 ++- src/main.h | 2 + src/precompiled.h | 17 +- src/public_amalgamation.cpp | 3 + src/rechecker_api.h | 72 ++-- src/rechecker_api_impl.cpp | 110 ++++-- src/rechecker_api_impl.h | 54 ++- src/resource.cpp | 197 +++++++--- src/resource.h | 34 +- 93 files changed, 6885 insertions(+), 732 deletions(-) create mode 100644 common/BaseSystemModule.cpp create mode 100644 common/BaseSystemModule.h create mode 100644 common/IAdminServer.h create mode 100644 common/IBaseSystem.h create mode 100644 common/IDemoPlayer.h create mode 100644 common/IEngineWrapper.h create mode 100644 common/IObjectContainer.h create mode 100644 common/ISystemModule.h create mode 100644 common/IVGuiModule.h create mode 100644 common/ObjectDictionary.cpp create mode 100644 common/ObjectDictionary.h create mode 100644 common/ObjectList.cpp create mode 100644 common/ObjectList.h create mode 100644 common/SteamAppStartUp.cpp create mode 100644 common/SteamAppStartUp.h create mode 100644 common/TextConsoleUnix.cpp create mode 100644 common/TextConsoleUnix.h create mode 100644 common/TextConsoleWin32.cpp create mode 100644 common/TextConsoleWin32.h create mode 100644 common/TokenLine.cpp create mode 100644 common/TokenLine.h create mode 100644 common/commandline.cpp create mode 100644 common/icommandline.h create mode 100644 common/md5.h create mode 100644 common/netapi.cpp create mode 100644 common/netapi.h create mode 100644 common/stdc++compat.cpp create mode 100644 common/textconsole.cpp create mode 100644 common/textconsole.h create mode 100644 public/icommandline.h create mode 100644 public/tier0/dbg.cpp create mode 100644 public/tier0/dbg.h create mode 100644 public/tier0/mem.h create mode 100644 public/tier0/memalloc.h create mode 100644 public/tier0/memdbgoff.h create mode 100644 public/tier0/memdbgon.h create mode 100644 public/tier0/platform.h create mode 100644 public/tier0/platform_linux.cpp create mode 100644 public/tier0/platform_win32.cpp create mode 100644 src/public_amalgamation.cpp diff --git a/Makefile b/Makefile index 072e271..b27a998 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,12 @@ NAME = rechecker COMPILER = /opt/intel/bin/icpc +BIN_SUFFIX = i386 OBJECTS = src/main.cpp src/meta_api.cpp src/dllapi.cpp src/cmdexec.cpp \ src/engine_rehlds.cpp src/h_export.cpp src/resource.cpp \ src/sdk_util.cpp src/hookchains_impl.cpp src/rechecker_api_impl.cpp public/interface.cpp -LINK = -lm -ldl -static-intel -static-libgcc -no-intel-extensions +LINK = -lm -ldl -static-intel -static-libgcc -no-intel-extensions -fno-exceptions OPT_FLAGS = -O3 -msse3 -ipo -no-prec-div -fp-model fast=2 -funroll-loops -fomit-frame-pointer -fno-stack-protector @@ -17,7 +18,7 @@ CFLAGS = $(OPT_FLAGS) CFLAGS += -g0 -fvisibility=hidden -DNOMINMAX -fvisibility-inlines-hidden\ -DNDEBUG -Dlinux -D__linux__ -std=c++11 -shared -wd147,274 -fasm-blocks\ -Qoption,cpp,--treat_func_as_string_literal_cpp -fno-rtti\ - -D_byteswap_ulong=_bswap + -D_byteswap_ulong=_bswap -D_mkdir=mkdir -D_stricmp=strcasecmp OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) @@ -28,15 +29,15 @@ all: mkdir -p $(BIN_DIR) mkdir -p $(BIN_DIR)/sdk - $(MAKE) $(NAME) && strip -x $(BIN_DIR)/$(NAME)_mm_i386.so + $(MAKE) $(NAME) && strip -x $(BIN_DIR)/$(NAME)_mm_$(BIN_SUFFIX).so $(NAME): $(OBJ_LINUX) - $(COMPILER) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -o$(BIN_DIR)/$(NAME)_mm_i386.so + $(COMPILER) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -o$(BIN_DIR)/$(NAME)_mm_$(BIN_SUFFIX).so check: cppcheck $(INCLUDE) --quiet --max-configs=100 -D__linux__ -DNDEBUG -DHAVE_STDINT_H . -debug: +debug: $(MAKE) all DEBUG=false default: all @@ -44,6 +45,4 @@ default: all clean: rm -rf Release/sdk/*.o rm -rf Release/*.o - rm -rf Release/$(NAME)_mm_i386.so - - + rm -rf Release/$(NAME)_mm_$(BIN_SUFFIX).so diff --git a/common/BaseSystemModule.cpp b/common/BaseSystemModule.cpp new file mode 100644 index 0000000..b5ba97e --- /dev/null +++ b/common/BaseSystemModule.cpp @@ -0,0 +1,154 @@ +/* +* +* 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 *BaseSystemModule::GetName() +{ + return m_Name; +} + +char *BaseSystemModule::GetType() +{ + return "GenericModule"; +} + +char *BaseSystemModule::GetStatusLine() +{ + return "No status available.\n"; +} + +void BaseSystemModule::ExecuteCommand(int commandID, char *commandLine) +{ + m_System->DPrintf("WARNING! Undeclared ExecuteCommand().\n"); +} + +extern int COM_BuildNumber(); + +int BaseSystemModule::GetVersion() +{ + return COM_BuildNumber(); +} + +int BaseSystemModule::GetSerial() +{ + return m_Serial; +} + +IBaseSystem *BaseSystemModule::GetSystem() +{ + return m_System; +} + +bool BaseSystemModule::Init(IBaseSystem *system, int serial, char *name) +{ + if (!system) + return false; + + m_State = MODULE_INITIALIZING; + m_System = system; + m_Serial = serial; + m_SystemTime = 0; + + if (name) { + strcopy(m_Name, name); + } + + return true; +} + +void BaseSystemModule::RunFrame(double time) +{ + m_SystemTime = time; +} + +void BaseSystemModule::ShutDown() +{ + if (m_State == MODULE_DISCONNECTED) + return; + + m_Listener.Clear(); + m_State = MODULE_DISCONNECTED; + + if (!m_System->RemoveModule(this)) + { + m_System->DPrintf("ERROR! BaseSystemModule::ShutDown: faild to remove module %s.\n", m_Name); + } +} + +void BaseSystemModule::RegisterListener(ISystemModule *module) +{ + ISystemModule *listener = (ISystemModule *)m_Listener.GetFirst(); + while (listener) + { + if (listener->GetSerial() == module->GetSerial()) + { + m_System->DPrintf("WARNING! BaseSystemModule::RegisterListener: module %s already added.\n", module->GetName()); + return; + } + + listener = (ISystemModule *)m_Listener.GetNext(); + } + + m_Listener.Add(module); +} + +void BaseSystemModule::RemoveListener(ISystemModule *module) +{ + ISystemModule *listener = (ISystemModule *)m_Listener.GetFirst(); + while (listener) + { + if (listener->GetSerial() == module->GetSerial()) + { + m_Listener.Remove(module); + return; + } + + listener = (ISystemModule *)m_Listener.GetNext(); + } +} + +void BaseSystemModule::FireSignal(unsigned int signal, void *data) +{ + ISystemModule *listener = (ISystemModule *)m_Listener.GetFirst(); + while (listener) + { + listener->ReceiveSignal(this, signal, data); + listener = (ISystemModule *)m_Listener.GetNext(); + } +} + +void BaseSystemModule::ReceiveSignal(ISystemModule *module, unsigned int signal, void *data) +{ + m_System->DPrintf("WARNING! Unhandled signal (%i) from module %s.\n", signal, module->GetName()); +} + +int BaseSystemModule::GetState() +{ + return m_State; +} diff --git a/common/BaseSystemModule.h b/common/BaseSystemModule.h new file mode 100644 index 0000000..385c418 --- /dev/null +++ b/common/BaseSystemModule.h @@ -0,0 +1,75 @@ +/* +* +* 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 "ObjectList.h" +#include "IBaseSystem.h" + +// C4250 - 'class1' : inherits 'BaseSystemModule::member' via dominance +#pragma warning(disable:4250) + +class BaseSystemModule: virtual public ISystemModule { +public: + BaseSystemModule() : m_State(MODULE_UNDEFINED) {} + virtual ~BaseSystemModule() {} + + 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 void RegisterListener(ISystemModule *module); + virtual void RemoveListener(ISystemModule *module); + virtual IBaseSystem *GetSystem(); + virtual int GetSerial(); + 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 *GetBaseDir() { return ""; } + void FireSignal(unsigned int signal, void *data = nullptr); + +protected: + IBaseSystem *m_System; + ObjectList m_Listener; + char m_Name[255]; + unsigned int m_State; + unsigned int m_Serial; + double m_SystemTime; +}; diff --git a/common/IAdminServer.h b/common/IAdminServer.h new file mode 100644 index 0000000..ab367ce --- /dev/null +++ b/common/IAdminServer.h @@ -0,0 +1,54 @@ +/* +* +* 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 "interface.h" + +// handle to a game window +typedef unsigned int ManageServerUIHandle_t; +class IManageServer; + +// Purpose: Interface to server administration functions +class IAdminServer: public IBaseInterface +{ +public: + // opens a manage server dialog for a local server + virtual ManageServerUIHandle_t OpenManageServerDialog(const char *serverName, const char *gameDir) = 0; + + // opens a manage server dialog to a remote server + virtual ManageServerUIHandle_t OpenManageServerDialog(unsigned int gameIP, unsigned int gamePort, const char *password) = 0; + + // forces the game info dialog closed + virtual void CloseManageServerDialog(ManageServerUIHandle_t gameDialog) = 0; + + // Gets a handle to the interface + virtual IManageServer *GetManageServerInterface(ManageServerUIHandle_t handle) = 0; +}; + +#define ADMINSERVER_INTERFACE_VERSION "AdminServer002" diff --git a/common/IBaseSystem.h b/common/IBaseSystem.h new file mode 100644 index 0000000..9f50fe3 --- /dev/null +++ b/common/IBaseSystem.h @@ -0,0 +1,91 @@ +/* +* +* 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 + +#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" + +class Panel; +class ObjectList; +class IFileSystem; + +class IBaseSystem: virtual public ISystemModule { +public: + virtual ~IBaseSystem() {} + + virtual double GetTime() = 0; + virtual unsigned int GetTick() = 0; + virtual void SetFPS(float fps) = 0; + + virtual void Printf(char *fmt, ...) = 0; + virtual void DPrintf(char *fmt, ...) = 0; + + virtual void RedirectOutput(char *buffer = nullptr, int maxSize = 0) = 0; + + virtual IFileSystem *GetFileSystem() = 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; + virtual void SetStatusLine(char *text) = 0; + + virtual void ShowConsole(bool visible) = 0; + virtual void LogConsole(char *filename) = 0; + + virtual bool InitVGUI(IVGuiModule *module) = 0; + +#ifdef _WIN32 + virtual Panel *GetPanel() = 0; +#endif // _WIN32 + + virtual bool RegisterCommand(char *name, ISystemModule *module, int commandID) = 0; + virtual void GetCommandMatches(char *string, ObjectList *pMatchList) = 0; + virtual void ExecuteString(char *commands) = 0; + virtual void ExecuteFile(char *filename) = 0; + virtual void Errorf(char *fmt, ...) = 0; + + virtual char *CheckParam(char *param) = 0; + + virtual bool AddModule(ISystemModule *module, char *name) = 0; + virtual ISystemModule *GetModule(char *interfacename, char *library, char *instancename = nullptr) = 0; + virtual bool RemoveModule(ISystemModule *module) = 0; + + virtual void Stop() = 0; + virtual char *GetBaseDir() = 0; +}; + +#define BASESYSTEM_INTERFACE_VERSION "basesystem002" diff --git a/common/IDemoPlayer.h b/common/IDemoPlayer.h new file mode 100644 index 0000000..2431b54 --- /dev/null +++ b/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/common/IEngineWrapper.h b/common/IEngineWrapper.h new file mode 100644 index 0000000..7162d5b --- /dev/null +++ b/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/common/IObjectContainer.h b/common/IObjectContainer.h new file mode 100644 index 0000000..333e9d0 --- /dev/null +++ b/common/IObjectContainer.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 + +class IObjectContainer { +public: + virtual ~IObjectContainer() {} + + virtual void Init() = 0; + + virtual bool Add(void *newObject) = 0; + virtual bool Remove(void *object) = 0; + virtual void Clear(bool freeElementsMemory) = 0; + + virtual void *GetFirst() = 0; + virtual void *GetNext() = 0; + + virtual int CountElements() = 0; + virtual bool Contains(void *object) = 0; + virtual bool IsEmpty() = 0; +}; diff --git a/common/ISystemModule.h b/common/ISystemModule.h new file mode 100644 index 0000000..9004a95 --- /dev/null +++ b/common/ISystemModule.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 "interface.h" + +class IBaseSystem; +class ISystemModule; + +class ISystemModule: public IBaseInterface { +public: + virtual ~ISystemModule() {} + 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 = nullptr) = 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; +}; diff --git a/common/IVGuiModule.h b/common/IVGuiModule.h new file mode 100644 index 0000000..e6864c8 --- /dev/null +++ b/common/IVGuiModule.h @@ -0,0 +1,76 @@ +/* +* +* 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 "interface.h" + +// Purpose: Standard interface to loading vgui modules +class IVGuiModule: public IBaseInterface +{ +public: + // called first to setup the module with the vgui + // returns true on success, false on failure + virtual bool Initialize(CreateInterfaceFn *vguiFactories, int factoryCount) = 0; + + // 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 = nullptr, int factoryCount = 0) = 0; + + // called when the module is selected from the menu or otherwise activated + virtual bool Activate() = 0; + + // returns true if the module is successfully initialized and available + virtual bool IsValid() = 0; + + // requests that the UI is temporarily disabled and all data files saved + virtual void Deactivate() = 0; + + // restart from a Deactivate() + virtual void Reactivate() = 0; + + // called when the module is about to be shutdown + virtual void Shutdown() = 0; + + // returns a handle to the main module panel + virtual vgui2::VPANEL GetPanel() = 0; + + // sets the parent of the main module panel + virtual void SetParent(vgui2::VPANEL parent) = 0; + + // messages sent through through the panel returned by GetPanel(): + // + // "ConnectedToGame" "ip" "port" "gamedir" + // "DisconnectedFromGame" + // "ActiveGameName" "name" + // "LoadingStarted" "type" "name" + // "LoadingFinished" "type" "name" +}; + +#define VGUIMODULE_INTERFACE_VERSION "VGuiModuleAdminServer001" diff --git a/common/ObjectDictionary.cpp b/common/ObjectDictionary.cpp new file mode 100644 index 0000000..b14c62d --- /dev/null +++ b/common/ObjectDictionary.cpp @@ -0,0 +1,515 @@ +/* +* +* 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" + +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 (m_entries) { + free(m_entries); + } +} + +void ObjectDictionary::Clear(bool freeObjectssMemory) +{ + if (freeObjectssMemory) + { + for (int i = 0; i < m_size; i++) + { + void *obj = m_entries[i].object; + if (obj) { + free(obj); + } + } + } + + m_size = 0; + CheckSize(); + ClearCache(); +} + +bool ObjectDictionary::Add(void *object, float key) +{ + if (m_size == m_maxSize && !CheckSize()) + return false; + + entry_t *p; + if (m_size && key < m_entries[m_size - 1].key) + { + p = &m_entries[FindClosestAsIndex(key)]; + + entry_t *e1 = &m_entries[m_size]; + entry_t *e2 = &m_entries[m_size - 1]; + + while (p->key <= key) { p++; } + while (p != e1) + { + e1->object = e2->object; + e1->key = e2->key; + + e1--; + e2--; + } + } + else + p = &m_entries[m_size]; + + p->key = key; + p->object = object; + m_size++; + + ClearCache(); + AddToCache(p); + + return true; +} + +int ObjectDictionary::FindClosestAsIndex(float key) +{ + if (m_size <= 0) + return -1; + + if (key <= m_entries->key) + return 0; + + int index = FindKeyInCache(key); + if (index >= 0) { + return index; + } + + int middle; + int first = 0; + int last = m_size - 1; + float keyMiddle, keyNext; + + if (key < m_entries[last].key) + { + while (true) + { + middle = (last + first) >> 1; + keyMiddle = m_entries[middle].key; + + if (keyMiddle == key) + break; + + if (keyMiddle < key) + { + if (m_entries[middle + 1].key >= key) + { + if (m_entries[middle + 1].key - key < key - keyMiddle) + ++middle; + break; + } + + first = (last + first) >> 1; + } + else + { + last = (last + first) >> 1; + } + } + } + else + { + middle = last; + } + + keyNext = m_entries[middle - 1].key; + while (keyNext == key) { + keyNext = m_entries[middle--].key; + } + + AddToCache(&m_entries[middle], key); + return middle; +} + +void ObjectDictionary::ClearCache() +{ + memset(m_cache, 0, sizeof(m_cache)); + m_cacheIndex = 0; +} + +bool ObjectDictionary::RemoveIndex(int index, bool freeObjectMemory) +{ + if (index < 0 || index >= m_size) + return false; + + 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); + + while (p != e1) + { + e1->object = e2->object; + e1->key = e2->key; + + e1++; + e2++; + } + + p->object = nullptr; + p->key = 0; + m_size--; + + CheckSize(); + ClearCache(); + + return false; +} + +bool ObjectDictionary::RemoveIndexRange(int minIndex, int maxIndex) +{ + if (minIndex > maxIndex) + { + if (maxIndex < 0) + maxIndex = 0; + + if (minIndex >= m_size) + minIndex = m_size - 1; + } + else + { + if (minIndex < 0) + minIndex = 0; + + if (maxIndex >= m_size) + maxIndex = m_size - 1; + } + + int offset = minIndex + maxIndex - 1; + m_size -= offset; + CheckSize(); + return true; +} + +bool ObjectDictionary::Remove(void *object) +{ + bool found = false; + for (int i = 0; i < m_size; i++) + { + if (m_entries[i].object == object) { + RemoveIndex(i); + found = true; + } + } + + return found ? true : false; +} + +bool ObjectDictionary::RemoveSingle(void *object) +{ + for (int i = 0; i < m_size; i++) + { + if (m_entries[i].object == object) { + RemoveIndex(i); + return true; + } + } + + return false; +} + +bool ObjectDictionary::RemoveKey(float key) +{ + int i = FindClosestAsIndex(key); + if (m_entries[i].key == key) + { + int j = i; + do { + ++j; + } + while (key == m_entries[j + 1].key); + + return RemoveIndexRange(i, j); + } + + return false; +} + +bool ObjectDictionary::CheckSize() +{ + int newSize = m_maxSize; + if (m_size == m_maxSize) + { + newSize = 1 - (int)(m_maxSize * -1.25f); + } + else if (m_maxSize * 0.5f > m_size) + { + newSize = (int)(m_maxSize * 0.75f); + } + + if (newSize != m_maxSize) + { + entry_t *newEntries = (entry_t *)malloc(sizeof(entry_t) * newSize); + if (!newEntries) + return false; + + memset(&newEntries[m_size], 0, sizeof(entry_t) * (newSize - m_size)); + + if (m_entries && m_size) + { + memcpy(newEntries, m_entries, sizeof(entry_t) * m_size); + free(m_entries); + } + + m_entries = newEntries; + m_maxSize = newSize; + } + + return true; +} + +void ObjectDictionary::Init() +{ + m_size = 0; + m_maxSize = 0; + m_entries = nullptr; + + CheckSize(); + ClearCache(); +} + +void ObjectDictionary::Init(int baseSize) +{ + m_size = 0; + m_maxSize = 0; + m_entries = (entry_t *)Mem_ZeroMalloc(sizeof(entry_t) * baseSize); + + if (m_entries) { + m_maxSize = baseSize; + } +} + +bool ObjectDictionary::Add(void *object) +{ + return Add(object, 0); +} + +int ObjectDictionary::CountElements() +{ + return m_size; +} + +bool ObjectDictionary::IsEmpty() +{ + return (m_size == 0) ? true : false; +} + +bool ObjectDictionary::Contains(void *object) +{ + if (FindObjectInCache(object) >= 0) + return true; + + for (int i = 0; i < m_size; i++) + { + entry_t *e = &m_entries[i]; + if (e->object == object) { + AddToCache(e); + return true; + } + } + + return false; +} + +void *ObjectDictionary::GetFirst() +{ + m_currentEntry = 0; + return GetNext(); +} + +void *ObjectDictionary::GetLast() +{ + return (m_size > 0) ? m_entries[m_size - 1].object : nullptr; +} + +bool ObjectDictionary::ChangeKey(void *object, float newKey) +{ + int pos = FindObjectInCache(object); + if (pos < 0) + { + for (pos = 0; pos < m_size; pos++) + { + if (m_entries[pos].object == object) { + AddToCache(&m_entries[pos]); + break; + } + } + + if (pos == m_size) { + return false; + } + } + + entry_t *p, *e; + + p = &m_entries[pos]; + if (p->key == newKey) + return false; + + int newpos = FindClosestAsIndex(newKey); + e = &m_entries[newpos]; + if (pos < newpos) + { + if (e->key > newKey) + e--; + + entry_t *e2 = &m_entries[pos + 1]; + while (p < e) + { + p->object = e2->object; + p->key = e2->key; + + p++; + e2++; + } + } + else if (pos > newpos) + { + if (e->key > newKey) + e++; + + entry_t *e2 = &m_entries[pos - 1]; + while (p > e) + { + p->object = e2->object; + p->key = e2->key; + + p--; + e2--; + } + } + + p->object = object; + p->key = newKey; + ClearCache(); + + return true; +} + +bool ObjectDictionary::UnsafeChangeKey(void *object, float newKey) +{ + int pos = FindObjectInCache(object); + if (pos < 0) + { + for (pos = 0; pos < m_size; pos++) + { + if (m_entries[pos].object == object) { + break; + } + } + + if (pos == m_size) { + return false; + } + } + + m_entries[pos].key = newKey; + ClearCache(); + return true; +} + +void ObjectDictionary::AddToCache(entry_t *entry) +{ + int i = (m_cacheIndex % MAX_OBJECT_CACHE); + + m_cache[i].object = entry; + m_cache[i].key = entry->key; + m_cacheIndex++; +} + +void ObjectDictionary::AddToCache(entry_t *entry, float key) +{ + int i = (m_cacheIndex % MAX_OBJECT_CACHE); + + m_cache[i].object = entry; + m_cache[i].key = key; + m_cacheIndex++; +} + +int ObjectDictionary::FindKeyInCache(float key) +{ + for (auto& ch : m_cache) + { + if (ch.object && ch.key == key) { + return (entry_t *)ch.object - m_entries; + } + } + + return -1; +} + +int ObjectDictionary::FindObjectInCache(void *object) +{ + for (auto& ch : m_cache) + { + if (ch.object && ch.object == object) { + return (entry_t *)ch.object - m_entries; + } + } + + return -1; +} + +void *ObjectDictionary::FindClosestKey(float key) +{ + m_currentEntry = FindClosestAsIndex(key); + return GetNext(); +} + +void *ObjectDictionary::GetNext() +{ + if (m_currentEntry < 0 || m_currentEntry >= m_size) + return nullptr; + + return m_entries[m_currentEntry++].object; +} + +void *ObjectDictionary::FindExactKey(float key) +{ + if ((m_currentEntry = FindClosestAsIndex(key)) < 0) + return nullptr; + + return (m_entries[m_currentEntry].key == key) ? GetNext() : nullptr; +} diff --git a/common/ObjectDictionary.h b/common/ObjectDictionary.h new file mode 100644 index 0000000..bf1b77f --- /dev/null +++ b/common/ObjectDictionary.h @@ -0,0 +1,94 @@ +/* +* +* 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 "IObjectContainer.h" + +class ObjectDictionary: public IObjectContainer { +public: + ObjectDictionary(); + virtual ~ObjectDictionary(); + + void Init(); + void Init(int baseSize); + + bool Add(void *object); + bool Contains(void *object); + bool IsEmpty(); + int CountElements(); + + void Clear(bool freeObjectssMemory = false); + + bool Add(void *object, float key); + bool ChangeKey(void *object, float newKey); + bool UnsafeChangeKey(void *object, float newKey); + + bool Remove(void *object); + bool RemoveSingle(void *object); + bool RemoveKey(float key); + bool RemoveRange(float startKey, float endKey); + + void *FindClosestKey(float key); + void *FindExactKey(float key); + + void *GetFirst(); + void *GetLast(); + void *GetNext(); + + int FindKeyInCache(float key); + int FindObjectInCache(void *object); + + 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); + + bool RemoveIndex(int index, bool freeObjectMemory = false); + bool RemoveIndexRange(int minIndex, int maxIndex); + int FindClosestAsIndex(float key); + +protected: + int m_currentEntry; + float m_findKey; + + enum { MAX_OBJECT_CACHE = 32 }; + + entry_t *m_entries; + entry_t m_cache[MAX_OBJECT_CACHE]; + + int m_cacheIndex; + int m_size; + int m_maxSize; +}; diff --git a/common/ObjectList.cpp b/common/ObjectList.cpp new file mode 100644 index 0000000..0eba24e --- /dev/null +++ b/common/ObjectList.cpp @@ -0,0 +1,259 @@ +/* +* +* 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() +{ + m_head = m_tail = m_current = nullptr; + m_number = 0; +} + +ObjectList::~ObjectList() +{ + Clear(false); +} + +bool ObjectList::AddHead(void *newObject) +{ + // create new element + element_t *newElement = (element_t *)Mem_ZeroMalloc(sizeof(element_t)); + + // out of memory + if (!newElement) + return false; + + // insert element + newElement->object = newObject; + + if (m_head) + { + newElement->next = m_head; + m_head->prev = newElement; + } + + m_head = newElement; + + // if list was empty set new m_tail + if (!m_tail) + m_tail = m_head; + + m_number++; + return true; +} + +void *ObjectList::RemoveHead() +{ + void *retObj; + + // check m_head is present + if (m_head) + { + retObj = m_head->object; + element_t *newHead = m_head->next; + if (newHead) + newHead->prev = nullptr; + + // if only one element is in list also update m_tail + // if we remove this prev element + if (m_tail == m_head) + m_tail = nullptr; + + free(m_head); + m_head = newHead; + + m_number--; + } + else + retObj = nullptr; + + return retObj; +} + +bool ObjectList::AddTail(void *newObject) +{ + // create new element + element_t *newElement = (element_t *)Mem_ZeroMalloc(sizeof(element_t)); + + // out of memory + if (!newElement) + return false; + + // insert element + newElement->object = newObject; + + if (m_tail) + { + newElement->prev = m_tail; + m_tail->next = newElement; + } + + m_tail = newElement; + + // if list was empty set new m_tail + if (!m_head) + m_head = m_tail; + + m_number++; + return true; +} + +void *ObjectList::RemoveTail() +{ + void *retObj; + + // check m_tail is present + if (m_tail) + { + retObj = m_tail->object; + element_t *newTail = m_tail->prev; + if (newTail) + newTail->next = nullptr; + + // if only one element is in list also update m_tail + // if we remove this prev element + if (m_head == m_tail) + m_head = nullptr; + + free(m_tail); + m_tail = newTail; + + m_number--; + + } + else + retObj = nullptr; + + return retObj; +} + +bool ObjectList::IsEmpty() +{ + return (m_head == nullptr); +} + +int ObjectList::CountElements() +{ + return m_number; +} + +bool ObjectList::Contains(void *object) +{ + element_t *e = m_head; + + while (e && e->object != object) { e = e->next; } + + if (e) + { + m_current = e; + return true; + } + else + { + return false; + } +} + +void ObjectList::Clear(bool freeElementsMemory) +{ + element_t *ne; + element_t *e = m_head; + + while (e) + { + ne = e->next; + + if (freeElementsMemory && e->object) + free(e->object); + + free(e); + e = ne; + } + + m_head = m_tail = m_current = nullptr; + m_number = 0; +} + +bool ObjectList::Remove(void *object) +{ + element_t *e = m_head; + + while (e && e->object != object) { e = e->next; } + + if (e) + { + if (e->prev) e->prev->next = e->next; + if (e->next) e->next->prev = e->prev; + + 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); + m_number--; + } + + return (e != nullptr); +} + +void ObjectList::Init() +{ + m_head = m_tail = m_current = nullptr; + m_number = 0; +} + +void *ObjectList::GetFirst() +{ + if (m_head) + { + m_current = m_head->next; + return m_head->object; + } + else + { + m_current = nullptr; + return nullptr; + } +} + +void *ObjectList::GetNext() +{ + void *retObj = nullptr; + if (m_current) + { + retObj = m_current->object; + m_current = m_current->next; + } + + return retObj; +} + +bool ObjectList::Add(void *newObject) +{ + return AddTail(newObject); +} diff --git a/common/ObjectList.h b/common/ObjectList.h new file mode 100644 index 0000000..d351ac3 --- /dev/null +++ b/common/ObjectList.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 "IObjectContainer.h" + +class ObjectList: public IObjectContainer { +public: + void Init(); + bool Add(void *newObject); + void *GetFirst(); + void *GetNext(); + + ObjectList(); + virtual ~ObjectList(); + + void Clear(bool freeElementsMemory = false); + int CountElements(); + void *RemoveTail(); + void *RemoveHead(); + + bool AddTail(void *newObject); + bool AddHead(void *newObject); + bool Remove(void *object); + bool Contains(void *object); + bool IsEmpty(); + + typedef struct element_s { + 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 *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; +}; diff --git a/common/SteamAppStartUp.cpp b/common/SteamAppStartUp.cpp new file mode 100644 index 0000000..87cdc55 --- /dev/null +++ b/common/SteamAppStartUp.cpp @@ -0,0 +1,211 @@ +/* +* +* 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 +#include "SteamAppStartup.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include + +#define STEAM_PARM "-steam" + +bool FileExists(const char *fileName) +{ + struct _stat statbuf; + return (_stat(fileName, &statbuf) == 0); +} + +// Handles launching the game indirectly via steam +void LaunchSelfViaSteam(const char *params) +{ + // calculate the details of our launch + char appPath[MAX_PATH]; + ::GetModuleFileName((HINSTANCE)GetModuleHandle(NULL), appPath, sizeof(appPath)); + + // strip out the exe name + char *slash = strrchr(appPath, '\\'); + if (slash) + { + *slash = '\0'; + } + + // save out our details to the registry + HKEY hKey; + if (ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER, "Software\\Valve\\Steam", &hKey)) + { + DWORD dwType = REG_SZ; + DWORD dwSize = static_cast( strlen(appPath) + 1 ); + RegSetValueEx(hKey, "TempAppPath", NULL, dwType, (LPBYTE)appPath, dwSize); + dwSize = static_cast( strlen(params) + 1 ); + RegSetValueEx(hKey, "TempAppCmdLine", NULL, dwType, (LPBYTE)params, dwSize); + // clear out the appID (since we don't know it yet) + dwType = REG_DWORD; + int appID = -1; + RegSetValueEx(hKey, "TempAppID", NULL, dwType, (LPBYTE)&appID, sizeof(appID)); + RegCloseKey(hKey); + } + + // search for an active steam instance + HWND hwnd = ::FindWindow("Valve_SteamIPC_Class", "Hidden Window"); + if (hwnd) + { + ::PostMessage(hwnd, WM_USER + 3, 0, 0); + } + else + { + // couldn't find steam, find and launch it + + // first, search backwards through our current set of directories + char steamExe[MAX_PATH] = ""; + char dir[MAX_PATH]; + + if (::GetCurrentDirectoryA(sizeof(dir), dir)) + { + char *slash = strrchr(dir, '\\'); + while (slash) + { + // see if steam_dev.exe is in the directory first + slash[1] = 0; + strcat(slash, "steam_dev.exe"); + FILE *f = fopen(dir, "rb"); + if (f) + { + // found it + fclose(f); + strcpy(steamExe, dir); + break; + } + + // see if steam.exe is in the directory + slash[1] = 0; + strcat(slash, "steam.exe"); + f = fopen(dir, "rb"); + if (f) + { + // found it + fclose(f); + strcpy(steamExe, dir); + break; + } + + // kill the string at the slash + slash[0] = 0; + + // move to the previous slash + slash = strrchr(dir, '\\'); + } + } + + if (!steamExe[0]) + { + // still not found, use the one in the registry + HKEY hKey; + if (ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER, "Software\\Valve\\Steam", &hKey)) + { + DWORD dwType; + DWORD dwSize = sizeof(steamExe); + RegQueryValueEx(hKey, "SteamExe", NULL, &dwType, (LPBYTE)steamExe, &dwSize); + RegCloseKey(hKey); + } + } + + if (!steamExe[0]) + { + // still no path, error + ::MessageBox(NULL, "Error running game: could not find steam.exe to launch", "Fatal Error", MB_OK | MB_ICONERROR); + return; + } + + // fix any slashes + for (char *slash = steamExe; *slash; slash++) + { + if (*slash == '/') + { + *slash = '\\'; + } + } + + // change to the steam directory + strcpy(dir, steamExe); + char *delimiter = strrchr(dir, '\\'); + if (delimiter) + { + *delimiter = 0; + _chdir(dir); + } + + // exec steam.exe, in silent mode, with the launch app param + char *args[4] = { steamExe, "-silent", "-applaunch", '\0' }; + _spawnv(_P_NOWAIT, steamExe, args); + } +} + +// Launches steam if necessary +bool ShouldLaunchAppViaSteam(const char *lpCmdLine, const char *steamFilesystemDllName, const char *stdioFilesystemDllName) +{ + // see if steam is on the command line + const char *steamStr = strstr(lpCmdLine, STEAM_PARM); + + // check the character following it is a whitespace or null + if (steamStr) + { + const char *postChar = steamStr + strlen(STEAM_PARM); + if (*postChar == 0 || isspace(*postChar)) + { + // we're running under steam already, let the app continue + return false; + } + } + + // we're not running under steam, see which filesystems are available + if (FileExists(stdioFilesystemDllName)) + { + // we're being run with a stdio filesystem, so we can continue without steam + return false; + } + + // make sure we have a steam filesystem available + if (!FileExists(steamFilesystemDllName)) + { + return false; + } + + // we have the steam filesystem, and no stdio filesystem, so we must need to be run under steam + // launch steam + LaunchSelfViaSteam(lpCmdLine); + return true; +} + +#endif // _WIN32 diff --git a/common/SteamAppStartUp.h b/common/SteamAppStartUp.h new file mode 100644 index 0000000..2b9fbe7 --- /dev/null +++ b/common/SteamAppStartUp.h @@ -0,0 +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. +* +*/ + +#pragma once + +// Call this first thing at startup +// Works out if the app is a steam app that is being ran outside of steam, +// and if so, launches steam and tells it to run us as a steam app +// +// 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); diff --git a/common/TextConsoleUnix.cpp b/common/TextConsoleUnix.cpp new file mode 100644 index 0000000..e5f446a --- /dev/null +++ b/common/TextConsoleUnix.cpp @@ -0,0 +1,324 @@ +/* +* +* 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) + +#include "TextConsoleUnix.h" +#include "icommandline.h" + +#include +#include +#include +#include +#include +#include +#include + +CTextConsoleUnix console; + +CTextConsoleUnix::~CTextConsoleUnix() +{ + CTextConsoleUnix::ShutDown(); +} + +bool CTextConsoleUnix::Init(IBaseSystem *system) +{ + static struct termios termNew; + sigset_t block_ttou; + + sigemptyset(&block_ttou); + sigaddset(&block_ttou, SIGTTOU); + sigprocmask(SIG_BLOCK, &block_ttou, NULL); + + tty = stdout; + + // this code is for echo-ing key presses to the connected tty + // (which is != STDOUT) + if (isatty(STDIN_FILENO)) + { + tty = fopen(ctermid(NULL), "w+"); + if (!tty) + { + printf("Unable to open tty(%s) for output\n", ctermid(NULL)); + tty = stdout; + } + else + { + // turn buffering off + setbuf(tty, NULL); + } + } + else + { + tty = fopen("/dev/null", "w+"); + if (!tty) + { + tty = stdout; + } + } + + tcgetattr(STDIN_FILENO, &termStored); + + memcpy(&termNew, &termStored, sizeof(struct termios)); + + // Disable canonical mode, and set buffer size to 1 byte + termNew.c_lflag &= (~ICANON); + termNew.c_cc[ VMIN ] = 1; + termNew.c_cc[ VTIME ] = 0; + + // disable echo + termNew.c_lflag &= (~ECHO); + + tcsetattr(STDIN_FILENO, TCSANOW, &termNew); + sigprocmask(SIG_UNBLOCK, &block_ttou, NULL); + + return CTextConsole::Init(); +} + +void CTextConsoleUnix::ShutDown() +{ + sigset_t block_ttou; + + sigemptyset(&block_ttou); + sigaddset(&block_ttou, SIGTTOU); + sigprocmask(SIG_BLOCK, &block_ttou, NULL); + tcsetattr(STDIN_FILENO, TCSANOW, &termStored); + sigprocmask(SIG_UNBLOCK, &block_ttou, NULL); + + CTextConsole::ShutDown(); +} + +// return 0 if the kb isn't hit +int CTextConsoleUnix::kbhit() +{ + fd_set rfds; + struct timeval tv; + + // Watch stdin (fd 0) to see when it has input. + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); + + // Return immediately. + tv.tv_sec = 0; + tv.tv_usec = 0; + + // Must be in raw or cbreak mode for this to work correctly. + return select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv) != -1 && FD_ISSET(STDIN_FILENO, &rfds); +} + +char *CTextConsoleUnix::GetLine() +{ + // early return for 99.999% case :) + if (!kbhit()) + return NULL; + + escape_sequence_t es; + + es = ESCAPE_CLEAR; + sigset_t block_ttou; + + sigemptyset(&block_ttou); + sigaddset(&block_ttou, SIGTTOU); + sigaddset(&block_ttou, SIGTTIN); + sigprocmask(SIG_BLOCK, &block_ttou, NULL); + + while (true) + { + if (!kbhit()) + break; + + int nLen; + char ch = 0; + int numRead = read(STDIN_FILENO, &ch, 1); + if (!numRead) + break; + + switch (ch) + { + case '\n': // Enter + es = ESCAPE_CLEAR; + + nLen = ReceiveNewline(); + if (nLen) + { + sigprocmask(SIG_UNBLOCK, &block_ttou, NULL); + return m_szConsoleText; + } + break; + + case 127: // Backspace + case '\b': // Backspace + es = ESCAPE_CLEAR; + ReceiveBackspace(); + break; + + case '\t': // TAB + es = ESCAPE_CLEAR; + ReceiveTab(); + break; + + case 27: // Escape character + es = ESCAPE_RECEIVED; + break; + + case '[': // 2nd part of escape sequence + case 'O': + case 'o': + switch (es) + { + case ESCAPE_CLEAR: + case ESCAPE_BRACKET_RECEIVED: + es = ESCAPE_CLEAR; + ReceiveStandardChar(ch); + break; + + case ESCAPE_RECEIVED: + es = ESCAPE_BRACKET_RECEIVED; + break; + } + break; + case 'A': + if (es == ESCAPE_BRACKET_RECEIVED) + { + es = ESCAPE_CLEAR; + ReceiveUpArrow(); + } + else + { + es = ESCAPE_CLEAR; + ReceiveStandardChar(ch); + } + break; + case 'B': + if (es == ESCAPE_BRACKET_RECEIVED) + { + es = ESCAPE_CLEAR; + ReceiveDownArrow(); + } + else + { + es = ESCAPE_CLEAR; + ReceiveStandardChar(ch); + } + break; + case 'C': + if (es == ESCAPE_BRACKET_RECEIVED) + { + es = ESCAPE_CLEAR; + ReceiveRightArrow(); + } + else + { + es = ESCAPE_CLEAR; + ReceiveStandardChar(ch); + } + break; + case 'D': + if (es == ESCAPE_BRACKET_RECEIVED) + { + es = ESCAPE_CLEAR; + ReceiveLeftArrow(); + } + else + { + es = ESCAPE_CLEAR; + ReceiveStandardChar(ch); + } + break; + default: + // Just eat this char if it's an unsupported escape + if (es != ESCAPE_BRACKET_RECEIVED) + { + // dont' accept nonprintable chars + if ((ch >= ' ') && (ch <= '~')) + { + es = ESCAPE_CLEAR; + ReceiveStandardChar(ch); + } + } + break; + } + + fflush(stdout); + } + + sigprocmask(SIG_UNBLOCK, &block_ttou, NULL); + return NULL; +} + +void CTextConsoleUnix::PrintRaw(char *pszMsg, int nChars) +{ + if (nChars == 0) + { + printf("%s", pszMsg); + } + else + { + for (int nCount = 0; nCount < nChars; nCount++) + { + putchar(pszMsg[ nCount ]); + } + } +} + +void CTextConsoleUnix::Echo(char *pszMsg, int nChars) +{ + if (nChars == 0) + { + fputs(pszMsg, tty); + } + else + { + for (int nCount = 0; nCount < nChars; nCount++) + { + fputc(pszMsg[ nCount ], tty); + } + } +} + +int CTextConsoleUnix::GetWidth() +{ + struct winsize ws; + int nWidth = 0; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0) + { + nWidth = (int)ws.ws_col; + } + + if (nWidth <= 1) + { + nWidth = 80; + } + + return nWidth; +} + +#endif // !defined(_WIN32) diff --git a/common/TextConsoleUnix.h b/common/TextConsoleUnix.h new file mode 100644 index 0000000..b40cbc4 --- /dev/null +++ b/common/TextConsoleUnix.h @@ -0,0 +1,59 @@ +/* +* +* 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 "textconsole.h" + +enum escape_sequence_t +{ + ESCAPE_CLEAR, + ESCAPE_RECEIVED, + ESCAPE_BRACKET_RECEIVED +}; + +class CTextConsoleUnix: public CTextConsole { +public: + virtual ~CTextConsoleUnix(); + + bool Init(IBaseSystem *system = nullptr); + void ShutDown(); + void PrintRaw(char *pszMsg, int nChars = 0); + void Echo(char *pszMsg, int nChars = 0); + char *GetLine(); + int GetWidth(); + +private: + int kbhit(); + + struct termios termStored; + FILE *tty; +}; + +extern CTextConsoleUnix console; diff --git a/common/TextConsoleWin32.cpp b/common/TextConsoleWin32.cpp new file mode 100644 index 0000000..101470b --- /dev/null +++ b/common/TextConsoleWin32.cpp @@ -0,0 +1,280 @@ +/* +* +* 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) +{ + // TODO ? + /*if (CtrlType != CTRL_C_EVENT && CtrlType != CTRL_BREAK_EVENT) + { + // don't quit on break or ctrl+c + m_System->Stop(); + }*/ + + return TRUE; +} + +// GetConsoleHwnd() helper function from MSDN Knowledge Base Article Q124103 +// needed, because HWND GetConsoleWindow(VOID) is not avaliable under Win95/98/ME +HWND GetConsoleHwnd() +{ + HWND hwndFound; // This is what is returned to the caller. + char pszNewWindowTitle[1024]; // Contains fabricated WindowTitle + char pszOldWindowTitle[1024]; // Contains original WindowTitle + + // Fetch current window title. + GetConsoleTitle(pszOldWindowTitle, sizeof(pszOldWindowTitle)); + + // Format a "unique" NewWindowTitle. + wsprintf(pszNewWindowTitle, "%d/%d", GetTickCount(), GetCurrentProcessId()); + + // Change current window title. + SetConsoleTitle(pszNewWindowTitle); + + // Ensure window title has been updated. + Sleep(40); + + // Look for NewWindowTitle. + hwndFound = FindWindow(nullptr, pszNewWindowTitle); + + // Restore original window title. + SetConsoleTitle(pszOldWindowTitle); + + return hwndFound; +} + +CTextConsoleWin32::~CTextConsoleWin32() +{ + CTextConsoleWin32::ShutDown(); +} + +bool CTextConsoleWin32::Init(IBaseSystem *system) +{ + if (!AllocConsole()) + m_System = system; + + SetTitle(m_System ? m_System->GetName() : "Console"); + + hinput = GetStdHandle(STD_INPUT_HANDLE); + houtput = GetStdHandle(STD_OUTPUT_HANDLE); + + if (!SetConsoleCtrlHandler(&ConsoleHandlerRoutine, TRUE)) + { + Print("WARNING! TextConsole::Init: Could not attach console hook.\n"); + } + + Attrib = FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; + SetWindowPos(GetConsoleHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOREPOSITION | SWP_SHOWWINDOW); + + return CTextConsole::Init(system); +} + +void CTextConsoleWin32::ShutDown() +{ + FreeConsole(); + CTextConsole::ShutDown(); +} + +void CTextConsoleWin32::SetVisible(bool visible) +{ + ShowWindow(GetConsoleHwnd(), visible ? SW_SHOW : SW_HIDE); + m_ConsoleVisible = visible; +} + +char *CTextConsoleWin32::GetLine() +{ + while (true) + { + INPUT_RECORD recs[1024]; + unsigned long numread; + unsigned long numevents; + + if (!GetNumberOfConsoleInputEvents(hinput, &numevents)) + { + if (m_System) + m_System->Errorf("CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents"); + + return nullptr; + } + + if (numevents <= 0) + break; + + if (!ReadConsoleInput(hinput, recs, ARRAYSIZE(recs), &numread)) + { + if (m_System) + m_System->Errorf("CTextConsoleWin32::GetLine: !ReadConsoleInput"); + return nullptr; + } + + if (numread == 0) + return nullptr; + + for (int i = 0; i < (int)numread; i++) + { + INPUT_RECORD *pRec = &recs[i]; + if (pRec->EventType != KEY_EVENT) + continue; + + if (pRec->Event.KeyEvent.bKeyDown) + { + // check for cursor keys + if (pRec->Event.KeyEvent.wVirtualKeyCode == VK_UP) + { + ReceiveUpArrow(); + } + else if (pRec->Event.KeyEvent.wVirtualKeyCode == VK_DOWN) + { + ReceiveDownArrow(); + } + else if (pRec->Event.KeyEvent.wVirtualKeyCode == VK_LEFT) + { + ReceiveLeftArrow(); + } + else if (pRec->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT) + { + ReceiveRightArrow(); + } + else + { + int nLen; + char ch = pRec->Event.KeyEvent.uChar.AsciiChar; + switch (ch) + { + case '\r': // Enter + nLen = ReceiveNewline(); + if (nLen) + { + return m_szConsoleText; + } + break; + case '\b': // Backspace + ReceiveBackspace(); + break; + case '\t': // TAB + ReceiveTab(); + break; + default: + // dont' accept nonprintable chars + if ((ch >= ' ') && (ch <= '~')) + { + ReceiveStandardChar(ch); + } + break; + } + } + } + } + } + + return nullptr; +} + +void CTextConsoleWin32::PrintRaw(char *pszMsg, int nChars) +{ +#ifdef LAUNCHER_FIXES + char outputStr[2048]; + WCHAR unicodeStr[1024]; + + DWORD nSize = MultiByteToWideChar(CP_UTF8, 0, pszMsg, -1, NULL, 0); + if (nSize > sizeof(unicodeStr)) + return; + + MultiByteToWideChar(CP_UTF8, 0, pszMsg, -1, unicodeStr, nSize); + DWORD nLength = WideCharToMultiByte(CP_OEMCP, 0, unicodeStr, -1, 0, 0, NULL, NULL); + if (nLength > sizeof(outputStr)) + return; + + WideCharToMultiByte(CP_OEMCP, 0, unicodeStr, -1, outputStr, nLength, NULL, NULL); + WriteFile(houtput, outputStr, nChars ? nChars : strlen(outputStr), NULL, NULL); +#else + WriteFile(houtput, pszMsg, nChars ? nChars : strlen(pszMsg), NULL, NULL); +#endif +} + +void CTextConsoleWin32::Echo(char *pszMsg, int nChars) +{ + PrintRaw(pszMsg, nChars); +} + +int CTextConsoleWin32::GetWidth() +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; + int nWidth = 0; + + if (GetConsoleScreenBufferInfo(houtput, &csbi)) { + nWidth = csbi.dwSize.X; + } + + if (nWidth <= 1) + nWidth = 80; + + return nWidth; +} + +void CTextConsoleWin32::SetStatusLine(char *pszStatus) +{ + strncpy(statusline, pszStatus, sizeof(statusline) - 1); + statusline[sizeof(statusline) - 2] = '\0'; + UpdateStatus(); +} + +void CTextConsoleWin32::UpdateStatus() +{ + COORD coord; + DWORD dwWritten = 0; + WORD wAttrib[ 80 ]; + + for (int i = 0; i < 80; i++) + { + wAttrib[i] = Attrib; // FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; + } + + coord.X = coord.Y = 0; + + WriteConsoleOutputAttribute(houtput, wAttrib, 80, coord, &dwWritten); + WriteConsoleOutputCharacter(houtput, statusline, 80, coord, &dwWritten); +} + +void CTextConsoleWin32::SetTitle(char *pszTitle) +{ + SetConsoleTitle(pszTitle); +} + +void CTextConsoleWin32::SetColor(WORD attrib) +{ + Attrib = attrib; +} + +#endif // defined(_WIN32) diff --git a/common/TextConsoleWin32.h b/common/TextConsoleWin32.h new file mode 100644 index 0000000..dbe6c32 --- /dev/null +++ b/common/TextConsoleWin32.h @@ -0,0 +1,61 @@ +/* +* +* 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 "TextConsole.h" + +class CTextConsoleWin32: public CTextConsole { +public: + virtual ~CTextConsoleWin32(); + + bool Init(IBaseSystem *system = nullptr); + void ShutDown(); + + void SetTitle(char *pszTitle); + void SetStatusLine(char *pszStatus); + void UpdateStatus(); + + void PrintRaw(char * pszMsz, int nChars = 0); + void Echo(char * pszMsz, int nChars = 0); + char *GetLine(); + int GetWidth(); + + void SetVisible(bool visible); + void SetColor(WORD); + +private: + HANDLE hinput; // standard input handle + HANDLE houtput; // standard output handle + WORD Attrib; // attrib colours for status bar + + char statusline[81]; // first line in console is status line +}; + +extern CTextConsoleWin32 console; diff --git a/common/TokenLine.cpp b/common/TokenLine.cpp new file mode 100644 index 0000000..df8643a --- /dev/null +++ b/common/TokenLine.cpp @@ -0,0 +1,132 @@ +#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) +{ + SetLine(string); +} + +TokenLine::~TokenLine() +{ + +} + +bool TokenLine::SetLine(const char *newLine) +{ + m_tokenNumber = 0; + + if (!newLine || (strlen(newLine) >= (MAX_LINE_CHARS - 1))) + { + memset(m_fullLine, 0, sizeof(m_fullLine)); + memset(m_tokenBuffer, 0, sizeof(m_tokenBuffer)); + return false; + } + + strcopy(m_fullLine, newLine); + strcopy(m_tokenBuffer, newLine); + + // parse tokens + char *charPointer = m_tokenBuffer; + while (*charPointer && (m_tokenNumber < MAX_LINE_TOKENS)) + { + // skip nonprintable chars + while (*charPointer && ((*charPointer <= ' ') || (*charPointer > '~'))) + charPointer++; + + if (*charPointer) + { + m_token[m_tokenNumber] = charPointer; + + // special treatment for quotes + if (*charPointer == '\"') + { + charPointer++; + m_token[m_tokenNumber] = charPointer; + while (*charPointer && (*charPointer != '\"')) + charPointer++; + } + else + { + m_token[m_tokenNumber] = charPointer; + while (*charPointer && ((*charPointer > 32) && (*charPointer <= 126))) + charPointer++; + } + + m_tokenNumber++; + + if (*charPointer) + { + *charPointer = '\0'; + charPointer++; + } + } + } + + return (m_tokenNumber != MAX_LINE_TOKENS); +} + +char *TokenLine::GetLine() +{ + return m_fullLine; +} + +char *TokenLine::GetToken(int i) +{ + if (i >= m_tokenNumber) + return NULL; + + return m_token[i]; +} + +// if the given parm is not present return NULL +// otherwise return the address of the following token, or an empty string +char *TokenLine::CheckToken(char *parm) +{ + for (int i = 0; i < m_tokenNumber; i++) + { + if (!m_token[i]) + continue; + + if (!strcmp(parm, m_token[i])) + { + char *ret = m_token[i + 1]; + + // if this token doesn't exist, since index i was the last + // return an empty string + if (m_tokenNumber == (i + 1)) + ret = ""; + + return ret; + } + } + + return NULL; +} + +int TokenLine::CountToken() +{ + int c = 0; + for (int i = 0; i < m_tokenNumber; i++) + { + if (m_token[i]) + c++; + } + + return c; +} + +char *TokenLine::GetRestOfLine(int i) +{ + if (i >= m_tokenNumber) + return NULL; + + return m_fullLine + (m_token[i] - m_tokenBuffer); +} diff --git a/common/TokenLine.h b/common/TokenLine.h new file mode 100644 index 0000000..0d16fb6 --- /dev/null +++ b/common/TokenLine.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 TokenLine { +public: + TokenLine(); + TokenLine(char *string); + virtual ~TokenLine(); + + 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 + bool SetLine(const char *newLine); // set new token line and parses it + +private: + enum { MAX_LINE_CHARS = 2048, MAX_LINE_TOKENS = 128 }; + + char m_tokenBuffer[MAX_LINE_CHARS]; + char m_fullLine[MAX_LINE_CHARS]; + char *m_token[MAX_LINE_TOKENS]; + int m_tokenNumber; +}; diff --git a/common/commandline.cpp b/common/commandline.cpp new file mode 100644 index 0000000..b50fc4c --- /dev/null +++ b/common/commandline.cpp @@ -0,0 +1,354 @@ +#include "precompiled.h" + +class CCommandLine: public ICommandLine { +public: + CCommandLine(); + virtual ~CCommandLine(); + + void CreateCmdLine(const char *commandline); + void CreateCmdLine(int argc, const char *argv[]); + const char *GetCmdLine() const; + + // Check whether a particular parameter exists + const char *CheckParm(const char *psz, char **ppszValue = nullptr) const; + void RemoveParm(const char *pszParm); + void AppendParm(const char *pszParm, const char *pszValues); + + void SetParm(const char *pszParm, const char *pszValues); + void SetParm(const char *pszParm, int iValue); + + // When the commandline contains @name, it reads the parameters from that file + void LoadParametersFromFile(const char *&pSrc, char *&pDst, int maxDestLen); + +private: + // Copy of actual command line + char *m_pszCmdLine; +}; + +CCommandLine g_CmdLine; +ICommandLine *cmdline = &g_CmdLine; + +ICommandLine *CommandLine() +{ + return &g_CmdLine; +} + +CCommandLine::CCommandLine() +{ + m_pszCmdLine = nullptr; +} + +CCommandLine::~CCommandLine() +{ + if (m_pszCmdLine) + { + delete [] m_pszCmdLine; + m_pszCmdLine = nullptr; + } +} + +char *CopyString(const char *src) +{ + if (!src) + return nullptr; + + char *out = (char *)new char[strlen(src) + 1]; + strcpy(out, src); + return out; +} + +// Creates a command line from the arguments passed in +void CCommandLine::CreateCmdLine(int argc, const char *argv[]) +{ + char cmdline[4096] = ""; + const int MAX_CHARS = sizeof(cmdline) - 1; + + for (int i = 0; i < argc; ++i) + { + if (strchr(argv[i], ' ')) + { + strncat(cmdline, "\"", MAX_CHARS); + strncat(cmdline, argv[i], MAX_CHARS); + strncat(cmdline, "\"", MAX_CHARS); + } + else + { + strncat(cmdline, argv[i], MAX_CHARS); + } + + strncat(cmdline, " ", MAX_CHARS); + } + + cmdline[strlen(cmdline)] = '\0'; + CreateCmdLine(cmdline); +} + +void CCommandLine::LoadParametersFromFile(const char *&pSrc, char *&pDst, int maxDestLen) +{ + // Suck out the file name + char szFileName[ MAX_PATH ]; + char *pOut; + char *pDestStart = pDst; + + // Skip the @ sign + pSrc++; + pOut = szFileName; + + while (*pSrc && *pSrc != ' ') + { + *pOut++ = *pSrc++; +#if 0 + if ((pOut - szFileName) >= (MAX_PATH - 1)) + break; +#endif + } + + *pOut = '\0'; + + // Skip the space after the file name + if (*pSrc) + pSrc++; + + // Now read in parameters from file + FILE *fp = fopen(szFileName, "r"); + if (fp) + { + char c; + c = (char)fgetc(fp); + while (c != EOF) + { + // Turn return characters into spaces + if (c == '\n') + c = ' '; + + *pDst++ = c; + +#if 0 + // Don't go past the end, and allow for our terminating space character AND a terminating null character. + if ((pDst - pDestStart) >= (maxDestLen - 2)) + break; +#endif + + // Get the next character, if there are more + c = (char)fgetc(fp); + } + + // Add a terminating space character + *pDst++ = ' '; + + fclose(fp); + } + else + { + printf("Parameter file '%s' not found, skipping...", szFileName); + } +} + +// Purpose: Create a command line from the passed in string +// Note that if you pass in a @filename, then the routine will read settings from a file instead of the command line +void CCommandLine::CreateCmdLine(const char *commandline) +{ + if (m_pszCmdLine) + { + delete[] m_pszCmdLine; + m_pszCmdLine = nullptr; + } + + char szFull[4096]; + + char *pDst = szFull; + const char *pSrc = commandline; + + bool allowAtSign = true; + + while (*pSrc) + { + if (*pSrc == '@') + { + if (allowAtSign) + { + LoadParametersFromFile(pSrc, pDst, sizeof(szFull) - (pDst - szFull)); + continue; + } + } + + allowAtSign = isspace(*pSrc) != 0; + +#if 0 + // Don't go past the end. + if ((pDst - szFull) >= (sizeof(szFull) - 1)) + break; +#endif + *pDst++ = *pSrc++; + } + + *pDst = '\0'; + + int len = strlen(szFull) + 1; + m_pszCmdLine = new char[len]; + memcpy(m_pszCmdLine, szFull, len); +} + +// Purpose: Remove specified string ( and any args attached to it ) from command line +void CCommandLine::RemoveParm(const char *pszParm) +{ + if (!m_pszCmdLine) + return; + + if (!pszParm || *pszParm == '\0') + return; + + // Search for first occurrence of pszParm + char *p, *found; + char *pnextparam; + int n; + int curlen; + + p = m_pszCmdLine; + while (*p) + { + curlen = strlen(p); + found = strstr(p, pszParm); + + if (!found) + break; + + pnextparam = found + 1; + while (pnextparam && *pnextparam && (*pnextparam != '-') && (*pnextparam != '+')) + pnextparam++; + + if (pnextparam && *pnextparam) + { + // We are either at the end of the string, or at the next param. Just chop out the current param. + // # of characters after this param. + n = curlen - (pnextparam - p); + + memcpy(found, pnextparam, n); + found[n] = '\0'; + } + else + { + // Clear out rest of string. + n = pnextparam - found; + memset(found, 0, n); + } + } + + // Strip and trailing ' ' characters left over. + while (1) + { + int curpos = strlen(m_pszCmdLine); + if (curpos == 0 || m_pszCmdLine[ curpos - 1 ] != ' ') + break; + + m_pszCmdLine[curpos - 1] = '\0'; + } +} + +// Purpose: Append parameter and argument values to command line +void CCommandLine::AppendParm(const char *pszParm, const char *pszValues) +{ + int nNewLength = 0; + char *pCmdString; + + // Parameter. + nNewLength = strlen(pszParm); + + // Values + leading space character. + if (pszValues) + nNewLength += strlen(pszValues) + 1; + + // Terminal 0; + nNewLength++; + + if (!m_pszCmdLine) + { + m_pszCmdLine = new char[ nNewLength ]; + strcpy(m_pszCmdLine, pszParm); + if (pszValues) + { + strcat(m_pszCmdLine, " "); + strcat(m_pszCmdLine, pszValues); + } + + return; + } + + // Remove any remnants from the current Cmd Line. + RemoveParm(pszParm); + + nNewLength += strlen(m_pszCmdLine) + 1 + 1; + + pCmdString = new char[ nNewLength ]; + memset(pCmdString, 0, nNewLength); + + strcpy(pCmdString, m_pszCmdLine); // Copy old command line. + strcat(pCmdString, " "); // Put in a space + strcat(pCmdString, pszParm); + + if (pszValues) + { + strcat(pCmdString, " "); + strcat(pCmdString, pszValues); + } + + // Kill off the old one + delete[] m_pszCmdLine; + + // Point at the new command line. + m_pszCmdLine = pCmdString; +} + +void CCommandLine::SetParm(const char *pszParm, const char *pszValues) +{ + RemoveParm(pszParm); + AppendParm(pszParm, pszValues); +} + +void CCommandLine::SetParm(const char *pszParm, int iValue) +{ + char buf[64]; + _snprintf(buf, sizeof(buf), "%d", iValue); + SetParm(pszParm, buf); +} + +// Purpose: Search for the parameter in the current commandline +const char *CCommandLine::CheckParm(const char *psz, char **ppszValue) const +{ + static char sz[128] = ""; + + if (!m_pszCmdLine) + return nullptr; + + char *pret = strstr(m_pszCmdLine, psz); + if (!pret || !ppszValue) + return pret; + + *ppszValue = nullptr; + + // find the next whitespace + char *p1 = pret; + do { + ++p1; + } while (*p1 != ' ' && *p1); + + int i = 0; + char *p2 = p1 + 1; + + do { + if (p2[i] == '\0' || p2[i] == ' ') + break; + + sz[i++] = p2[i]; + } while (i < sizeof(sz)); + + sz[i] = '\0'; + *ppszValue = sz; + + return pret; +} + +const char *CCommandLine::GetCmdLine() const +{ + return m_pszCmdLine; +} diff --git a/common/crc.h b/common/crc.h index 44bcf35..f7c6bb2 100644 --- a/common/crc.h +++ b/common/crc.h @@ -17,17 +17,8 @@ #include "quakedef.h" -// MD5 Hash -typedef struct -{ - unsigned int buf[4]; - unsigned int bits[2]; - unsigned char in[64]; -} MD5Context_t; - typedef unsigned int CRC32_t; - #ifdef __cplusplus extern "C" { @@ -45,11 +36,3 @@ BOOL CRC_File(CRC32_t *crcvalue, char *pszFileName); byte COM_BlockSequenceCRCByte(byte *base, int length, int sequence); int CRC_MapFile(CRC32_t *crcvalue, char *pszFileName); - -void MD5Init(MD5Context_t *ctx); -void MD5Update(MD5Context_t *ctx, const unsigned char *buf, unsigned int len); -void MD5Final(unsigned char digest[16], MD5Context_t *ctx); -void MD5Transform(unsigned int buf[4], const unsigned int in[16]); - -BOOL MD5_Hash_File(unsigned char digest[16], char *pszFileName, BOOL bUsefopen, BOOL bSeed, unsigned int seed[4]); -char *MD5_Print(unsigned char hash[16]); diff --git a/common/entity_state.h b/common/entity_state.h index b3d364d..2fe67c9 100644 --- a/common/entity_state.h +++ b/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/common/enums.h b/common/enums.h index 14e2ce3..ad8bfe0 100644 --- a/common/enums.h +++ b/common/enums.h @@ -16,12 +16,13 @@ #ifndef ENUMS_H #define ENUMS_H +// Used as array indexer typedef enum netsrc_s { - NS_CLIENT, + NS_CLIENT = 0, NS_SERVER, - NS_MULTICAST // xxxMO + NS_MULTICAST, // xxxMO + NS_MAX } netsrc_t; #endif - diff --git a/common/hltv.h b/common/hltv.h index a6ded4e..ea420a3 100644 --- a/common/hltv.h +++ b/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: @@ -41,10 +42,9 @@ #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) // +#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) @@ -52,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/common/icommandline.h b/common/icommandline.h new file mode 100644 index 0000000..3e65189 --- /dev/null +++ b/common/icommandline.h @@ -0,0 +1,25 @@ +#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/common/kbutton.h b/common/kbutton.h index a890ce5..5607568 100644 --- a/common/kbutton.h +++ b/common/kbutton.h @@ -32,13 +32,10 @@ #pragma once #endif - -/* <31b2a> ../common/kbutton.h:7 */ typedef struct kbutton_s { int down[2]; int state; } kbutton_t; - #endif // KBUTTON_H diff --git a/common/mathlib.h b/common/mathlib.h index bc93a60..af30ae7 100644 --- a/common/mathlib.h +++ b/common/mathlib.h @@ -1,37 +1,47 @@ -/*** +/* * -* 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. -* All Rights Reserved. +* 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. * -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. +* 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 MATHLIB_H #define MATHLIB_H +#ifdef _WIN32 +#pragma once +#endif -/* <42b7f> ../common/mathlib.h:3 */ typedef float vec_t; -/* <42b91> ../common/mathlib.h:6 */ #if !defined DID_VEC3_T_DEFINE && !defined vec3_t #define DID_VEC3_T_DEFINE typedef vec_t vec3_t[3]; #endif -/* <80013> ../common/mathlib.h:8 */ typedef vec_t vec4_t[4]; +typedef int fixed16_t; -/* <42bac> ../common/mathlib.h:18 */ -typedef int fixed16_t; /* size: 4 */ - -/* <42bb7> ../common/mathlib.h:60 */ typedef union DLONG_u { int i[2]; @@ -55,32 +65,31 @@ typedef union DLONG_u #endif template -inline T min(T a, T b) { +inline T min(T a, T b) +{ return (a < b) ? a : b; } template -inline T max(T a, T b) { +inline T max(T a, T b) +{ return (a < b) ? b : a; } template -inline T clamp(T a, T min, T max) { +inline T clamp(T a, T min, T max) +{ return (a > max) ? max : (a < min) ? min : a; } template -inline T bswap(T s) { - switch (sizeof(T)) { -#ifdef _WIN32 - case 2: {auto res = _byteswap_ushort(*(uint16 *)&s); return *(T *)&res;} - case 4: {auto res = _byteswap_ulong(*(uint32 *)(&s)); return *(T *)&res;} - case 8: {auto res = _byteswap_uint64(*(uint64 *)&s); return *(T *)&res;} -#else - case 2: {auto res = _bswap16(*(uint16 *)&s); return *(T *)&res;} - case 4: {auto res = _bswap(*(uint32 *)&s); return *(T *)&res;} - case 8: {auto res = _bswap64(*(uint64 *)&s); return *(T *)&res;} -#endif +inline T bswap(T s) +{ + switch (sizeof(T)) + { + case 2: {auto res = __builtin_bswap16(*(uint16 *)&s); return *(T *)&res; } + case 4: {auto res = __builtin_bswap32(*(uint32 *)&s); return *(T *)&res; } + case 8: {auto res = __builtin_bswap64(*(uint64 *)&s); return *(T *)&res; } default: return s; } } diff --git a/common/md5.h b/common/md5.h new file mode 100644 index 0000000..637ba0f --- /dev/null +++ b/common/md5.h @@ -0,0 +1,34 @@ +/*** +* +* 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. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#pragma once + +#include + +// MD5 Hash +typedef struct +{ + unsigned int buf[4]; + unsigned int bits[2]; + unsigned char in[64]; +} MD5Context_t; + +void MD5Init(MD5Context_t *ctx); +void MD5Update(MD5Context_t *ctx, const unsigned char *buf, unsigned int len); +void MD5Final(unsigned char digest[16], MD5Context_t *ctx); +void MD5Transform(unsigned int buf[4], const unsigned int in[16]); + +BOOL MD5_Hash_File(unsigned char digest[16], char *pszFileName, BOOL bUsefopen, BOOL bSeed, unsigned int seed[4]); +char *MD5_Print(unsigned char hash[16]); diff --git a/common/netadr.h b/common/netadr.h index 304073c..0a468d2 100644 --- a/common/netadr.h +++ b/common/netadr.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ -// netadr.h + #ifndef NETADR_H #define NETADR_H #ifdef _WIN32 @@ -31,10 +31,10 @@ typedef enum typedef struct netadr_s { - netadrtype_t type; - unsigned char ip[4]; - unsigned char ipx[10]; - unsigned short port; + netadrtype_t type; + unsigned char ip[4]; + unsigned char ipx[10]; + unsigned short port; } netadr_t; #endif // NETADR_H diff --git a/common/netapi.cpp b/common/netapi.cpp new file mode 100644 index 0000000..7c69449 --- /dev/null +++ b/common/netapi.cpp @@ -0,0 +1,208 @@ +#include +#include + +#ifdef _WIN32 + #include "winsock.h" +#else + #include + #include + #include + #include + #include + #include +#endif // _WIN32 + +#include "netapi.h" + +class CNetAPI: public INetAPI { +public: + virtual void NetAdrToSockAddr(netadr_t *a, struct sockaddr *s); + virtual void SockAddrToNetAdr(struct sockaddr *s, netadr_t *a); + + virtual char *AdrToString(netadr_t *a); + virtual bool StringToAdr(const char *s, netadr_t *a); + + virtual void GetSocketAddress(int socket, netadr_t *a); + virtual bool CompareAdr(netadr_t *a, netadr_t *b); + virtual void GetLocalIP(netadr_t *a); +}; + +// Expose interface +CNetAPI g_NetAPI; +INetAPI *net = (INetAPI *)&g_NetAPI; + +void CNetAPI::NetAdrToSockAddr(netadr_t *a, struct sockaddr *s) +{ + memset(s, 0, sizeof(*s)); + + if (a->type == NA_BROADCAST) + { + ((struct sockaddr_in *)s)->sin_family = AF_INET; + ((struct sockaddr_in *)s)->sin_port = a->port; + ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST; + } + else if (a->type == NA_IP) + { + ((struct sockaddr_in *)s)->sin_family = AF_INET; + ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip; + ((struct sockaddr_in *)s)->sin_port = a->port; + } +} + +void CNetAPI::SockAddrToNetAdr(struct sockaddr *s, netadr_t *a) +{ + if (s->sa_family == AF_INET) + { + a->type = NA_IP; + *(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr; + a->port = ((struct sockaddr_in *)s)->sin_port; + } +} + +char *CNetAPI::AdrToString(netadr_t *a) +{ + static char s[64]; + memset(s, 0, sizeof(s)); + + if (a) + { + if (a->type == NA_LOOPBACK) + { + sprintf(s, "loopback"); + } + else if (a->type == NA_IP) + { + sprintf(s, "%i.%i.%i.%i:%i", a->ip[0], a->ip[1], a->ip[2], a->ip[3], ntohs(a->port)); + } + } + + return s; +} + +bool StringToSockaddr(const char *s, struct sockaddr *sadr) +{ + struct hostent *h; + char *colon; + char copy[128]; + struct sockaddr_in *p; + + memset(sadr, 0, sizeof(*sadr)); + + p = (struct sockaddr_in *)sadr; + p->sin_family = AF_INET; + p->sin_port = 0; + + strcpy(copy, s); + + // strip off a trailing :port if present + for (colon = copy ; *colon ; colon++) + { + if (*colon == ':') + { + // terminate + *colon = '\0'; + + // Start at next character + p->sin_port = htons((short)atoi(colon + 1)); + } + } + + // Numeric IP, no DNS + if (copy[0] >= '0' && copy[0] <= '9' && strstr(copy, ".")) + { + *(int *)&p->sin_addr = inet_addr(copy); + } + else + { + // DNS it + if (!(h = gethostbyname(copy))) + { + return false; + } + + // Use first result + *(int *)&p->sin_addr = *(int *)h->h_addr_list[0]; + } + + return true; +} + +bool CNetAPI::StringToAdr(const char *s, netadr_t *a) +{ + struct sockaddr sadr; + if (!strcmp(s, "localhost")) + { + memset(a, 0, sizeof(*a)); + a->type = NA_LOOPBACK; + return true; + } + + if (!StringToSockaddr(s, &sadr)) + { + return false; + } + + SockAddrToNetAdr(&sadr, a); + return true; +} + +// Lookup the IP address for the specified IP socket +void CNetAPI::GetSocketAddress(int socket, netadr_t *a) +{ + char buff[512]; + struct sockaddr_in address; + int namelen; + + memset(a, 0, sizeof(*a)); + gethostname(buff, sizeof(buff)); + + // Ensure that it doesn't overrun the buffer + buff[sizeof buff - 1] = '\0'; + StringToAdr(buff, a); + + namelen = sizeof(address); + if (getsockname(socket, (struct sockaddr *)&address, (int *)&namelen) == 0) + { + a->port = address.sin_port; + } +} + +bool CNetAPI::CompareAdr(netadr_t *a, netadr_t *b) +{ + if (a->type != b->type) + { + return false; + } + + if (a->type == NA_LOOPBACK) + { + return true; + } + + if (a->type == NA_IP && + a->ip[0] == b->ip[0] && + a->ip[1] == b->ip[1] && + a->ip[2] == b->ip[2] && + a->ip[3] == b->ip[3] && + a->port == b->port) + { + return true; + } + + return false; +} + +void CNetAPI::GetLocalIP(netadr_t *a) +{ + char s[64]; + if(!::gethostname(s, 64)) + { + struct hostent *localip = ::gethostbyname(s); + if(localip) + { + a->type = NA_IP; + a->port = 0; + memcpy(a->ip, localip->h_addr_list[0], 4); + } + } +} diff --git a/common/netapi.h b/common/netapi.h new file mode 100644 index 0000000..8401c92 --- /dev/null +++ b/common/netapi.h @@ -0,0 +1,25 @@ +#ifndef NETAPI_H +#define NETAPI_H +#ifdef _WIN32 +#pragma once +#endif + +#include "netadr.h" + +class INetAPI { +public: + virtual void NetAdrToSockAddr(netadr_t *a, struct sockaddr *s) = 0; // Convert a netadr_t to sockaddr + virtual void SockAddrToNetAdr(struct sockaddr *s, netadr_t *a) = 0; // Convert a sockaddr to netadr_t + + virtual char *AdrToString(netadr_t *a) = 0; // Convert a netadr_t to a string + virtual bool StringToAdr(const char *s, netadr_t *a) = 0; // Convert a string address to a netadr_t, doing DNS if needed + virtual void GetSocketAddress(int socket, netadr_t *a) = 0; // Look up IP address for socket + virtual bool CompareAdr(netadr_t *a, netadr_t *b) = 0; + + // return the IP of the local host + virtual void GetLocalIP(netadr_t *a) = 0; +}; + +extern INetAPI *net; + +#endif // NETAPI_H diff --git a/common/qlimits.h b/common/qlimits.h index 3fad403..c19e670 100644 --- a/common/qlimits.h +++ b/common/qlimits.h @@ -25,15 +25,19 @@ #define MAX_LIGHTSTYLE_INDEX_BITS 6 #define MAX_LIGHTSTYLES (1< ../common/quakedef.h:29 */ -typedef int BOOL; /* size: 4 */ +typedef int BOOL; // user message #define MAX_USER_MSG_DATA 192 -/* <627f> ../common/quakedef.h:137 */ //moved to com_model.h //typedef struct cache_user_s //{ // void *data; //} cache_user_t; -/* <4313b> ../common/quakedef.h:162 */ typedef int (*pfnUserMsgHook)(const char *, int, void *); diff --git a/common/stdc++compat.cpp b/common/stdc++compat.cpp new file mode 100644 index 0000000..6177fee --- /dev/null +++ b/common/stdc++compat.cpp @@ -0,0 +1,33 @@ +#include + +#if !defined(_WIN32) +void NORETURN Sys_Error(const char *error, ...); + +// This file adds the necessary compatibility tricks to avoid symbols with +// version GLIBCXX_3.4.16 and bigger, keeping binary compatibility with libstdc++ 4.6.1. +namespace std +{ + // We shouldn't be throwing exceptions at all, but it sadly turns out we call STL (inline) functions that do. + void __throw_out_of_range_fmt(const char *fmt, ...) + { + va_list ap; + char buf[1024]; // That should be big enough. + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + buf[sizeof(buf) - 1] = '\0'; + va_end(ap); + + Sys_Error(buf); + } +}; // namespace std + +// Technically, this symbol is not in GLIBCXX_3.4.20, but in CXXABI_1.3.8, +// but that's equivalent, version-wise. Those calls are added by the compiler +// itself on `new Class[n]` calls. +extern "C" +void __cxa_throw_bad_array_new_length() +{ + Sys_Error("Bad array new length."); +} +#endif // !defined(_WIN32) diff --git a/common/textconsole.cpp b/common/textconsole.cpp new file mode 100644 index 0000000..076137d --- /dev/null +++ b/common/textconsole.cpp @@ -0,0 +1,394 @@ +/* +* +* 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) +{ + // NULL or a valid base system interface + m_System = system; + + memset(m_szConsoleText, 0, sizeof(m_szConsoleText)); + m_nConsoleTextLen = 0; + m_nCursorPosition = 0; + + memset(m_szSavedConsoleText, 0, sizeof(m_szSavedConsoleText)); + m_nSavedConsoleTextLen = 0; + + memset(m_aszLineBuffer, 0, sizeof(m_aszLineBuffer)); + m_nTotalLines = 0; + m_nInputLine = 0; + m_nBrowseLine = 0; + + // these are log messages, not related to console + Sys_Printf("\n"); + Sys_Printf("Console initialized.\n"); + + m_ConsoleVisible = true; + + return true; +} + +void CTextConsole::SetVisible(bool visible) +{ + m_ConsoleVisible = visible; +} + +bool CTextConsole::IsVisible() +{ + return m_ConsoleVisible; +} + +void CTextConsole::ShutDown() +{ + ; +} + +void CTextConsole::Print(char *pszMsg) +{ + if (m_nConsoleTextLen) + { + int nLen = m_nConsoleTextLen; + while (nLen--) + { + PrintRaw("\b \b"); + } + } + + PrintRaw(pszMsg); + + if (m_nConsoleTextLen) + { + PrintRaw(m_szConsoleText, m_nConsoleTextLen); + } + + UpdateStatus(); +} + +int CTextConsole::ReceiveNewline() +{ + int nLen = 0; + + Echo("\n"); + + if (m_nConsoleTextLen) + { + nLen = m_nConsoleTextLen; + + m_szConsoleText[ m_nConsoleTextLen ] = '\0'; + m_nConsoleTextLen = 0; + m_nCursorPosition = 0; + + // cache line in buffer, but only if it's not a duplicate of the previous line + if ((m_nInputLine == 0) || (strcmp(m_aszLineBuffer[ m_nInputLine - 1 ], m_szConsoleText))) + { + strncpy(m_aszLineBuffer[ m_nInputLine ], m_szConsoleText, MAX_CONSOLE_TEXTLEN); + m_nInputLine++; + + if (m_nInputLine > m_nTotalLines) + m_nTotalLines = m_nInputLine; + + if (m_nInputLine >= MAX_BUFFER_LINES) + m_nInputLine = 0; + + } + + m_nBrowseLine = m_nInputLine; + } + + return nLen; +} + +void CTextConsole::ReceiveBackspace() +{ + int nCount; + + if (m_nCursorPosition == 0) + { + return; + } + + m_nConsoleTextLen--; + m_nCursorPosition--; + + Echo("\b"); + + for (nCount = m_nCursorPosition; nCount < m_nConsoleTextLen; ++nCount) + { + m_szConsoleText[ nCount ] = m_szConsoleText[ nCount + 1 ]; + Echo(m_szConsoleText + nCount, 1); + } + + Echo(" "); + + nCount = m_nConsoleTextLen; + while (nCount >= m_nCursorPosition) + { + Echo("\b"); + nCount--; + } + + m_nBrowseLine = m_nInputLine; +} + +void CTextConsole::ReceiveTab() +{ +#ifndef LAUNCHER_FIXES + if (!m_System) + return; +#else + if (!rehldsFuncs || !m_nConsoleTextLen) + { + return; + } +#endif + ObjectList matches; + m_szConsoleText[ m_nConsoleTextLen ] = '\0'; +#ifndef LAUNCHER_FIXES + m_System->GetCommandMatches(m_szConsoleText, &matches); +#else + rehldsFuncs->GetCommandMatches(m_szConsoleText, &matches); +#endif + if (matches.IsEmpty()) + return; + + if (matches.CountElements() == 1) + { + char *pszCmdName = (char *)matches.GetFirst(); + char *pszRest = pszCmdName + strlen(m_szConsoleText); + + if (pszRest) + { + Echo(pszRest); + strcat(m_szConsoleText, pszRest); + m_nConsoleTextLen += strlen(pszRest); + + Echo(" "); + strcat(m_szConsoleText, " "); + m_nConsoleTextLen++; + } + } + else + { + int nLongestCmd = 0; + int nSmallestCmd = 0; + int nCurrentColumn; + int nTotalColumns; + char szCommonCmd[256];//Should be enough. + char szFormatCmd[256]; + char *pszSmallestCmd; + char *pszCurrentCmd = (char *)matches.GetFirst(); + nSmallestCmd = strlen(pszCurrentCmd); + pszSmallestCmd = pszCurrentCmd; + while (pszCurrentCmd) + { + if ((int)strlen(pszCurrentCmd) > nLongestCmd) + { + nLongestCmd = strlen(pszCurrentCmd); + } + if ((int)strlen(pszCurrentCmd) < nSmallestCmd) + { + nSmallestCmd = strlen(pszCurrentCmd); + pszSmallestCmd = pszCurrentCmd; + } + pszCurrentCmd = (char *)matches.GetNext(); + } + + nTotalColumns = (GetWidth() - 1) / (nLongestCmd + 1); + nCurrentColumn = 0; + + Echo("\n"); + Q_strcpy(szCommonCmd, pszSmallestCmd); + // Would be nice if these were sorted, but not that big a deal + pszCurrentCmd = (char *)matches.GetFirst(); + while (pszCurrentCmd) + { + if (++nCurrentColumn > nTotalColumns) + { + Echo("\n"); + nCurrentColumn = 1; + } + + _snprintf(szFormatCmd, sizeof(szFormatCmd), "%-*s ", nLongestCmd, pszCurrentCmd); + Echo(szFormatCmd); + for (char *pCur = pszCurrentCmd, *pCommon = szCommonCmd; (*pCur&&*pCommon); pCur++, pCommon++) + { + if (*pCur != *pCommon) + { + *pCommon = 0; + break; + } + } + pszCurrentCmd = (char *)matches.GetNext(); + } + + Echo("\n"); + if (Q_strcmp(szCommonCmd, m_szConsoleText)) + { + Q_strcpy(m_szConsoleText, szCommonCmd); + m_nConsoleTextLen = Q_strlen(szCommonCmd); + } + + Echo(m_szConsoleText); + } + + m_nCursorPosition = m_nConsoleTextLen; + m_nBrowseLine = m_nInputLine; +} + +void CTextConsole::ReceiveStandardChar(const char ch) +{ + int nCount; + + // If the line buffer is maxed out, ignore this char + if (m_nConsoleTextLen >= (sizeof(m_szConsoleText) - 2)) + { + return; + } + + nCount = m_nConsoleTextLen; + while (nCount > m_nCursorPosition) + { + m_szConsoleText[ nCount ] = m_szConsoleText[ nCount - 1 ]; + nCount--; + } + + m_szConsoleText[ m_nCursorPosition ] = ch; + + Echo(m_szConsoleText + m_nCursorPosition, m_nConsoleTextLen - m_nCursorPosition + 1); + + m_nConsoleTextLen++; + m_nCursorPosition++; + + nCount = m_nConsoleTextLen; + while (nCount > m_nCursorPosition) + { + Echo("\b"); + nCount--; + } + + m_nBrowseLine = m_nInputLine; +} + +void CTextConsole::ReceiveUpArrow() +{ + int nLastCommandInHistory = m_nInputLine + 1; + if (nLastCommandInHistory > m_nTotalLines) + nLastCommandInHistory = 0; + + if (m_nBrowseLine == nLastCommandInHistory) + return; + + if (m_nBrowseLine == m_nInputLine) + { + if (m_nConsoleTextLen > 0) + { + // Save off current text + strncpy(m_szSavedConsoleText, m_szConsoleText, m_nConsoleTextLen); + // No terminator, it's a raw buffer we always know the length of + } + + m_nSavedConsoleTextLen = m_nConsoleTextLen; + } + + m_nBrowseLine--; + if (m_nBrowseLine < 0) + { + m_nBrowseLine = m_nTotalLines - 1; + } + + // delete old line + while (m_nConsoleTextLen--) + { + Echo("\b \b"); + } + + // copy buffered line + Echo(m_aszLineBuffer[ m_nBrowseLine ]); + + strncpy(m_szConsoleText, m_aszLineBuffer[ m_nBrowseLine ], MAX_CONSOLE_TEXTLEN); + + m_nConsoleTextLen = strlen(m_aszLineBuffer[ m_nBrowseLine ]); + m_nCursorPosition = m_nConsoleTextLen; +} + +void CTextConsole::ReceiveDownArrow() +{ + if (m_nBrowseLine == m_nInputLine) + return; + + if (++m_nBrowseLine > m_nTotalLines) + m_nBrowseLine = 0; + + // delete old line + while (m_nConsoleTextLen--) + { + Echo("\b \b"); + } + + if (m_nBrowseLine == m_nInputLine) + { + if (m_nSavedConsoleTextLen > 0) + { + // Restore current text + strncpy(m_szConsoleText, m_szSavedConsoleText, m_nSavedConsoleTextLen); + // No terminator, it's a raw buffer we always know the length of + + Echo(m_szConsoleText, m_nSavedConsoleTextLen); + } + + m_nConsoleTextLen = m_nSavedConsoleTextLen; + } + else + { + // copy buffered line + Echo(m_aszLineBuffer[ m_nBrowseLine ]); + strncpy(m_szConsoleText, m_aszLineBuffer[ m_nBrowseLine ], MAX_CONSOLE_TEXTLEN); + m_nConsoleTextLen = strlen(m_aszLineBuffer[ m_nBrowseLine ]); + } + + m_nCursorPosition = m_nConsoleTextLen; +} + +void CTextConsole::ReceiveLeftArrow() +{ + if (m_nCursorPosition == 0) + return; + + Echo("\b"); + m_nCursorPosition--; +} + +void CTextConsole::ReceiveRightArrow() +{ + if (m_nCursorPosition == m_nConsoleTextLen) + return; + + Echo(m_szConsoleText + m_nCursorPosition, 1); + m_nCursorPosition++; +} diff --git a/common/textconsole.h b/common/textconsole.h new file mode 100644 index 0000000..25fc128 --- /dev/null +++ b/common/textconsole.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 "IBaseSystem.h" + +#define MAX_CONSOLE_TEXTLEN 256 +#define MAX_BUFFER_LINES 30 + +class CTextConsole { +public: + virtual ~CTextConsole() {} + + virtual bool Init(IBaseSystem *system = nullptr); + virtual void ShutDown(); + virtual void Print(char *pszMsg); + + virtual void SetTitle(char *pszTitle) {} + virtual void SetStatusLine(char *pszStatus) {} + virtual void UpdateStatus() {} + + // Must be provided by children + virtual void PrintRaw(char *pszMsg, int nChars = 0) = 0; + virtual void Echo(char *pszMsg, int nChars = 0) = 0; + virtual char *GetLine() = 0; + virtual int GetWidth() = 0; + + virtual void SetVisible(bool visible); + virtual bool IsVisible(); + +protected: + char m_szConsoleText[MAX_CONSOLE_TEXTLEN]; // console text buffer + int m_nConsoleTextLen; // console textbuffer length + int m_nCursorPosition; // position in the current input line + + // Saved input data when scrolling back through command history + char m_szSavedConsoleText[MAX_CONSOLE_TEXTLEN]; // console text buffer + int m_nSavedConsoleTextLen; // console textbuffer length + + char m_aszLineBuffer[MAX_BUFFER_LINES][MAX_CONSOLE_TEXTLEN]; // command buffer last MAX_BUFFER_LINES commands + int m_nInputLine; // Current line being entered + int m_nBrowseLine; // current buffer line for up/down arrow + int m_nTotalLines; // # of nonempty lines in the buffer + + bool m_ConsoleVisible; + + IBaseSystem *m_System; + + int ReceiveNewline(); + void ReceiveBackspace(); + void ReceiveTab(); + void ReceiveStandardChar(const char ch); + void ReceiveUpArrow(); + void ReceiveDownArrow(); + void ReceiveLeftArrow(); + void ReceiveRightArrow(); +}; + +#include "SteamAppStartUp.h" + +#if defined(_WIN32) + #include "TextConsoleWin32.h" +#else + #include "TextConsoleUnix.h" +#endif // defined(_WIN32) + +void Sys_Printf(char *fmt, ...); diff --git a/common/vmodes.h b/common/vmodes.h index 5d4384f..9765bca 100644 --- a/common/vmodes.h +++ b/common/vmodes.h @@ -27,8 +27,6 @@ */ #pragma once - -/* <430ee> ../common/vmodes.h:40 */ typedef struct rect_s { int left, right, top, bottom; diff --git a/engine/cmd_rehlds.h b/engine/cmd_rehlds.h index efa8393..003cb60 100644 --- a/engine/cmd_rehlds.h +++ b/engine/cmd_rehlds.h @@ -33,7 +33,7 @@ typedef void(*xcommand_t)(void); typedef struct cmd_function_s { struct cmd_function_s *next; - char *name; + const char *name; xcommand_t function; int flags; } cmd_function_t; diff --git a/engine/consistency.h b/engine/consistency.h index a89a0d0..7ca108c 100644 --- a/engine/consistency.h +++ b/engine/consistency.h @@ -26,18 +26,13 @@ * */ -#ifndef CONSISTENCY_H -#define CONSISTENCY_H -#ifdef _WIN32 #pragma once -#endif -#define MAX_CONSISTENCY_LIST 512 +const int MAX_CONSISTENCY_LIST = 512; -/* <7508> ../engine/consistency.h:9 */ typedef struct consistency_s { - char * filename; + char *filename; int issound; int orig_index; int value; @@ -45,5 +40,3 @@ typedef struct consistency_s float mins[3]; float maxs[3]; } consistency_t; - -#endif // CONSISTENCY_H \ No newline at end of file diff --git a/engine/custom.h b/engine/custom.h index 5a5156e..333a4a0 100644 --- a/engine/custom.h +++ b/engine/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 @@ -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. @@ -75,14 +82,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/engine/eiface.h b/engine/eiface.h index e377975..b2b2233 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -144,11 +144,11 @@ typedef struct enginefuncs_s const char *(*pfnTraceTexture) (edict_t *pTextureEntity, const float *v1, const float *v2 ); void (*pfnTraceSphere) (const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr); void (*pfnGetAimVector) (edict_t* ent, float speed, float *rgflReturn); - void (*pfnServerCommand) (char* str); + void (*pfnServerCommand) (const char* str); void (*pfnServerExecute) (void); - void (*pfnClientCommand) (edict_t* pEdict, char* szFmt, ...); + void (*pfnClientCommand) (edict_t* pEdict, const char* szFmt, ...); void (*pfnParticleEffect) (const float *org, const float *dir, float color, float count); - void (*pfnLightStyle) (int style, char* val); + void (*pfnLightStyle) (int style, const char* val); int (*pfnDecalIndex) (const char *name); int (*pfnPointContents) (const float *rgflVector); void (*pfnMessageBegin) (int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); @@ -200,7 +200,7 @@ typedef struct enginefuncs_s void (*pfnSetView) (const edict_t *pClient, const edict_t *pViewent ); float (*pfnTime) ( void ); void (*pfnCrosshairAngle) (const edict_t *pClient, float pitch, float yaw); - byte * (*pfnLoadFileForMe) (char *filename, int *pLength); + byte * (*pfnLoadFileForMe) (const char *filename, int *pLength); void (*pfnFreeFile) (void *buffer); void (*pfnEndSection) (const char *pszSectionName); // trigger_endsection int (*pfnCompareFileTime) (char *filename1, char *filename2, int *iCompare); @@ -215,9 +215,9 @@ typedef struct enginefuncs_s char* (*pfnInfoKeyValue) (char *infobuffer, const char *key); void (*pfnSetKeyValue) (char *infobuffer, const char *key, const char *value); void (*pfnSetClientKeyValue) (int clientIndex, char *infobuffer, const char *key, const char *value); - int (*pfnIsMapValid) (char *filename); + int (*pfnIsMapValid) (const char *filename); void (*pfnStaticDecal) ( const float *origin, int decalIndex, int entityIndex, int modelIndex ); - int (*pfnPrecacheGeneric) (char* s); + int (*pfnPrecacheGeneric) (const char* s); int (*pfnGetPlayerUserId) (edict_t *e ); // returns the server assigned userid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients void (*pfnBuildSoundMsg) (edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); int (*pfnIsDedicatedServer) (void);// is this a dedicated server? @@ -239,7 +239,7 @@ typedef struct enginefuncs_s void (*pfnDeltaSetField) ( struct delta_s *pFields, const char *fieldname ); void (*pfnDeltaUnsetField) ( struct delta_s *pFields, const char *fieldname ); - void (*pfnDeltaAddEncoder) ( char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) ); + void (*pfnDeltaAddEncoder) ( const char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) ); int (*pfnGetCurrentPlayer) ( void ); int (*pfnCanSkipPlayer) ( const edict_t *player ); int (*pfnDeltaFindField) ( struct delta_s *pFields, const char *fieldname ); @@ -258,7 +258,7 @@ typedef struct enginefuncs_s void (*pfnGetPlayerStats) ( const edict_t *pClient, int *ping, int *packet_loss ); - void (*pfnAddServerCommand) ( char *cmd_name, void (*function) (void) ); + void (*pfnAddServerCommand) ( const char *cmd_name, void (*function) (void) ); // For voice communications, set which clients hear eachother. // NOTE: these functions take player entity indices (starting at 1). @@ -274,7 +274,7 @@ typedef struct enginefuncs_s sentenceEntry_s* (*pfnSequencePickSentence) ( const char* groupName, int pickMethod, int *picked ); // LH: Give access to filesize via filesystem - int (*pfnGetFileSize) ( char *filename ); + int (*pfnGetFileSize) ( const char *filename ); unsigned int (*pfnGetApproxWavePlayLen) (const char *filepath); // MDC: Added for CZ career-mode diff --git a/engine/maintypes.h b/engine/maintypes.h index 40ae20c..f55bac9 100644 --- a/engine/maintypes.h +++ b/engine/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,9 +42,29 @@ // Function is not tested at all. #define UNTESTED +#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; -typedef unsigned int string_t; // from engine's pr_comp.h; +// From engine/server.h +typedef enum sv_delta_s +{ + sv_packet_nodelta, + sv_packet_delta, +} sv_delta_t; #endif // MAINTYPES_H diff --git a/engine/model.h b/engine/model.h index ba5d638..354a815 100644 --- a/engine/model.h +++ b/engine/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/engine/osconfig.h b/engine/osconfig.h index 5d14deb..5b21303 100644 --- a/engine/osconfig.h +++ b/engine/osconfig.h @@ -79,9 +79,6 @@ #include #include #include - - // Deail with stupid macro in kernel.h - #undef __FUNCTION__ #endif // _WIN32 #include @@ -92,7 +89,13 @@ #include #include + #ifdef _WIN32 // WINDOWS + // Define __func__ on VS less than 2015 + #if _MSC_VER < 1900 + #define __func__ __FUNCTION__ + #endif + #define _CRT_SECURE_NO_WARNINGS #define WIN32_LEAN_AND_MEAN @@ -103,8 +106,13 @@ #define HIDDEN #define NOINLINE __declspec(noinline) #define ALIGN16 __declspec(align(16)) + #define NORETURN __declspec(noreturn) #define FORCE_STACK_ALIGN + #define __builtin_bswap16 _byteswap_ushort + #define __builtin_bswap32 _byteswap_ulong + #define __builtin_bswap64 _byteswap_uint64 + //inline bool SOCKET_FIONBIO(SOCKET s, int m) { return (ioctlsocket(s, FIONBIO, (u_long*)&m) == 0); } //inline int SOCKET_MSGLEN(SOCKET s, u_long& r) { return ioctlsocket(s, FIONREAD, (u_long*)&r); } typedef int socklen_t; @@ -123,11 +131,6 @@ VirtualFree(ptr, 0, MEM_RELEASE); } #else // _WIN32 - #ifdef __FUNCTION__ - #undef __FUNCTION__ - #endif - #define __FUNCTION__ __func__ - #ifndef PAGESIZE #define PAGESIZE 4096 #endif @@ -135,10 +138,7 @@ #define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) #define _MAX_FNAME NAME_MAX - - #ifndef MAX_PATH - #define MAX_PATH 260 - #endif // MAX_PATH + #define MAX_PATH 260 typedef void *HWND; @@ -151,8 +151,15 @@ #define HIDDEN __attribute__((visibility("hidden"))) #define NOINLINE __attribute__((noinline)) #define ALIGN16 __attribute__((aligned(16))) + #define NORETURN __attribute__((noreturn)) #define FORCE_STACK_ALIGN __attribute__((force_align_arg_pointer)) +#if defined __INTEL_COMPILER + #define __builtin_bswap16 _bswap16 + #define __builtin_bswap32 _bswap + #define __builtin_bswap64 _bswap64 +#endif // __INTEL_COMPILER + //inline bool SOCKET_FIONBIO(SOCKET s, int m) { return (ioctl(s, FIONBIO, (int*)&m) == 0); } //inline int SOCKET_MSGLEN(SOCKET s, u_long& r) { return ioctl(s, FIONREAD, (int*)&r); } typedef int SOCKET; @@ -165,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); } @@ -192,4 +203,8 @@ #define EXT_FUNC FORCE_STACK_ALIGN +// Used to obtain the string name of a variable. +#define nameof_variable(name) template_nameof_variable(name, #name) +template const char* template_nameof_variable(const T& /*validate_type*/, const char* name) { return name; } + #endif // _OSCONFIG_H diff --git a/engine/rehlds_api.h b/engine/rehlds_api.h index 2f4a115..f0c1559 100644 --- a/engine/rehlds_api.h +++ b/engine/rehlds_api.h @@ -267,7 +267,7 @@ struct RehldsFuncs_t { cvar_t*(*GetCvarVars)(); int (*SV_GetChallenge)(const netadr_t& adr); void (*SV_AddResource)(resourcetype_t type, const char *name, int size, unsigned char flags, int index); - int(*MSG_ReadShort)(void); + int(*MSG_ReadShort)(); int(*MSG_ReadBuf)(int iSize, void *pbuf); void(*MSG_WriteBuf)(sizebuf_t *sb, int iSize, void *buf); void(*MSG_WriteByte)(sizebuf_t *sb, int c); @@ -297,4 +297,4 @@ public: virtual IRehldsFlightRecorder* GetFlightRecorder() = 0; }; -#define VREHLDS_HLDS_API_VERSION "VREHLDS_HLDS_API_VERSION001" \ No newline at end of file +#define VREHLDS_HLDS_API_VERSION "VREHLDS_HLDS_API_VERSION001" diff --git a/engine/static_map.h b/engine/static_map.h index 7138aff..d19033a 100644 --- a/engine/static_map.h +++ b/engine/static_map.h @@ -44,7 +44,7 @@ private: // this was a root node unsigned int rootId = GetRoodNodeId(node->key); if (m_RootNodes[rootId] != node) { - Sys_Error(__FUNCTION__ ": invalid root node"); + Sys_Error("%s: invalid root node", __func__); return; } diff --git a/engine/sys_shared.cpp b/engine/sys_shared.cpp index a642c76..b9a5033 100644 --- a/engine/sys_shared.cpp +++ b/engine/sys_shared.cpp @@ -29,6 +29,8 @@ #if defined(__GNUC__) #include +#elif _MSC_VER >= 1400 && !defined(ASMLIB_H) +#include // __cpuidex #endif #define SSE3_FLAG (1<<0) @@ -69,4 +71,4 @@ void Sys_CheckCpuInstructionsSupport(void) #endif cpuinfo.avx2 = (cpuid_data[1] & AVX2_FLAG) ? 1 : 0; // ebx -} \ No newline at end of file +} diff --git a/msvc/rechecker.vcxproj b/msvc/rechecker.vcxproj index a52f06f..fe35156 100644 --- a/msvc/rechecker.vcxproj +++ b/msvc/rechecker.vcxproj @@ -162,7 +162,6 @@ - @@ -178,11 +177,9 @@ true true - - Use - + @@ -260,7 +257,8 @@ rechecker.def - IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") +IF EXIST "$(ProjectDir)ServerStart_cs_6153.bat" (CALL "$(ProjectDir)ServerStart_cs_6153.bat") Automatic deployment script diff --git a/msvc/rechecker.vcxproj.filters b/msvc/rechecker.vcxproj.filters index 55170fd..171af61 100644 --- a/msvc/rechecker.vcxproj.filters +++ b/msvc/rechecker.vcxproj.filters @@ -454,9 +454,6 @@ sdk\public - - sdk\public - @@ -475,9 +472,6 @@ sdk\common - - sdk\public - @@ -490,6 +484,7 @@ + diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h index a80fd70..a6248d9 100644 --- a/pm_shared/pm_defs.h +++ b/pm_shared/pm_defs.h @@ -208,7 +208,7 @@ typedef struct playermove_s void (*PM_GetModelBounds)( struct model_s *mod, float *mins, float *maxs ); void *(*PM_HullForBsp)( physent_t *pe, float *offset ); float (*PM_TraceModel)( physent_t *pEnt, float *start, float *end, trace_t *trace ); - int (*COM_FileSize)(char *filename); + int (*COM_FileSize)(const char *filename); byte *(*COM_LoadFile) (const char *path, int usehunk, int *pLength); void (*COM_FreeFile) ( void *buffer ); char *(*memfgets)( byte *pMemFile, int fileSize, int *pFilePos, char *pBuffer, int bufferSize ); diff --git a/public/FileSystem.h b/public/FileSystem.h index e1ce53c..e2b8928 100644 --- a/public/FileSystem.h +++ b/public/FileSystem.h @@ -1,32 +1,54 @@ -//========= 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" +#else + #define STDIO_FILESYSTEM_LIB "filesystem_stdio.so" + #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 { @@ -42,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 + // 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, + // 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; - - // 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 bool AddPackFile(const char *fullpath, const char *pathID) = 0; - virtual void AddSearchPathNoWrite( const char *pPath, 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; }; // Steam3/Src compat #define IBaseFileSystem IFileSystem #define FILESYSTEM_INTERFACE_VERSION "VFileSystem009" - -#endif // FILESYSTEM_H diff --git a/public/engine_hlds_api.h b/public/engine_hlds_api.h index 3147083..53ceb36 100644 --- a/public/engine_hlds_api.h +++ b/public/engine_hlds_api.h @@ -28,16 +28,20 @@ #pragma once -#include "maintypes.h" #include "interface.h" +#ifdef _WIN32 + #define ENGINE_LIB "swds.dll" +#else + #define ENGINE_LIB "engine_i486.so" +#endif // _WIN32 + 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/public/engine_launcher_api.h b/public/engine_launcher_api.h index 74f1b69..1c60e6a 100644 --- a/public/engine_launcher_api.h +++ b/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/public/icommandline.h b/public/icommandline.h new file mode 100644 index 0000000..a06ba94 --- /dev/null +++ b/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/public/idedicatedexports.h b/public/idedicatedexports.h index 2f6e255..5cbe36c 100644 --- a/public/idedicatedexports.h +++ b/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/public/interface.cpp b/public/interface.cpp index 67c3748..1bd0c92 100644 --- a/public/interface.cpp +++ b/public/interface.cpp @@ -1,25 +1,98 @@ -#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. +* +*/ -#if !defined ( _WIN32 ) +#include "interface.h" + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include "windows.h" +#endif // _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 @@ -28,151 +101,67 @@ 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 ) +CSysModule *Sys_LoadModule(const char *pModuleName) { -#if defined ( _WIN32 ) - HMODULE hDLL = LoadLibrary( pModuleName ); +#ifdef _WIN32 + HMODULE hDLL = LoadLibrary(pModuleName); #else - HMODULE hDLL = NULL; + HMODULE hDLL = nullptr; 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 ); + _snprintf(szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s", pModuleName); + hDLL = dlopen(pModuleName, RTLD_NOW); } -#endif +#endif // _WIN32 - if( !hDLL ) + if (!hDLL) { char str[512]; -#if defined ( _WIN32 ) - _snprintf( str, sizeof(str), "%s.dll", pModuleName ); - hDLL = LoadLibrary( str ); + +#if defined(_WIN32) + _snprintf(str, sizeof(str), "%s.dll", pModuleName); + hDLL = LoadLibrary(str); #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(str, sizeof(str), "%s.dylib", szAbsoluteModuleName); + hDLL = dlopen(str, RTLD_NOW); #else - printf("Error:%s\n",dlerror()); - _snprintf( str, sizeof(str), "%s.so", szAbsoluteModuleName ); + printf("Error: %s\n", dlerror()); + _snprintf(str, sizeof(str), "%s.so", szAbsoluteModuleName); hDLL = dlopen(str, RTLD_NOW); #endif } @@ -180,83 +169,68 @@ CSysModule *Sys_LoadModule( const char *pModuleName ) 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/public/interface.h b/public/interface.h index 3349146..9773a99 100644 --- a/public/interface.h +++ b/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. @@ -8,22 +7,17 @@ // 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 -//#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,71 +69,55 @@ 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 // extend this for other error conditions/code -enum +enum { IFACE_OK = 0, 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/public/keydefs.h b/public/keydefs.h index 590367b..6f1e43f 100644 --- a/public/keydefs.h +++ b/public/keydefs.h @@ -121,4 +121,4 @@ #define K_MOUSE4 244 #define K_MOUSE5 245 -#endif // KEYDEFS_H \ No newline at end of file +#endif // KEYDEFS_H diff --git a/public/pman_particlemem.h b/public/pman_particlemem.h index 6ccb971..e2a03fc 100644 --- a/public/pman_particlemem.h +++ b/public/pman_particlemem.h @@ -194,4 +194,4 @@ public: }; -#endif//PARTICLEMEM_H__ \ No newline at end of file +#endif//PARTICLEMEM_H__ diff --git a/public/savegame_version.h b/public/savegame_version.h index 26749a5..f14564d 100644 --- a/public/savegame_version.h +++ b/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/public/tier0/dbg.cpp b/public/tier0/dbg.cpp new file mode 100644 index 0000000..58dabd0 --- /dev/null +++ b/public/tier0/dbg.cpp @@ -0,0 +1,435 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// The main debug library implementation +//============================================================================= + +#include "precompiled.h" + +//----------------------------------------------------------------------------- +// internal structures +//----------------------------------------------------------------------------- + +enum +{ + MAX_GROUP_NAME_LENGTH = 48 +}; + +struct SpewGroup_t +{ + char m_GroupName[MAX_GROUP_NAME_LENGTH]; + int m_Level; +}; + + +//----------------------------------------------------------------------------- +// Templates to assist in validating pointers: + +void _AssertValidReadPtr(void* ptr, int count/* = 1*/) +{ +#ifdef _WIN32 + Assert(!IsBadReadPtr(ptr, count)); +#else + Assert(ptr); +#endif + +} + +void _AssertValidWritePtr(void* ptr, int count/* = 1*/) +{ +#ifdef _WIN32 + Assert(!IsBadWritePtr(ptr, count)); +#else + Assert(ptr); +#endif +} + +void _AssertValidReadWritePtr(void* ptr, int count/* = 1*/) +{ +#ifdef _WIN32 + Assert(!(IsBadWritePtr(ptr, count) || IsBadReadPtr(ptr, count))); +#else + Assert(ptr); +#endif +} + +void AssertValidStringPtr(const char* ptr, int maxchar/* = 0xFFFFFF */) +{ +#ifdef _WIN32 + Assert(!IsBadStringPtr(ptr, maxchar)); +#else + Assert(ptr); +#endif +} + + +//----------------------------------------------------------------------------- +// globals +//----------------------------------------------------------------------------- + +SpewRetval_t DefaultSpewFunc(SpewType_t type, char const *pMsg) +{ + printf("%s", pMsg); + if (type == SPEW_ASSERT) + return SPEW_DEBUGGER; + else if (type == SPEW_ERROR) + return SPEW_ABORT; + else + return SPEW_CONTINUE; +} + +static SpewOutputFunc_t s_SpewOutputFunc = DefaultSpewFunc; + +static char const* s_pFileName; +static int s_Line; +static SpewType_t s_SpewType; + +static SpewGroup_t* s_pSpewGroups = 0; +static int s_GroupCount = 0; +static int s_DefaultLevel = 0; + + + +//----------------------------------------------------------------------------- +// Spew output management. +//----------------------------------------------------------------------------- + +void SpewOutputFunc(SpewOutputFunc_t func) +{ + s_SpewOutputFunc = func ? func : DefaultSpewFunc; +} + +SpewOutputFunc_t GetSpewOutputFunc(void) +{ + if (s_SpewOutputFunc) + { + return s_SpewOutputFunc; + } + else + { + return DefaultSpewFunc; + } +} + +//----------------------------------------------------------------------------- +// Spew functions +//----------------------------------------------------------------------------- + +void _SpewInfo(SpewType_t type, char const* pFile, int line) +{ + // Only grab the file name. Ignore the path. + char const* pSlash = strrchr(pFile, '\\'); + char const* pSlash2 = strrchr(pFile, '/'); + if (pSlash < pSlash2) pSlash = pSlash2; + + s_pFileName = pSlash ? pSlash + 1 : pFile; + s_Line = line; + s_SpewType = type; +} + +SpewRetval_t _SpewMessage(SpewType_t spewType, char const* pMsgFormat, va_list args) +{ + char pTempBuffer[1024]; + + /* Printf the file and line for warning + assert only... */ + int len = 0; + if ((spewType == SPEW_ASSERT)) + { + len = sprintf(pTempBuffer, "%s (%d) : ", s_pFileName, s_Line); + } + + /* Create the message.... */ + len += vsprintf(&pTempBuffer[len], pMsgFormat, args); + + // Add \n for warning and assert + if ((spewType == SPEW_ASSERT)) + { + len += sprintf(&pTempBuffer[len], "\n"); + } + + assert(len < 1024); /* use normal assert here; to avoid recursion. */ + assert(s_SpewOutputFunc); + + /* direct it to the appropriate target(s) */ + SpewRetval_t ret = s_SpewOutputFunc(spewType, pTempBuffer); + switch (ret) + { + // Put the break into the macro so it would occur in the right place + // case SPEW_DEBUGGER: + // DebuggerBreak(); + // break; + + case SPEW_ABORT: + // MessageBox(NULL,"Error in _SpewMessage","Error",MB_OK); + exit(0); + default: + break; + } + + return ret; +} + +SpewRetval_t _SpewMessage(char const* pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args); + va_end(args); + return ret; +} + +SpewRetval_t _DSpewMessage(char const *pGroupName, int level, char const* pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return SPEW_CONTINUE; + + va_list args; + va_start(args, pMsgFormat); + SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args); + va_end(args); + return ret; +} + +void Msg(char const* pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void DMsg(char const *pGroupName, int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void Warning(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void DWarning(char const *pGroupName, int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void Log(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +void DLog(char const *pGroupName, int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +void Error(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_ERROR, pMsgFormat, args); + va_end(args); +} + + +//----------------------------------------------------------------------------- +// A couple of super-common dynamic spew messages, here for convenience +// These looked at the "developer" group, print if it's level 1 or higher +//----------------------------------------------------------------------------- + +void DevMsg(int level, char const* pMsgFormat, ...) +{ + if (!IsSpewActive("developer", level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void DevWarning(int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive("developer", level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void DevLog(int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive("developer", level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +void DevMsg(char const *pMsgFormat, ...) +{ + if (!IsSpewActive("developer", 1)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void DevWarning(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void DevLog(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +//----------------------------------------------------------------------------- +// Find a group, return true if found, false if not. Return in ind the +// index of the found group, or the index of the group right before where the +// group should be inserted into the list to maintain sorted order. +//----------------------------------------------------------------------------- + +bool FindSpewGroup(char const* pGroupName, int* pInd) +{ + int s = 0; + if (s_GroupCount) + { + int e = (int)(s_GroupCount - 1); + while (s <= e) + { + int m = (s + e) >> 1; + int cmp = Q_stricmp(pGroupName, s_pSpewGroups[m].m_GroupName); + if (!cmp) + { + *pInd = m; + return true; + } + if (cmp < 0) + e = m - 1; + else + s = m + 1; + } + } + *pInd = s; + return false; +} + + +//----------------------------------------------------------------------------- +// Sets the priority level for a spew group +//----------------------------------------------------------------------------- + +void SpewActivate(char const* pGroupName, int level) +{ + Assert(pGroupName); + + // check for the default group first... + if ((pGroupName[0] == '*') && (pGroupName[1] == '\0')) + { + s_DefaultLevel = level; + return; + } + + // Normal case, search in group list using binary search. + // If not found, grow the list of groups and insert it into the + // right place to maintain sorted order. Then set the level. + int ind; + if (!FindSpewGroup(pGroupName, &ind)) + { + // not defined yet, insert an entry. + ++s_GroupCount; + if (s_pSpewGroups) + { + s_pSpewGroups = (SpewGroup_t*)realloc(s_pSpewGroups, + s_GroupCount * sizeof(SpewGroup_t)); + + // shift elements down to preserve order + int numToMove = s_GroupCount - ind - 1; + memmove(&s_pSpewGroups[ind + 1], &s_pSpewGroups[ind], + numToMove * sizeof(SpewGroup_t)); + } + else + s_pSpewGroups = (SpewGroup_t*)malloc(s_GroupCount * sizeof(SpewGroup_t)); + + Assert(strlen(pGroupName) < MAX_GROUP_NAME_LENGTH); + strcpy(s_pSpewGroups[ind].m_GroupName, pGroupName); + } + s_pSpewGroups[ind].m_Level = level; +} + + +//----------------------------------------------------------------------------- +// Tests to see if a particular spew is active +//----------------------------------------------------------------------------- + +bool IsSpewActive(char const* pGroupName, int level) +{ + // If we don't find the spew group, use the default level. + int ind; + if (FindSpewGroup(pGroupName, &ind)) + return s_pSpewGroups[ind].m_Level >= level; + else + return s_DefaultLevel >= level; +} + + +// If we don't have a function from math.h, then it doesn't link certain floating-point +// functions in and printfs with %f cause runtime errors in the C libraries. +float CrackSmokingCompiler(float a) +{ + return fabs(a); +} + +void* Plat_SimpleLog(const char* file, int line) +{ + FILE* f = fopen("simple.log", "at+"); + fprintf(f, "%s:%i\n", file, line); + fclose(f); + + return NULL; +} diff --git a/public/tier0/dbg.h b/public/tier0/dbg.h new file mode 100644 index 0000000..37b4d0a --- /dev/null +++ b/public/tier0/dbg.h @@ -0,0 +1,453 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// The main debug library interfaces +//============================================================================= + + +#ifndef DBG_H +#define DBG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include "basetypes.h" +#include "tier0/platform.h" +#include +#include +#include + + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- + +#ifdef TIER0_DLL_EXPORT +#define DBG_INTERFACE DLL_EXPORT +#define DBG_OVERLOAD DLL_GLOBAL_EXPORT +#define DBG_CLASS DLL_CLASS_EXPORT +#else +#define DBG_INTERFACE DLL_IMPORT +#define DBG_OVERLOAD DLL_GLOBAL_IMPORT +#define DBG_CLASS DLL_CLASS_IMPORT +#endif + + +//----------------------------------------------------------------------------- +// Usage model for the Dbg library +// +// 1. Spew. +// +// Spew can be used in a static and a dynamic mode. The static +// mode allows us to display assertions and other messages either only +// in debug builds, or in non-release builds. The dynamic mode allows us to +// turn on and off certain spew messages while the application is running. +// +// Static Spew messages: +// +// Assertions are used to detect and warn about invalid states +// Spews are used to display a particular status/warning message. +// +// To use an assertion, use +// +// Assert( (f == 5) ); +// AssertMsg( (f == 5), ("F needs to be %d here!\n", 5) ); +// AssertFunc( (f == 5), BadFunc() ); +// AssertEquals( f, 5 ); +// AssertFloatEquals( f, 5.0f, 1e-3 ); +// +// The first will simply report that an assertion failed on a particular +// code file and line. The second version will display a print-f formatted message +// along with the file and line, the third will display a generic message and +// will also cause the function BadFunc to be executed, and the last two +// will report an error if f is not equal to 5 (the last one asserts within +// a particular tolerance). +// +// To use a warning, use +// +// Warning("Oh I feel so %s all over\n", "yummy"); +// +// Warning will do its magic in only Debug builds. To perform spew in *all* +// builds, use RelWarning. +// +// Three other spew types, Msg, Log, and Error, are compiled into all builds. +// These error types do *not* need two sets of parenthesis. +// +// Msg( "Isn't this exciting %d?", 5 ); +// Error( "I'm just thrilled" ); +// +// Dynamic Spew messages +// +// It is possible to dynamically turn spew on and off. Dynamic spew is +// identified by a spew group and priority level. To turn spew on for a +// particular spew group, use SpewActivate( "group", level ). This will +// cause all spew in that particular group with priority levels <= the +// level specified in the SpewActivate function to be printed. Use DSpew +// to perform the spew: +// +// DWarning( "group", level, "Oh I feel even yummier!\n" ); +// +// Priority level 0 means that the spew will *always* be printed, and group +// '*' is the default spew group. If a DWarning is encountered using a group +// whose priority has not been set, it will use the priority of the default +// group. The priority of the default group is initially set to 0. +// +// Spew output +// +// The output of the spew system can be redirected to an externally-supplied +// function which is responsible for outputting the spew. By default, the +// spew is simply printed using printf. +// +// To redirect spew output, call SpewOutput. +// +// SpewOutputFunc( OutputFunc ); +// +// This will cause OutputFunc to be called every time a spew message is +// generated. OutputFunc will be passed a spew type and a message to print. +// It must return a value indicating whether the debugger should be invoked, +// whether the program should continue running, or whether the program +// should abort. +// +// 2. Code activation +// +// To cause code to be run only in debug builds, use DBG_CODE: +// An example is below. +// +// DBG_CODE( +// { +// int x = 5; +// ++x; +// } +// ); +// +// Code can be activated based on the dynamic spew groups also. Use +// +// DBG_DCODE( "group", level, +// { int x = 5; ++x; } +// ); +// +// 3. Breaking into the debugger. +// +// To cause an unconditional break into the debugger in debug builds only, use DBG_BREAK +// +// DBG_BREAK(); +// +// You can force a break in any build (release or debug) using +// +// DebuggerBreak(); +//----------------------------------------------------------------------------- + +/* Various types of spew messages */ +// I'm sure you're asking yourself why SPEW_ instead of DBG_ ? +// It's because DBG_ is used all over the place in windows.h +// For example, DBG_CONTINUE is defined. Feh. +enum SpewType_t +{ + SPEW_MESSAGE = 0, + SPEW_WARNING, + SPEW_ASSERT, + SPEW_ERROR, + SPEW_LOG, + + SPEW_TYPE_COUNT +}; + +enum SpewRetval_t +{ + SPEW_DEBUGGER = 0, + SPEW_CONTINUE, + SPEW_ABORT +}; + +/* type of externally defined function used to display debug spew */ +typedef SpewRetval_t(*SpewOutputFunc_t)(SpewType_t spewType, char const *pMsg); + +/* Used to redirect spew output */ +void SpewOutputFunc(SpewOutputFunc_t func); + +/* Used ot get the current spew output function */ +SpewOutputFunc_t GetSpewOutputFunc(void); + +/* Used to manage spew groups and subgroups */ +void SpewActivate(char const* pGroupName, int level); +bool IsSpewActive(char const* pGroupName, int level); + +/* Used to display messages, should never be called directly. */ +void _SpewInfo(SpewType_t type, char const* pFile, int line); +SpewRetval_t _SpewMessage(char const* pMsg, ...); +SpewRetval_t _DSpewMessage(char const *pGroupName, int level, char const* pMsg, ...); + +/* Used to define macros, never use these directly. */ +#define _Assert( _exp ) do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + if (_SpewMessage("Assertion Failed: " #_exp) == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertMsg( _exp, _msg ) do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + if (_SpewMessage(_msg) == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertFunc( _exp, _f ) do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage("Assertion Failed!" #_exp); \ + _f; \ + if (ret == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertEquals( _exp, _expectedValue ) \ + do { \ + if ((_exp) != (_expectedValue)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage("Expected %d but got %d!", (_expectedValue), (_exp)); \ + if (ret == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertFloatEquals( _exp, _expectedValue, _tol ) \ + do { \ + if (fabs((_exp) - (_expectedValue)) > (_tol)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage("Expected %f but got %f!", (_expectedValue), (_exp)); \ + if (ret == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +/* Spew macros... */ + +#ifdef _DEBUG + +#define Assert( _exp ) _Assert( _exp ) +#define AssertMsg( _exp, _msg ) _AssertMsg( _exp, _msg ) +#define AssertFunc( _exp, _f ) _AssertFunc( _exp, _f ) +#define AssertEquals( _exp, _expectedValue ) _AssertEquals( _exp, _expectedValue ) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) _AssertFloatEquals( _exp, _expectedValue, _tol ) +#define Verify( _exp ) _Assert( _exp ) + +#define AssertMsg1( _exp, _msg, a1 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1 ) ) +#define AssertMsg2( _exp, _msg, a1, a2 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2 ) ) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3 ) ) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4 ) ) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5 ) ) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ) ) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ) ) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7 ) ) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ) + + +#else /* Not _DEBUG */ + +#define Assert( _exp ) ((void)0) +#define AssertMsg( _exp, _msg ) ((void)0) +#define AssertFunc( _exp, _f ) ((void)0) +#define AssertEquals( _exp, _expectedValue ) ((void)0) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define Verify( _exp ) (_exp) + +#define AssertMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif /* _DEBUG */ + + + +/* These are always compiled in */ +void Msg(char const* pMsg, ...); +void DMsg(char const *pGroupName, int level, char const *pMsg, ...); + +void Warning(char const *pMsg, ...); +void DWarning(char const *pGroupName, int level, char const *pMsg, ...); + +void Log(char const *pMsg, ...); +void DLog(char const *pGroupName, int level, char const *pMsg, ...); + +void Error(char const *pMsg, ...); + +// You can use this macro like a runtime assert macro. +// If the condition fails, then Error is called with the message. This macro is called +// like AssertMsg, where msg must be enclosed in parenthesis: +// +// ErrorIfNot( bCondition, ("a b c %d %d %d", 1, 2, 3) ); +#define ErrorIfNot( condition, msg ) \ + if ( (condition) ) \ + ; \ + else \ + { \ + Error msg; \ + } + +/* A couple of super-common dynamic spew messages, here for convenience */ +/* These looked at the "developer" group */ +void DevMsg(int level, char const* pMsg, ...); +void DevWarning(int level, char const *pMsg, ...); +void DevLog(int level, char const *pMsg, ...); + +/* default level versions (level 1) */ +void DevMsg(char const* pMsg, ...); +void DevWarning(char const *pMsg, ...); +void DevLog(char const *pMsg, ...); + +/* Code macros, debugger interface */ + +#ifdef _DEBUG + +#define DBG_CODE( _code ) if (0) ; else { _code } +#define DBG_DCODE( _g, _l, _code ) if (IsSpewActive( _g, _l )) { _code } else {} +#define DBG_BREAK() DebuggerBreak() /* defined in platform.h */ + +#else /* not _DEBUG */ + +#define DBG_CODE( _code ) ((void)0) +#define DBG_DCODE( _g, _l, _code ) ((void)0) +#define DBG_BREAK() ((void)0) + +#endif /* _DEBUG */ + +//----------------------------------------------------------------------------- +// Macro to assist in asserting constant invariants during compilation + +#define UID_PREFIX generated_id_ +#define UID_CAT1(a,c) a ## c +#define UID_CAT2(a,c) UID_CAT1(a,c) +#define UNIQUE_ID UID_CAT2(UID_PREFIX,__LINE__) + + +#ifdef _DEBUG +#define COMPILE_TIME_ASSERT( pred ) switch(0){case 0:case pred:;} +#define ASSERT_INVARIANT( pred ) static void UNIQUE_ID() { COMPILE_TIME_ASSERT( pred ) } +#else +#define COMPILE_TIME_ASSERT( pred ) +#define ASSERT_INVARIANT( pred ) +#endif + + +//----------------------------------------------------------------------------- +// Templates to assist in validating pointers: + +// Have to use these stubs so we don't have to include windows.h here. +void _AssertValidReadPtr(void* ptr, int count = 1); +void _AssertValidWritePtr(void* ptr, int count = 1); +void _AssertValidReadWritePtr(void* ptr, int count = 1); + + void AssertValidStringPtr(const char* ptr, int maxchar = 0xFFFFFF); +template inline void AssertValidReadPtr(T* ptr, int count = 1) { _AssertValidReadPtr((void*)ptr, count); } +template inline void AssertValidWritePtr(T* ptr, int count = 1) { _AssertValidWritePtr((void*)ptr, count); } +template inline void AssertValidReadWritePtr(T* ptr, int count = 1) { _AssertValidReadWritePtr((void*)ptr, count); } + +#define AssertValidThis() AssertValidReadWritePtr(this,sizeof(*this)) + +//----------------------------------------------------------------------------- +// Macro to protect functions that are not reentrant + +#ifdef _DEBUG +class CReentryGuard +{ +public: + CReentryGuard(int *pSemaphore) + : m_pSemaphore(pSemaphore) + { + ++(*m_pSemaphore); + } + + ~CReentryGuard() + { + --(*m_pSemaphore); + } + +private: + int *m_pSemaphore; +}; + +#define ASSERT_NO_REENTRY() \ + static int fSemaphore##__LINE__; \ + Assert( !fSemaphore##__LINE__ ); \ + CReentryGuard ReentryGuard##__LINE__( &fSemaphore##__LINE__ ) +#else +#define ASSERT_NO_REENTRY() +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Inline string formatter +// + +class CDbgFmtMsg +{ +public: + CDbgFmtMsg(const char *pszFormat, ...) + { + va_list arg_ptr; + + va_start(arg_ptr, pszFormat); + _vsnprintf(m_szBuf, sizeof(m_szBuf) - 1, pszFormat, arg_ptr); + va_end(arg_ptr); + + m_szBuf[sizeof(m_szBuf) - 1] = 0; + } + + operator const char *() const + { + return m_szBuf; + } + +private: + char m_szBuf[256]; +}; + +//----------------------------------------------------------------------------- +// +// Purpose: Embed debug info in each file. +// + +//#ifdef _WIN32 +//#ifdef _DEBUG +//#pragma comment(compiler) +//#pragma comment(exestr,"*** DEBUG file detected, Last Compile: " __DATE__ ", " __TIME__ " ***") +//#endif +//#endif + +#endif /* DBG_H */ diff --git a/public/tier0/mem.h b/public/tier0/mem.h new file mode 100644 index 0000000..b539eb3 --- /dev/null +++ b/public/tier0/mem.h @@ -0,0 +1,37 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: Memory allocation! +// +// $NoKeywords: $ +//============================================================================= + +#ifndef TIER0_MEM_H +#define TIER0_MEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include +#include "tier0/platform.h" + +#ifdef TIER0_DLL_EXPORT +# define MEM_INTERFACE DLL_EXPORT +#else +# define MEM_INTERFACE DLL_IMPORT +#endif + + +//----------------------------------------------------------------------------- +// DLL-exported methods for particular kinds of memory +//----------------------------------------------------------------------------- +MEM_INTERFACE void *MemAllocScratch(int nMemSize); +MEM_INTERFACE void MemFreeScratch(); + +#ifdef __linux__ +MEM_INTERFACE void ZeroMemory(void *mem, size_t length); +#endif + + +#endif /* TIER0_MEM_H */ diff --git a/public/tier0/memalloc.h b/public/tier0/memalloc.h new file mode 100644 index 0000000..45ceede --- /dev/null +++ b/public/tier0/memalloc.h @@ -0,0 +1,77 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: This header should never be used directly from leaf code!!! +// Instead, just add the file memoverride.cpp into your project and all this +// will automagically be used +// +// $NoKeywords: $ +//============================================================================= + +#ifndef TIER0_MEMALLOC_H +#define TIER0_MEMALLOC_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include +#include "tier0/mem.h" + +struct _CrtMemState; + +//----------------------------------------------------------------------------- +// NOTE! This should never be called directly from leaf code +// Just use new,delete,malloc,free etc. They will call into this eventually +//----------------------------------------------------------------------------- +class IMemAlloc +{ +public: + // Release versions + virtual void *Alloc(size_t nSize) = 0; + virtual void *Realloc(void *pMem, size_t nSize) = 0; + virtual void Free(void *pMem) = 0; + virtual void *Expand(void *pMem, size_t nSize) = 0; + + // Debug versions + virtual void *Alloc(size_t nSize, const char *pFileName, int nLine) = 0; + virtual void *Realloc(void *pMem, size_t nSize, const char *pFileName, int nLine) = 0; + virtual void Free(void *pMem, const char *pFileName, int nLine) = 0; + virtual void *Expand(void *pMem, size_t nSize, const char *pFileName, int nLine) = 0; + + // Returns size of a particular allocation + virtual size_t GetSize(void *pMem) = 0; + + // Force file + line information for an allocation + virtual void PushAllocDbgInfo(const char *pFileName, int nLine) = 0; + virtual void PopAllocDbgInfo() = 0; + + // FIXME: Remove when we have our own allocator + // these methods of the Crt debug code is used in our codebase currently + virtual long CrtSetBreakAlloc(long lNewBreakAlloc) = 0; + virtual int CrtSetReportMode(int nReportType, int nReportMode) = 0; + virtual int CrtIsValidHeapPointer(const void *pMem) = 0; + virtual int CrtCheckMemory(void) = 0; + virtual int CrtSetDbgFlag(int nNewFlag) = 0; + virtual void CrtMemCheckpoint(_CrtMemState *pState) = 0; + + // FIXME: Make a better stats interface + virtual void DumpStats() = 0; + + // FIXME: Remove when we have our own allocator + virtual void* CrtSetReportFile(int nRptType, void* hFile) = 0; + virtual void* CrtSetReportHook(void* pfnNewHook) = 0; + virtual int CrtDbgReport(int nRptType, const char * szFile, + int nLine, const char * szModule, const char * pMsg) = 0; + + virtual int heapchk() = 0; +}; + + +//----------------------------------------------------------------------------- +// Singleton interface +//----------------------------------------------------------------------------- +IMemAlloc *g_pMemAlloc; + + +#endif /* TIER0_MEMALLOC_H */ diff --git a/public/tier0/memdbgoff.h b/public/tier0/memdbgoff.h new file mode 100644 index 0000000..e11e382 --- /dev/null +++ b/public/tier0/memdbgoff.h @@ -0,0 +1,21 @@ +//========= Copyright © 1996-2003, Valve LLC, All rights reserved. ============ +// +// Purpose: This header, which must be the final line of a .h file, +// causes all crt methods to stop using debugging versions of the memory allocators. +// NOTE: Use memdbgon.h to re-enable memory debugging. +// +// $NoKeywords: $ +//============================================================================= + +#ifdef MEM_DEBUG_ON + +#undef malloc +#undef realloc +#undef calloc +#undef free +#undef _expand +#undef _msize +#undef new +#undef MEM_DEBUG_ON + +#endif diff --git a/public/tier0/memdbgon.h b/public/tier0/memdbgon.h new file mode 100644 index 0000000..42be466 --- /dev/null +++ b/public/tier0/memdbgon.h @@ -0,0 +1,93 @@ +//========= Copyright © 1996-2003, Valve LLC, All rights reserved. ============ +// +// Purpose: This header, which must be the final include in a .cpp (or .h) file, +// causes all crt methods to use debugging versions of the memory allocators. +// NOTE: Use memdbgoff.h to disable memory debugging. +// +// $NoKeywords: $ +//============================================================================= + +// SPECIAL NOTE! This file must *not* use include guards; we need to be able +// to include this potentially multiple times (since we can deactivate debugging +// by including memdbgoff.h) + +// SPECIAL NOTE #2: This must be the final include in a .cpp or .h file!!! +#include "osconfig.h" + +#ifdef _DEBUG + +#include +#include +#include +#include + +#include "tier0/memdbgoff.h" + +#define MEM_DEBUG_ON 1 + +#undef malloc +#undef realloc +#undef calloc +#undef _expand +#undef free +#undef _msize + +#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define calloc(c, s) _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define realloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define free(p) _free_dbg(p, _NORMAL_BLOCK) +#define _msize(p) _msize_dbg(p, _NORMAL_BLOCK) +#define _expand(p, s) _expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) + + +#if defined(__AFX_H__) && defined(DEBUG_NEW) +#define new DEBUG_NEW +#else +#undef new +#define MEMALL_DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +#define new MEMALL_DEBUG_NEW +#endif + +#undef _strdup +#undef strdup +#undef _wcsdup +#undef wcsup + +#define _strdup(s) strdup_dbg(s, __FILE__, __LINE__) +#define strdup(s) strdup_dbg(s, __FILE__, __LINE__) +#define _wcsdup(s) wcsdup_dbg(s, __FILE__, __LINE__) +#define wcsdup(s) wcsdup_dbg(s, __FILE__, __LINE__) + +// Make sure we don't define strdup twice +#ifndef MEM_DBG_DEFINED_STRDUP +#define MEM_DBG_DEFINED_STRDUP 1 + +inline char *strdup_dbg(const char *pString, const char *pFileName, unsigned nLine) +{ + char *pMemory; + + if (!pString) + return NULL; + + if ((pMemory = (char *)_malloc_dbg(strlen(pString) + 1, _NORMAL_BLOCK, pFileName, nLine)) != NULL) + return strcpy(pMemory, pString); + + return NULL; +} + +inline wchar_t *wcsdup_dbg(const wchar_t *pString, const char *pFileName, unsigned nLine) +{ + wchar_t *pMemory; + + if (!pString) + return NULL; + + if ((pMemory = (wchar_t *)_malloc_dbg((wcslen(pString) + 1) * sizeof(wchar_t), _NORMAL_BLOCK, pFileName, nLine)) != NULL) + return wcscpy(pMemory, pString); + + return NULL; +} + +#endif // DBMEM_DEFINED_STRDUP + +#endif // _DEBUG diff --git a/public/tier0/platform.h b/public/tier0/platform.h new file mode 100644 index 0000000..1f85749 --- /dev/null +++ b/public/tier0/platform.h @@ -0,0 +1,630 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Extremely low-level platform-specific stuff +//============================================================================= + + +#ifndef PLATFORM_H +#define PLATFORM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" + +// need this for _alloca +#include + +// need this for memset +#include + +#include "archtypes.h" + +typedef float float32; +typedef double float64; + +// for when we don't care about how many bits we use +typedef unsigned int uint; + +// This can be used to ensure the size of pointers to members when declaring +// a pointer type for a class that has only been forward declared +#ifdef _MSC_VER +#define SINGLE_INHERITANCE __single_inheritance +#define MULTIPLE_INHERITANCE __multiple_inheritance +#else +#define SINGLE_INHERITANCE +#define MULTIPLE_INHERITANCE +#endif + +/* +FIXME: Enable this when we no longer fear change =) + +// need these for the limits +#include +#include + +// Maximum and minimum representable values +#define INT8_MAX SCHAR_MAX +#define INT16_MAX SHRT_MAX +#define INT32_MAX LONG_MAX +#define INT64_MAX (((int64)~0) >> 1) + +#define INT8_MIN SCHAR_MIN +#define INT16_MIN SHRT_MIN +#define INT32_MIN LONG_MIN +#define INT64_MIN (((int64)1) << 63) + +#define UINT8_MAX ((uint8)~0) +#define UINT16_MAX ((uint16)~0) +#define UINT32_MAX ((uint32)~0) +#define UINT64_MAX ((uint64)~0) + +#define UINT8_MIN 0 +#define UINT16_MIN 0 +#define UINT32_MIN 0 +#define UINT64_MIN 0 + +#ifndef UINT_MIN +#define UINT_MIN UINT32_MIN +#endif + +#define FLOAT32_MAX FLT_MAX +#define FLOAT64_MAX DBL_MAX + +#define FLOAT32_MIN FLT_MIN +#define FLOAT64_MIN DBL_MIN +*/ + +// portability / compiler settings +#if defined(_WIN32) && !defined(WINDED) + +#if defined(_M_IX86) +#define __i386__ 1 +#endif + +#elif __linux__ +typedef void * HINSTANCE; +#define _MAX_PATH PATH_MAX +#endif // defined(_WIN32) && !defined(WINDED) + + +// Defines MAX_PATH +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +// Used to step into the debugger +#define DebuggerBreak() __asm { int 3 } + +// C functions for external declarations that call the appropriate C++ methods +#ifndef EXPORT +#ifdef _WIN32 +#define EXPORT _declspec( dllexport ) +#else +#define EXPORT /* */ +#endif +#endif + +#if defined __i386__ && !defined __linux__ +#define id386 1 +#else +#define id386 0 +#endif // __i386__ + +#ifdef _WIN32 +// Used for dll exporting and importing +#define DLL_EXPORT extern "C" __declspec( dllexport ) +#define DLL_IMPORT extern "C" __declspec( dllimport ) + +// Can't use extern "C" when DLL exporting a class +#define DLL_CLASS_EXPORT __declspec( dllexport ) +#define DLL_CLASS_IMPORT __declspec( dllimport ) + +// Can't use extern "C" when DLL exporting a global +#define DLL_GLOBAL_EXPORT extern __declspec( dllexport ) +#define DLL_GLOBAL_IMPORT extern __declspec( dllimport ) +#elif defined __linux__ + +// Used for dll exporting and importing +#define DLL_EXPORT extern "C" +#define DLL_IMPORT extern "C" + +// Can't use extern "C" when DLL exporting a class +#define DLL_CLASS_EXPORT +#define DLL_CLASS_IMPORT + +// Can't use extern "C" when DLL exporting a global +#define DLL_GLOBAL_EXPORT extern +#define DLL_GLOBAL_IMPORT extern + +#else +#error "Unsupported Platform." +#endif + +// Used for standard calling conventions +#ifdef _WIN32 +#define FASTCALL __fastcall +#define FORCEINLINE __forceinline +#else +#define FASTCALL +#define FORCEINLINE inline +#endif + +// Force a function call site -not- to inlined. (useful for profiling) +#define DONT_INLINE(a) (((int)(a)+1)?(a):(a)) + +// Pass hints to the compiler to prevent it from generating unnessecary / stupid code +// in certain situations. Several compilers other than MSVC also have an equivilent +// construct. +// +// Essentially the 'Hint' is that the condition specified is assumed to be true at +// that point in the compilation. If '0' is passed, then the compiler assumes that +// any subsequent code in the same 'basic block' is unreachable, and thus usually +// removed. +#ifdef _MSC_VER +#define HINT(THE_HINT) __assume((THE_HINT)) +#else +#define HINT(THE_HINT) 0 +#endif + +// Marks the codepath from here until the next branch entry point as unreachable, +// and asserts if any attempt is made to execute it. +#define UNREACHABLE() { Assert(0); HINT(0); } + +// In cases where no default is present or appropriate, this causes MSVC to generate +// as little code as possible, and throw an assertion in debug. +#define NO_DEFAULT default: UNREACHABLE(); + +#ifdef _WIN32 +// Alloca defined for this platform +#define stackalloc( _size ) _alloca( _size ) +#define stackfree( _p ) 0 +#elif __linux__ +// Alloca defined for this platform +#define stackalloc( _size ) alloca( _size ) +#define stackfree( _p ) 0 +#endif + +#ifdef _WIN32 +// Remove warnings from warning level 4. +#pragma warning(disable : 4514) // warning C4514: 'acosl' : unreferenced inline function has been removed +#pragma warning(disable : 4100) // warning C4100: 'hwnd' : unreferenced formal parameter +#pragma warning(disable : 4127) // warning C4127: conditional expression is constant +#pragma warning(disable : 4512) // warning C4512: 'InFileRIFF' : assignment operator could not be generated +#pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable +#pragma warning(disable : 4706) // warning C4706: assignment within conditional expression +#pragma warning(disable : 4710) // warning C4710: function 'x' not inlined +#pragma warning(disable : 4702) // warning C4702: unreachable code +#pragma warning(disable : 4505) // unreferenced local function has been removed +#pragma warning(disable : 4239) // nonstandard extension used : 'argument' ( conversion from class Vector to class Vector& ) +#pragma warning(disable : 4097) // typedef-name 'BaseClass' used as synonym for class-name 'CFlexCycler::CBaseFlex' +#pragma warning(disable : 4324) // Padding was added at the end of a structure +#pragma warning(disable : 4244) // type conversion warning. +#pragma warning(disable : 4305) // truncation from 'const double ' to 'float ' +#pragma warning(disable : 4786) // Disable warnings about long symbol names + +#if _MSC_VER >= 1300 +#pragma warning(disable : 4511) // Disable warnings about private copy constructors +#endif +#endif +//----------------------------------------------------------------------------- +// Purpose: Standard functions for handling endian-ness +//----------------------------------------------------------------------------- + +//------------------------------------- +// Basic swaps +//------------------------------------- + +template +inline T WordSwapC(T w) +{ + uint16 temp; + + temp = ((*((uint16 *)&w) & 0xff00) >> 8); + temp |= ((*((uint16 *)&w) & 0x00ff) << 8); + + return *((T*)&temp); +} + +template +inline T DWordSwapC(T dw) +{ + uint32 temp; + + temp = *((uint32 *)&dw) >> 24; + temp |= ((*((uint32 *)&dw) & 0x00FF0000) >> 8); + temp |= ((*((uint32 *)&dw) & 0x0000FF00) << 8); + temp |= ((*((uint32 *)&dw) & 0x000000FF) << 24); + + return *((T*)&temp); +} + +//------------------------------------- +// Fast swaps +//------------------------------------- + +#ifdef _MSC_VER + +#define WordSwap WordSwapAsm +#define DWordSwap DWordSwapAsm + +#pragma warning(push) +#pragma warning (disable:4035) // no return value + +template +inline T WordSwapAsm(T w) +{ + __asm + { + mov ax, w + xchg al, ah + } +} + +template +inline T DWordSwapAsm(T dw) +{ + __asm + { + mov eax, dw + bswap eax + } +} + +#pragma warning(pop) + +// The assembly implementation is not compatible with floats +template <> +inline float DWordSwapAsm(float f) +{ + return DWordSwapC(f); +} + +#else + +#define WordSwap WordSwapC +#define DWordSwap DWordSwapC + +#endif + +//------------------------------------- +// The typically used methods. +//------------------------------------- + +#if defined(__i386__) +#define VALVE_LITTLE_ENDIAN 1 +#endif + +#ifdef _SGI_SOURCE +#define VALVE_BIG_ENDIAN 1 +#endif + +#if defined(VALVE_LITTLE_ENDIAN) + +#define Valve_BigShort( val ) WordSwap( val ) +#define Valve_BigWord( val ) WordSwap( val ) +#define Valve_BigLong( val ) DWordSwap( val ) +#define Valve_BigDWord( val ) DWordSwap( val ) +#define Valve_BigFloat( val ) DWordSwap( val ) +#define Valve_LittleShort( val ) ( val ) +#define Valve_LittleWord( val ) ( val ) +#define Valve_LittleLong( val ) ( val ) +#define Valve_LittleDWord( val ) ( val ) +#define Valve_LittleFloat( val ) ( val ) + +#elif defined(BIG_ENDIAN) + +#define Valve_BigShort( val ) ( val ) +#define Valve_BigWord( val ) ( val ) +#define Valve_BigLong( val ) ( val ) +#define Valve_BigDWord( val ) ( val ) +#define Valve_BigFloat( val ) ( val ) +#define Valve_LittleShort( val ) WordSwap( val ) +#define Valve_LittleWord( val ) WordSwap( val ) +#define Valve_LittleLong( val ) DWordSwap( val ) +#define Valve_LittleDWord( val ) DWordSwap( val ) +#define Valve_LittleFloat( val ) DWordSwap( val ) + +#else + +// @Note (toml 05-02-02): this technique expects the compiler to +// optimize the expression and eliminate the other path. On any new +// platform/compiler this should be tested. +inline short BigShort(short val) { int test = 1; return (*(char *)&test == 1) ? WordSwap(val) : val; } +inline uint16 BigWord(uint16 val) { int test = 1; return (*(char *)&test == 1) ? WordSwap(val) : val; } +inline long BigLong(long val) { int test = 1; return (*(char *)&test == 1) ? DWordSwap(val) : val; } +inline uint32 BigDWord(uint32 val) { int test = 1; return (*(char *)&test == 1) ? DWordSwap(val) : val; } +inline float BigFloat(float val) { int test = 1; return (*(char *)&test == 1) ? DWordSwap(val) : val; } +inline short LittleShort(short val) { int test = 1; return (*(char *)&test == 1) ? val : WordSwap(val); } +inline uint16 LittleWord(uint16 val) { int test = 1; return (*(char *)&test == 1) ? val : WordSwap(val); } +inline long LittleLong(long val) { int test = 1; return (*(char *)&test == 1) ? val : DWordSwap(val); } +inline uint32 LittleDWord(uint32 val) { int test = 1; return (*(char *)&test == 1) ? val : DWordSwap(val); } +inline float LittleFloat(float val) { int test = 1; return (*(char *)&test == 1) ? val : DWordSwap(val); } + +#endif + + + +#ifdef TIER0_DLL_EXPORT +#define PLATFORM_INTERFACE DLL_EXPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_EXPORT +#else +#define PLATFORM_INTERFACE DLL_IMPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_IMPORT +#endif + +/* +PLATFORM_INTERFACE double Plat_FloatTime(); // Returns time in seconds since the module was loaded. +PLATFORM_INTERFACE unsigned long Plat_MSTime(); // Time in milliseconds. + +// b/w compatibility +#define Sys_FloatTime Plat_FloatTime +*/ + +// Processor Information: +struct CPUInformation +{ + int m_Size; // Size of this structure, for forward compatability. + + bool m_bRDTSC : 1, // Is RDTSC supported? + m_bCMOV : 1, // Is CMOV supported? + m_bFCMOV : 1, // Is FCMOV supported? + m_bSSE : 1, // Is SSE supported? + m_bSSE2 : 1, // Is SSE2 Supported? + m_b3DNow : 1, // Is 3DNow! Supported? + m_bMMX : 1, // Is MMX supported? + m_bHT : 1; // Is HyperThreading supported? + + unsigned char m_nLogicalProcessors, // Number op logical processors. + m_nPhysicalProcessors; // Number of physical processors + + int64 m_Speed; // In cycles per second. + + char* m_szProcessorID; // Processor vendor Identification. +}; + +PLATFORM_INTERFACE const CPUInformation& GetCPUInformation(); + + +//----------------------------------------------------------------------------- +// Thread related functions +//----------------------------------------------------------------------------- +// Registers the current thread with Tier0's thread management system. +// This should be called on every thread created in the game. +PLATFORM_INTERFACE unsigned long Plat_RegisterThread(const char *pName = "Source Thread"); + +// Registers the current thread as the primary thread. +PLATFORM_INTERFACE unsigned long Plat_RegisterPrimaryThread(); + +// VC-specific. Sets the thread's name so it has a friendly name in the debugger. +// This should generally only be handled by Plat_RegisterThread and Plat_RegisterPrimaryThread +PLATFORM_INTERFACE void Plat_SetThreadName(unsigned long dwThreadID, const char *pName); + +// These would be private if it were possible to export private variables from a .DLL. +// They need to be variables because they are checked by inline functions at performance +// critical places. +PLATFORM_INTERFACE unsigned long Plat_PrimaryThreadID; + +// Returns the ID of the currently executing thread. +PLATFORM_INTERFACE unsigned long Plat_GetCurrentThreadID(); + +// Returns the ID of the primary thread. +inline unsigned long Plat_GetPrimaryThreadID() +{ + return Plat_PrimaryThreadID; +} + +// Returns true if the current thread is the primary thread. +inline bool Plat_IsPrimaryThread() +{ + //return true; + return (Plat_GetPrimaryThreadID() == Plat_GetCurrentThreadID()); +} + +//----------------------------------------------------------------------------- +// Security related functions +//----------------------------------------------------------------------------- +// Ensure that the hardware key's drivers have been installed. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyDriver(); + +// Ok, so this isn't a very secure way to verify the hardware key for now. It +// is primarially depending on the fact that all the binaries have been wrapped +// with the secure wrapper provided by the hardware keys vendor. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKey(); + +// The same as above, but notifies user with a message box when the key isn't in +// and gives him an opportunity to correct the situation. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyPrompt(); + +// Can be called in real time, doesn't perform the verify every frame. Mainly just +// here to allow the game to drop out quickly when the key is removed, rather than +// allowing the wrapper to pop up it's own blocking dialog, which the engine doesn't +// like much. +PLATFORM_INTERFACE bool Plat_FastVerifyHardwareKey(); + + + +//----------------------------------------------------------------------------- +// Include additional dependant header components. +//----------------------------------------------------------------------------- +//#include "tier0/fasttimer.h" + + +//----------------------------------------------------------------------------- +// Just logs file and line to simple.log +//----------------------------------------------------------------------------- +void* Plat_SimpleLog(const char* file, int line); + +//#define Plat_dynamic_cast Plat_SimpleLog(__FILE__,__LINE__),dynamic_cast + +//----------------------------------------------------------------------------- +// Methods to invoke the constructor, copy constructor, and destructor +//----------------------------------------------------------------------------- + +template +inline void Construct(T* pMemory) +{ + new(pMemory)T; +} + +template +inline void CopyConstruct(T* pMemory, T const& src) +{ + new(pMemory)T(src); +} + +template +inline void Destruct(T* pMemory) +{ + pMemory->~T(); + +#ifdef _DEBUG + memset(pMemory, 0xDD, sizeof(T)); +#endif +} + + +// +// GET_OUTER() +// +// A platform-independent way for a contained class to get a pointer to its +// owner. If you know a class is exclusively used in the context of some +// "outer" class, this is a much more space efficient way to get at the outer +// class than having the inner class store a pointer to it. +// +// class COuter +// { +// class CInner // Note: this does not need to be a nested class to work +// { +// void PrintAddressOfOuter() +// { +// printf( "Outer is at 0x%x\n", GET_OUTER( COuter, m_Inner ) ); +// } +// }; +// +// CInner m_Inner; +// friend class CInner; +// }; + +#define GET_OUTER( OuterType, OuterMember ) \ + ( ( OuterType * ) ( (char *)this - offsetof( OuterType, OuterMember ) ) ) + + +/* TEMPLATE_FUNCTION_TABLE() + +(Note added to platform.h so platforms that correctly support templated +functions can handle portions as templated functions rather than wrapped +functions) + +Helps automate the process of creating an array of function +templates that are all specialized by a single integer. +This sort of thing is often useful in optimization work. + +For example, using TEMPLATE_FUNCTION_TABLE, this: + +TEMPLATE_FUNCTION_TABLE(int, Function, ( int blah, int blah ), 10) +{ +return argument * argument; +} + +is equivilent to the following: + +(NOTE: the function has to be wrapped in a class due to code +generation bugs involved with directly specializing a function +based on a constant.) + +template +class FunctionWrapper +{ +public: +int Function( int blah, int blah ) +{ +return argument*argument; +} +} + +typedef int (*FunctionType)( int blah, int blah ); + +class FunctionName +{ +public: +enum { count = 10 }; +FunctionType functions[10]; +}; + +FunctionType FunctionName::functions[] = +{ +FunctionWrapper<0>::Function, +FunctionWrapper<1>::Function, +FunctionWrapper<2>::Function, +FunctionWrapper<3>::Function, +FunctionWrapper<4>::Function, +FunctionWrapper<5>::Function, +FunctionWrapper<6>::Function, +FunctionWrapper<7>::Function, +FunctionWrapper<8>::Function, +FunctionWrapper<9>::Function +}; +*/ + +bool vtune(bool resume); + + +#define TEMPLATE_FUNCTION_TABLE(RETURN_TYPE, NAME, ARGS, COUNT) \ + \ +typedef RETURN_TYPE (FASTCALL *__Type_##NAME) ARGS; \ + \ +template \ +struct __Function_##NAME \ +{ \ + static RETURN_TYPE FASTCALL Run ARGS; \ +}; \ + \ +template \ +struct __MetaLooper_##NAME : __MetaLooper_##NAME \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME::Run; } \ +}; \ + \ +template<> \ +struct __MetaLooper_##NAME<0> \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME<0>::Run; } \ +}; \ + \ +class NAME \ +{ \ +private: \ + static const __MetaLooper_##NAME m; \ +public: \ + enum { count = COUNT }; \ + static const __Type_##NAME* functions; \ +}; \ +const __MetaLooper_##NAME NAME::m; \ +const __Type_##NAME* NAME::functions = (__Type_##NAME*)&m; \ +template \ +RETURN_TYPE FASTCALL __Function_##NAME::Run ARGS + + +#define LOOP_INTERCHANGE(BOOLEAN, CODE)\ + if( (BOOLEAN) )\ + {\ + CODE;\ + } else\ + {\ + CODE;\ + } + + +#endif /* PLATFORM_H */ diff --git a/public/tier0/platform_linux.cpp b/public/tier0/platform_linux.cpp new file mode 100644 index 0000000..ca1e44e --- /dev/null +++ b/public/tier0/platform_linux.cpp @@ -0,0 +1,59 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "precompiled.h" + +double Plat_FloatTime() +{ + 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); +} + +unsigned long Plat_MSTime() +{ + struct timeval tp; + static int secbase = 0; + + gettimeofday(&tp, NULL); + + if (!secbase) + { + secbase = tp.tv_sec; + return (tp.tv_usec / 1000000.0); + } + + return (unsigned long)((tp.tv_sec - secbase) + tp.tv_usec / 1000000.0); + +} + + + +bool vtune(bool resume) +{ + return true; +} + + +// -------------------------------------------------------------------------------------------------- // +// Memory stuff. +// -------------------------------------------------------------------------------------------------- // + + +void Plat_SetThreadName(unsigned long dwThreadID, const char *pName) +{ + Assert("Plat_SetThreadName not implemented"); +} diff --git a/public/tier0/platform_win32.cpp b/public/tier0/platform_win32.cpp new file mode 100644 index 0000000..765d0a6 --- /dev/null +++ b/public/tier0/platform_win32.cpp @@ -0,0 +1,95 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "precompiled.h" + +static LARGE_INTEGER g_PerformanceFrequency; +static LARGE_INTEGER g_MSPerformanceFrequency; +static LARGE_INTEGER g_ClockStart; +static HINSTANCE g_pVTuneDLL; + +static void InitTime() +{ + if (!g_PerformanceFrequency.QuadPart) + { + QueryPerformanceFrequency(&g_PerformanceFrequency); + g_MSPerformanceFrequency.QuadPart = g_PerformanceFrequency.QuadPart / 1000; + QueryPerformanceCounter(&g_ClockStart); + } +} + +double Plat_FloatTime() +{ + InitTime(); + + LARGE_INTEGER CurrentTime; + + QueryPerformanceCounter(&CurrentTime); + + double fRawSeconds = (double)(CurrentTime.QuadPart - g_ClockStart.QuadPart) / (double)(g_PerformanceFrequency.QuadPart); + + return fRawSeconds; +} + +unsigned long Plat_MSTime() +{ + InitTime(); + + LARGE_INTEGER CurrentTime; + + QueryPerformanceCounter(&CurrentTime); + + return (unsigned long)((CurrentTime.QuadPart - g_ClockStart.QuadPart) / g_MSPerformanceFrequency.QuadPart); +} + +void free_vtune() +{ + FreeLibrary(g_pVTuneDLL); +} + +bool vtune(bool resume) +{ + static bool bInitialized = false; + static void(__cdecl *VTResume)(void) = NULL; + static void(__cdecl *VTPause) (void) = NULL; + + // Grab the Pause and Resume function pointers from the VTune DLL the first time through: + if (!bInitialized) + { + bInitialized = true; + + g_pVTuneDLL = LoadLibrary("vtuneapi.dll"); + + if (g_pVTuneDLL) + { + VTResume = (void(__cdecl *)())GetProcAddress(g_pVTuneDLL, "VTResume"); + VTPause = (void(__cdecl *)())GetProcAddress(g_pVTuneDLL, "VTPause"); + atexit(free_vtune); + } + } + + // Call the appropriate function, as indicated by the argument: + if (resume && VTResume) + { + VTResume(); + return true; + + } + else if (!resume && VTPause) + { + VTPause(); + return true; + } + + return false; + +} + + +// -------------------------------------------------------------------------------------------------- // +// Memory stuff. +// -------------------------------------------------------------------------------------------------- // diff --git a/public/utlbuffer.cpp b/public/utlbuffer.cpp index c9f4508..53ad7f4 100644 --- a/public/utlbuffer.cpp +++ b/public/utlbuffer.cpp @@ -416,4 +416,4 @@ void CUtlBuffer::SeekPut(SeekType_t type, int offset) m_Put = m_Memory.NumAllocated() - offset; break; } -} \ No newline at end of file +} diff --git a/public/utlmemory.h b/public/utlmemory.h index 071260a..7ccce20 100644 --- a/public/utlmemory.h +++ b/public/utlmemory.h @@ -320,4 +320,4 @@ void CUtlMemory::Purge() } -#endif // UTLSTORAGE_H \ No newline at end of file +#endif // UTLSTORAGE_H diff --git a/public/utlrbtree.h b/public/utlrbtree.h index de4890a..e8fca65 100644 --- a/public/utlrbtree.h +++ b/public/utlrbtree.h @@ -1119,7 +1119,7 @@ int CUtlRBTree::Depth( I node ) const int depthright = Depth( RightChild(node) ); int depthleft = Depth( LeftChild(node) ); - return max(depthright, depthleft) + 1; + return Q_max(depthright, depthleft) + 1; } diff --git a/src/cmdexec.cpp b/src/cmdexec.cpp index 92a6110..a844657 100644 --- a/src/cmdexec.cpp +++ b/src/cmdexec.cpp @@ -15,7 +15,7 @@ CExecMngr::CBufExec::~CBufExec() ; } -void CExecMngr::AddElement(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash) +void CExecMngr::Add(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash) { m_execList.push_back(new CBufExec(pClient, pResource, responseHash)); } @@ -86,7 +86,7 @@ void EXT_FUNC CmdExec_hook(IGameClient *pClient, IResourceBuffer *pRes, char *cm SERVER_COMMAND(cmdExec); } -void CExecMngr::CommandExecute(IGameClient *pClient) +void CExecMngr::ExecuteCommand(IGameClient *pClient) { bool bBreak = false; auto iter = m_execList.begin(); @@ -133,6 +133,10 @@ void CExecMngr::Clear(IGameClient *pClient) { if (!pClient) { + for (auto exec : m_execList) { + delete exec; + } + m_execList.clear(); return; } diff --git a/src/cmdexec.h b/src/cmdexec.h index bd98663..504c997 100644 --- a/src/cmdexec.h +++ b/src/cmdexec.h @@ -3,8 +3,8 @@ class CExecMngr { public: - void AddElement(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash); - void CommandExecute(IGameClient *pClient); + void Add(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash); + void ExecuteCommand(IGameClient *pClient); void Clear(IGameClient *pClient = NULL); private: diff --git a/src/config.cpp b/src/config.cpp index 585bfc8..3f12aaa 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -9,7 +9,7 @@ CConfig Config; void CConfig::Init() { char *pos; - char path[MAX_PATH_LENGTH]; + char path[MAX_PATH]; strncpy(path, GET_PLUGIN_PATH(PLID), sizeof(path) - 1); path[sizeof(path) - 1] = '\0'; @@ -73,7 +73,7 @@ void CConfig::Load() if (fp == NULL) { - UTIL_Printf(__FUNCTION__ ": can't find path to " FILE_INI_CONFIG "\n"); + UTIL_Printf("%s: can't find path to " FILE_INI_CONFIG "\n", __func__); return; } diff --git a/src/config.h b/src/config.h index 5091e04..7a24429 100644 --- a/src/config.h +++ b/src/config.h @@ -14,7 +14,7 @@ private: void ResetValues(); private: - char m_PathDir[MAX_PATH_LENGTH]; + char m_PathDir[MAX_PATH]; // settings float m_DelayExec; diff --git a/src/dllapi.cpp b/src/dllapi.cpp index 9594d30..d1eb00f 100644 --- a/src/dllapi.cpp +++ b/src/dllapi.cpp @@ -3,7 +3,6 @@ DLL_FUNCTIONS *g_pFunctionTable; extern void ServerDeactivate_Post(); -extern void ClientPutInServer_Post(edict_t *pEntity); static DLL_FUNCTIONS gFunctionTable = { @@ -92,7 +91,7 @@ static DLL_FUNCTIONS gFunctionTable_Post = NULL, // pfnClientConnect NULL, // pfnClientDisconnect NULL, // pfnClientKill - &ClientPutInServer_Post, // pfnClientPutInServer + NULL, // pfnClientPutInServer NULL, // pfnClientCommand NULL, // pfnClientUserInfoChanged NULL, // pfnServerActivate @@ -137,12 +136,12 @@ C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersi { if (!pFunctionTable) { - ALERT(at_logged, __FUNCTION__ " called with null pFunctionTable"); + ALERT(at_logged, "%s called with null pFunctionTable", __func__); return FALSE; } else if (*interfaceVersion != INTERFACE_VERSION) { - ALERT(at_logged, __FUNCTION__ " version mismatch; requested=%d ours=%d", *interfaceVersion, INTERFACE_VERSION); + ALERT(at_logged, "%s version mismatch; requested=%d ours=%d", __func__, *interfaceVersion, INTERFACE_VERSION); //! Tell metamod what version we had, so it can figure out who is out of date. *interfaceVersion = INTERFACE_VERSION; @@ -159,12 +158,12 @@ C_DLLEXPORT int GetEntityAPI2_Post(DLL_FUNCTIONS *pFunctionTable, int *interface { if (!pFunctionTable) { - ALERT(at_logged, __FUNCTION__ " called with null pFunctionTable"); + ALERT(at_logged, "%s called with null pFunctionTable", __func__); return FALSE; } else if (*interfaceVersion != INTERFACE_VERSION) { - ALERT(at_logged, __FUNCTION__ " version mismatch; requested=%d ours=%d", *interfaceVersion, INTERFACE_VERSION); + ALERT(at_logged, "%s version mismatch; requested=%d ours=%d", __func__, *interfaceVersion, INTERFACE_VERSION); //! Tell metamod what version we had, so it can figure out who is out of date. *interfaceVersion = INTERFACE_VERSION; diff --git a/src/engine_api.cpp b/src/engine_api.cpp index 37e59e1..303738e 100644 --- a/src/engine_api.cpp +++ b/src/engine_api.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" -enginefuncs_t meta_engfuncs_post = +enginefuncs_t meta_engfuncs_post = { NULL, // pfnPrecacheModel() NULL, // pfnPrecacheSound() @@ -216,12 +216,12 @@ C_DLLEXPORT int GetEngineFunctions_Post(enginefuncs_t *pengfuncsFromEngine, int { if (!pengfuncsFromEngine) { - ALERT(at_logged, __FUNCTION__ " called with null pengfuncsFromEngine"); + ALERT(at_logged, "%s called with null pengfuncsFromEngine", __func__); return FALSE; } else if (*interfaceVersion != ENGINE_INTERFACE_VERSION) { - ALERT(at_logged, __FUNCTION__ " version mismatch; requested=%d ours=%d", *interfaceVersion, ENGINE_INTERFACE_VERSION); + ALERT(at_logged, "%s version mismatch; requested=%d ours=%d", __func__, *interfaceVersion, ENGINE_INTERFACE_VERSION); // Tell metamod what version we had, so it can figure out who is out of date. *interfaceVersion = ENGINE_INTERFACE_VERSION; return FALSE; diff --git a/src/engine_rehlds.cpp b/src/engine_rehlds.cpp index ebb8782..7824c7f 100644 --- a/src/engine_rehlds.cpp +++ b/src/engine_rehlds.cpp @@ -8,11 +8,7 @@ IRehldsServerData *g_RehldsServerData; rehlds_ret RehldsApi_Init() { -#ifdef WIN32 - CSysModule *engineModule = Sys_LoadModule("swds.dll"); -#else - CSysModule *engineModule = Sys_LoadModule("engine_i486.so"); -#endif // WIN32 + CSysModule *engineModule = Sys_LoadModule(ENGINE_LIB); if (!engineModule) return RETURN_NOT_FOUND; @@ -26,7 +22,7 @@ rehlds_ret RehldsApi_Init() if (!g_RehldsApi) { - UTIL_LogPrintf(__FUNCTION__ " : REHLDS can't find Interface API\n"); + UTIL_LogPrintf("%s : REHLDS can't find Interface API\n", __func__); return RETURN_NOT_FOUND; } @@ -35,13 +31,13 @@ rehlds_ret RehldsApi_Init() if (majorVersion != REHLDS_API_VERSION_MAJOR) { - UTIL_LogPrintf(__FUNCTION__ " : REHLDS Api major version mismatch; expected %d, real %d\n", REHLDS_API_VERSION_MAJOR, majorVersion); + UTIL_LogPrintf("%s : REHLDS Api major version mismatch; expected %d, real %d\n", __func__, REHLDS_API_VERSION_MAJOR, majorVersion); return RETURN_MAJOR_MISMATCH; } if (minorVersion < REHLDS_API_VERSION_MINOR) { - UTIL_LogPrintf(__FUNCTION__ " : REHLDS Api minor version mismatch; expected at least %d, real %d\n", REHLDS_API_VERSION_MINOR, minorVersion); + UTIL_LogPrintf("%s : REHLDS Api minor version mismatch; expected at least %d, real %d\n", __func__, REHLDS_API_VERSION_MINOR, minorVersion); return RETURN_MINOR_MISMATCH; } diff --git a/src/hookchains_impl.cpp b/src/hookchains_impl.cpp index f5a0004..ac47da6 100644 --- a/src/hookchains_impl.cpp +++ b/src/hookchains_impl.cpp @@ -21,13 +21,13 @@ AbstractHookChainRegistry::AbstractHookChainRegistry() { - memset(m_Hooks, 0, sizeof(m_Hooks)); - memset(m_Priorities, 0, sizeof(m_Priorities)); + Q_memset(m_Hooks, 0, sizeof(m_Hooks)); + Q_memset(m_Priorities, 0, sizeof(m_Priorities)); m_NumHooks = 0; } -bool AbstractHookChainRegistry::findHook(void* hookFunc) const +bool AbstractHookChainRegistry::findHook(void *hookFunc) const { for (auto i = 0; i < m_NumHooks; i++) { if (m_Hooks[i] == hookFunc) @@ -37,14 +37,14 @@ bool AbstractHookChainRegistry::findHook(void* hookFunc) const return false; } -void AbstractHookChainRegistry::addHook(void* hookFunc, int priority) +void AbstractHookChainRegistry::addHook(void *hookFunc, int priority) { if (!hookFunc) { - Sys_Error(__FUNCTION__ " Parameter hookFunc can't be a nullptr"); + Sys_Error("%s: Parameter hookFunc can't be a nullptr", __func__); } if (findHook(hookFunc)) { - Sys_Error(__FUNCTION__ " The same handler can't be used twice on the hookchain."); + Sys_Error("%s: The same handler can't be used twice on the hookchain.", __func__); } for (auto i = 0; i < MAX_HOOKS_IN_CHAIN; i++) @@ -63,13 +63,13 @@ void AbstractHookChainRegistry::addHook(void* hookFunc, int priority) } if (m_NumHooks >= MAX_HOOKS_IN_CHAIN) { - Sys_Error(__FUNCTION__ " MAX_HOOKS_IN_CHAIN limit hit"); + Sys_Error("%s: MAX_HOOKS_IN_CHAIN limit hit", __func__); } m_NumHooks++; } -void AbstractHookChainRegistry::removeHook(void* hookFunc) { +void AbstractHookChainRegistry::removeHook(void *hookFunc) { // erase hook for (auto i = 0; i < m_NumHooks; i++) @@ -79,8 +79,8 @@ void AbstractHookChainRegistry::removeHook(void* hookFunc) { --m_NumHooks; if (m_NumHooks != i) { - memmove(&m_Hooks[i], &m_Hooks[i + 1], (m_NumHooks - i) * sizeof(m_Hooks[0])); - memmove(&m_Priorities[i], &m_Priorities[i + 1], (m_NumHooks - i) * sizeof(m_Priorities[0])); + Q_memmove(&m_Hooks[i], &m_Hooks[i + 1], (m_NumHooks - i) * sizeof(m_Hooks[0])); + Q_memmove(&m_Priorities[i], &m_Priorities[i + 1], (m_NumHooks - i) * sizeof(m_Priorities[0])); m_Hooks[m_NumHooks] = NULL; } else diff --git a/src/hookchains_impl.h b/src/hookchains_impl.h index cab3340..30d6991 100644 --- a/src/hookchains_impl.h +++ b/src/hookchains_impl.h @@ -28,19 +28,19 @@ #pragma once #include "hookchains.h" -#define MAX_HOOKS_IN_CHAIN 19 +const int MAX_HOOKS_IN_CHAIN = 19; // Implementation for chains in modules template -class IHookChainImpl : public IHookChain { +class IHookChainImpl: public IHookChain { public: - typedef t_ret(*hookfunc_t)(IHookChain*, t_args...); - typedef t_ret(*origfunc_t)(t_args...); + typedef t_ret (*hookfunc_t)(IHookChain *, t_args...); + typedef t_ret (*origfunc_t)(t_args...); - IHookChainImpl(void** hooks, origfunc_t orig) : m_Hooks(hooks), m_OriginalFunc(orig) + IHookChainImpl(void **hooks, origfunc_t orig) : m_Hooks(hooks), m_OriginalFunc(orig) { if (orig == NULL) - Sys_Error(__FUNCTION__ ": Non-void HookChain without original function."); + Sys_Error("%s: Non-void HookChain without original function.", __func__); } virtual ~IHookChainImpl() {} @@ -62,18 +62,18 @@ public: } private: - void** m_Hooks; + void **m_Hooks; origfunc_t m_OriginalFunc; }; // Implementation for void chains in modules template -class IVoidHookChainImpl : public IVoidHookChain { +class IVoidHookChainImpl: public IVoidHookChain { public: - typedef void(*hookfunc_t)(IVoidHookChain*, t_args...); - typedef void(*origfunc_t)(t_args...); + typedef void (*hookfunc_t)(IVoidHookChain *, t_args...); + typedef void (*origfunc_t)(t_args...); - IVoidHookChainImpl(void** hooks, origfunc_t orig) : m_Hooks(hooks), m_OriginalFunc(orig) {} + IVoidHookChainImpl(void **hooks, origfunc_t orig) : m_Hooks(hooks), m_OriginalFunc(orig) {} virtual ~IVoidHookChainImpl() {} virtual void callNext(t_args... args) { @@ -97,20 +97,20 @@ public: } private: - void** m_Hooks; + void **m_Hooks; origfunc_t m_OriginalFunc; }; class AbstractHookChainRegistry { protected: - void* m_Hooks[MAX_HOOKS_IN_CHAIN + 1]; // +1 for null + void *m_Hooks[MAX_HOOKS_IN_CHAIN + 1]; // +1 for null int m_Priorities[MAX_HOOKS_IN_CHAIN + 1]; int m_NumHooks; protected: - void addHook(void* hookFunc, int priority); - bool findHook(void* hookFunc) const; - void removeHook(void* hookFunc); + void addHook(void *hookFunc, int priority); + bool findHook(void *hookFunc) const; + void removeHook(void *hookFunc); public: AbstractHookChainRegistry(); @@ -119,8 +119,8 @@ public: template class IHookChainRegistryImpl : public IHookChainRegistry < t_ret, t_args...>, public AbstractHookChainRegistry { public: - typedef t_ret(*hookfunc_t)(IHookChain*, t_args...); - typedef t_ret(*origfunc_t)(t_args...); + typedef t_ret (*hookfunc_t)(IHookChain *, t_args...); + typedef t_ret (*origfunc_t)(t_args...); virtual ~IHookChainRegistryImpl() { } @@ -130,18 +130,18 @@ public: } virtual void registerHook(hookfunc_t hook, int priority) { - addHook((void*)hook, priority); + addHook((void *)hook, priority); } virtual void unregisterHook(hookfunc_t hook) { - removeHook((void*)hook); + removeHook((void *)hook); } }; template -class IVoidHookChainRegistryImpl : public IVoidHookChainRegistry , public AbstractHookChainRegistry { +class IVoidHookChainRegistryImpl: public IVoidHookChainRegistry , public AbstractHookChainRegistry { public: - typedef void(*hookfunc_t)(IVoidHookChain*, t_args...); - typedef void(*origfunc_t)(t_args...); + typedef void (*hookfunc_t)(IVoidHookChain *, t_args...); + typedef void (*origfunc_t)(t_args...); virtual ~IVoidHookChainRegistryImpl() { } @@ -151,10 +151,10 @@ public: } virtual void registerHook(hookfunc_t hook, int priority) { - addHook((void*)hook, priority); + addHook((void *)hook, priority); } virtual void unregisterHook(hookfunc_t hook) { - removeHook((void*)hook); + removeHook((void *)hook); } }; diff --git a/src/main.cpp b/src/main.cpp index 0af5e7b..6665f53 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,6 +68,8 @@ bool OnMetaAttach() g_RehldsHookchains->SV_DropClient()->registerHook(&SV_DropClient); g_RehldsHookchains->SV_CheckConsistencyResponse()->registerHook(&SV_CheckConsistencyResponse); g_RehldsHookchains->SV_TransferConsistencyInfo()->registerHook(&SV_TransferConsistencyInfo); + g_RehldsHookchains->SV_Spawn_f()->registerHook(&SV_Spawn_f); + g_RehldsHookchains->HandleNetCommand()->registerHook(&HandleNetCommand); SV_AddResource = g_RehldsFuncs->SV_AddResource; SV_FileInConsistencyList = g_RehldsFuncs->SV_FileInConsistencyList; @@ -107,6 +109,10 @@ void OnMetaDetach() g_RehldsHookchains->SV_DropClient()->unregisterHook(&SV_DropClient); g_RehldsHookchains->SV_CheckConsistencyResponse()->unregisterHook(&SV_CheckConsistencyResponse); g_RehldsHookchains->SV_TransferConsistencyInfo()->unregisterHook(&SV_TransferConsistencyInfo); + g_RehldsHookchains->SV_Spawn_f()->unregisterHook(&SV_Spawn_f); + g_RehldsHookchains->HandleNetCommand()->unregisterHook(&HandleNetCommand); + + ClearQueryFiles_api(); } void ServerDeactivate_Post() @@ -141,24 +147,6 @@ int SV_TransferConsistencyInfo(IRehldsHook_SV_TransferConsistencyInfo *chain) return chain->callNext() + nConsistency; } -void ClientPutInServer_Post(edict_t *pEntity) -{ - int nIndex = ENTINDEX(pEntity) - 1; - - if (nIndex < 0 || nIndex >= gpGlobals->maxClients) - RETURN_META(MRES_IGNORED); - - IGameClient *pClient = g_RehldsApi->GetServerStatic()->GetClient(nIndex); - - // client is connected to putinserver, go execute cmd out buffer - Exec.CommandExecute(pClient); - - // clear temporary files of response - g_pResource->Clear(pClient); - - SET_META_RESULT(MRES_IGNORED); -} - bool SV_CheckConsistencyResponse(IRehldsHook_SV_CheckConsistencyResponse *chain, IGameClient *pSenderClient, resource_t *resource, uint32 hash) { if (!g_pResource->FileConsistencyResponse(pSenderClient, resource, hash)) @@ -167,3 +155,33 @@ bool SV_CheckConsistencyResponse(IRehldsHook_SV_CheckConsistencyResponse *chain, // call next hook and take return of values from original func return chain->callNext(pSenderClient, resource, hash); } + +void SV_Spawn_f(IRehldsHook_SV_Spawn_f *chain) +{ + chain->callNext(); + + auto pClient = g_RehldsFuncs->GetHostClient(); + if (!pClient->IsConnected()) { + return; + } + + bool haveAtLeastOne; + g_pResource->GetResponseFile(pClient, nullptr, &haveAtLeastOne); + if (haveAtLeastOne) { + g_RecheckerHookchains.m_FileConsistencyFinal.callChain(nullptr, pClient); + } + + // client is connected to putinserver, go execute cmd out buffer + Exec.ExecuteCommand(pClient); +} + +const int clc_fileconsistency = 7; +void HandleNetCommand(IRehldsHook_HandleNetCommand *chain, IGameClient *cl, int8 opcode) +{ + if (opcode == clc_fileconsistency) { + // clear temporary files of response + g_pResource->Clear(cl); + } + + chain->callNext(cl, opcode); +} diff --git a/src/main.h b/src/main.h index a3dae97..58f42d5 100644 --- a/src/main.h +++ b/src/main.h @@ -3,6 +3,8 @@ void SV_DropClient(IRehldsHook_SV_DropClient *chain, IGameClient *pClient, bool crash, const char *string); bool SV_CheckConsistencyResponse(IRehldsHook_SV_CheckConsistencyResponse *chain, IGameClient *pSenderClient, resource_t *resource, uint32 hash); int SV_TransferConsistencyInfo(IRehldsHook_SV_TransferConsistencyInfo *chain); +void SV_Spawn_f(IRehldsHook_SV_Spawn_f *chain); +void HandleNetCommand(IRehldsHook_HandleNetCommand *chain, IGameClient *cl, int8 opcode); extern void (*SV_AddResource)(resourcetype_t type, const char *name, int size, unsigned char flags, int index); extern qboolean (*SV_FileInConsistencyList)(const char *filename, consistency_t **ppconsist); diff --git a/src/precompiled.h b/src/precompiled.h index f36ab50..6032cd9 100644 --- a/src/precompiled.h +++ b/src/precompiled.h @@ -1,17 +1,7 @@ #pragma once -#ifdef _WIN32 // WINDOWS - #pragma warning(disable : 4005) -#else - #define _stricmp strcasecmp - #define _mkdir mkdir - #ifdef __FUNCTION__ - #undef __FUNCTION__ - #endif - #define __FUNCTION__ __func__ -#endif // _WIN32 - -#define MAX_PATH_LENGTH 260 +#include "basetypes.h" +#include "archtypes.h" #include #include @@ -29,16 +19,15 @@ #include "engine_rehlds.h" #include "consistency.h" +#include "engine_hlds_api.h" #include "hookchains_impl.h" #include "rechecker_api.h" #include "rechecker_api_impl.h" #include "main.h" #include "task.h" -//#include "config.h" #include "resource.h" #include "cmdexec.h" -//#include "sdk_util.h" // UTIL_LogPrintf, etc #undef DLLEXPORT diff --git a/src/public_amalgamation.cpp b/src/public_amalgamation.cpp new file mode 100644 index 0000000..1fc308c --- /dev/null +++ b/src/public_amalgamation.cpp @@ -0,0 +1,3 @@ +#include "precompiled.h" + +#include "interface.cpp" diff --git a/src/rechecker_api.h b/src/rechecker_api.h index d84f60b..1ffaf4e 100644 --- a/src/rechecker_api.h +++ b/src/rechecker_api.h @@ -30,73 +30,103 @@ #include "hookchains.h" #include "interface.h" -#define RECHECKER_API_VERSION_MAJOR 1 -#define RECHECKER_API_VERSION_MINOR 0 +#define RECHECKER_API_VERSION_MAJOR 2 +#define RECHECKER_API_VERSION_MINOR 1 -enum flag_type_resources +enum ResourceType_e { - FLAG_TYPE_NONE = 0, - FLAG_TYPE_EXISTS, // to comparison with the specified hash value - FLAG_TYPE_MISSING, // check it missing file on client - FLAG_TYPE_IGNORE, // ignore the specified hash value - FLAG_TYPE_HASH_ANY, // any file with any the hash value + RES_TYPE_NONE = 0, + RES_TYPE_EXISTS, // to comparison with the specified hash value + RES_TYPE_MISSING, // check it missing file on client + RES_TYPE_IGNORE, // ignore the specified hash value + RES_TYPE_HASH_ANY, // any file with any the hash value }; class IResourceBuffer; // FileConsistencyProcess hook -typedef IVoidHookChain IRecheckerHook_FileConsistencyProcess; -typedef IVoidHookChainRegistry IRecheckerHookRegistry_FileConsistencyProcess; +typedef IVoidHookChain IRecheckerHook_FileConsistencyProcess; +typedef IVoidHookChainRegistry IRecheckerHookRegistry_FileConsistencyProcess; // CmdExec hook typedef IVoidHookChain IRecheckerHook_CmdExec; typedef IVoidHookChainRegistry IRecheckerHookRegistry_CmdExec; +// FileConsistencyFinal hook +typedef IVoidHookChain IRecheckerHook_FileConsistencyFinal; +typedef IVoidHookChainRegistry IRecheckerHookRegistry_FileConsistencyFinal; + class IRecheckerHookchains { -public: +protected: virtual ~IRecheckerHookchains() {} +public: virtual IRecheckerHookRegistry_FileConsistencyProcess *FileConsistencyProcess() = 0; virtual IRecheckerHookRegistry_CmdExec *CmdExec() = 0; + virtual IRecheckerHookRegistry_FileConsistencyFinal *FileConsistencyFinal() = 0; }; class IResourceBuffer { -public: +protected: virtual ~IResourceBuffer() {} +public: virtual uint32 GetFileHash() const = 0; - virtual flag_type_resources GetFileFlag() const = 0; + virtual ResourceType_e GetFileFlag() const = 0; virtual const char *GetFileName() const = 0; virtual const char *GetCmdExec() const = 0; virtual int GetLine() const = 0; virtual bool IsBreak() const = 0; // is have do not check a next files - virtual bool IsDuplicate() const = 0; // it is already have in resourcelist + virtual bool IsDuplicate() const = 0; // it is already have in resourcelist virtual bool IsAddEx() const = 0; // if it added via API }; -class IResourceFile { +class IResponseBuffer { +protected: + virtual ~IResponseBuffer() {} + public: + virtual int GetUserID() const = 0; + virtual IGameClient *GetGameClient() const = 0; + virtual const char *GetFileName() const = 0; + virtual uint32 GetClientHash() const = 0; + virtual uint32 GetPrevHash() const = 0; +}; + +class IResourceFile { +protected: virtual ~IResourceFile() {} +public: virtual const char *FindFilenameOfHash(uint32 hash) = 0; virtual int GetConsistencyNum() const = 0; virtual uint32 GetPrevHash() const = 0; }; +#undef FindResource + +using query_func_t = void (*)(IGameClient *pClient, uint32 hash, int uniqueId); + struct RecheckerFuncs_t { - IResourceBuffer *(*AddElement)(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, bool bBreak); - IResourceBuffer*(*FindElement)(char *filename); - IResourceFile*(*GetResourceFile)(); + IResourceBuffer *(*AddResource)(const char *filename, char *cmdExec, ResourceType_e flag, uint32 hash, bool bBreak); + IResourceBuffer *(*AddQueryFile)(const char *filename, ResourceType_e flag, uint32 hash, query_func_t callback, int uniqueId); + void (*RemoveQueryFile)(int uniqueId); + void (*ClearQueryFiles)(); + IResourceBuffer *(*FindResource)(const char *filename); + IResourceFile *(*GetResource)(); + IResponseBuffer *(*GetResponseFile)(IGameClient *pClient, const char *filename); + bool (*IsResourceExists)(IGameClient *pClient, const char *filename, uint32 &hash); }; class IRecheckerApi { -public: +protected: virtual ~IRecheckerApi() { } +public: virtual int GetMajorVersion() = 0; virtual int GetMinorVersion() = 0; - virtual const RecheckerFuncs_t* GetFuncs() = 0; - virtual IRecheckerHookchains* GetHookchains() = 0; + virtual const RecheckerFuncs_t *GetFuncs() = 0; + virtual IRecheckerHookchains *GetHookchains() = 0; }; diff --git a/src/rechecker_api_impl.cpp b/src/rechecker_api_impl.cpp index 0057063..3482559 100644 --- a/src/rechecker_api_impl.cpp +++ b/src/rechecker_api_impl.cpp @@ -29,52 +29,108 @@ CRecheckerApi g_RecheckerApi; CRecheckerHookchains g_RecheckerHookchains; -RecheckerFuncs_t g_RecheckerApiFuncs = +RecheckerFuncs_t g_RecheckerApiFuncs = { - &AddElement_api, - &FindElement_api, - &GetResourceFile_api + &AddResource_api, + &AddQueryFile_api, + &RemoveQueryFile_api, + &ClearQueryFiles_api, + &FindResource_api, + &GetResource_api, + &GetResponseFile_api, + &IsResourceExists_api, }; -IResourceBuffer *EXT_FUNC AddElement_api(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, bool bBreak) +IResourceBuffer *EXT_FUNC AddResource_api(const char *filename, char *cmdExec, ResourceType_e flag, uint32 hash, bool bBreak) { - auto nRes = g_pResource->AddElement(filename, cmdExec, flag, hash, 0, bBreak); - if (!nRes->IsDuplicate()) { - // resource was added via the API - nRes->SetAddEx(); - } + auto nRes = g_pResource->Add(filename, cmdExec, flag, hash, 0, bBreak); + // resource was added via the API + nRes->SetAddEx(); return nRes; } -IResourceBuffer *EXT_FUNC FindElement_api(char *filename) -{ - // to mark files which are not required to add to the resource again - for (auto res : (*g_pResource->GetResourceList())) - { - if (_stricmp(res->GetFileName(), filename) == 0) - { - // resource name already have, return its; - return res; - } - } +std::vector g_QueryFiles; - return nullptr; +IResourceBuffer *EXT_FUNC AddQueryFile_api(const char *filename, ResourceType_e flag, uint32 hash, query_func_t callback, int uniqueId) +{ + g_QueryFiles.push_back(new query_file_t(filename, flag, hash, callback, uniqueId)); + + auto nRes = g_pResource->Add(filename, "", flag, hash, -1, false); + + // resource was added via the API + nRes->SetAddEx(); + return nRes; } -IResourceFile *EXT_FUNC GetResourceFile_api() +void EXT_FUNC ClearQueryFiles_api() { + for (auto query : g_QueryFiles) { + delete query; + } + + g_QueryFiles.clear(); +} + +void EXT_FUNC RemoveQueryFile_api(int uniqueId) +{ + auto iter = g_QueryFiles.begin(); + while (iter != g_QueryFiles.end()) + { + if ((*iter)->uniqueId != uniqueId) { + iter++; + continue; + } + + delete (*iter); + iter = g_QueryFiles.erase(iter); + } + + if (g_QueryFiles.size() <= 0) { + g_QueryFiles.clear(); + } +} + +IResourceBuffer *EXT_FUNC FindResource_api(const char *filename) { + return g_pResource->GetResourceFile(filename); +} + +IResponseBuffer *EXT_FUNC GetResponseFile_api(IGameClient *pClient, const char *filename) { + return g_pResource->GetResponseFile(pClient, filename); +} + +bool EXT_FUNC IsResourceExists_api(IGameClient *pClient, const char *filename, uint32 &hash) +{ + auto res = g_pResource->GetResponseFile(pClient, filename); + if (res->GetClientHash() == res->GetPrevHash()) { + // file is missing? + return false; + } + + if (hash && res->GetClientHash() == hash) { + return true; + } + + hash = res->GetClientHash(); + return true; +} + +IResourceFile *EXT_FUNC GetResource_api() { return g_pResource; } -IRecheckerHookRegistry_FileConsistencyProcess* CRecheckerHookchains::FileConsistencyProcess() { +IRecheckerHookRegistry_FileConsistencyProcess *CRecheckerHookchains::FileConsistencyProcess() { return &m_FileConsistencyProcess; } -IRecheckerHookRegistry_CmdExec* CRecheckerHookchains::CmdExec() { +IRecheckerHookRegistry_CmdExec *CRecheckerHookchains::CmdExec() { return &m_CmdExec; } +IRecheckerHookRegistry_FileConsistencyFinal *CRecheckerHookchains::FileConsistencyFinal() { + return &m_FileConsistencyFinal; +} + int EXT_FUNC CRecheckerApi::GetMajorVersion() { return RECHECKER_API_VERSION_MAJOR; @@ -85,12 +141,12 @@ int EXT_FUNC CRecheckerApi::GetMinorVersion() return RECHECKER_API_VERSION_MINOR; } -const RecheckerFuncs_t* EXT_FUNC CRecheckerApi::GetFuncs() +const RecheckerFuncs_t *EXT_FUNC CRecheckerApi::GetFuncs() { return &g_RecheckerApiFuncs; } -IRecheckerHookchains* EXT_FUNC CRecheckerApi::GetHookchains() +IRecheckerHookchains *EXT_FUNC CRecheckerApi::GetHookchains() { return &g_RecheckerHookchains; } diff --git a/src/rechecker_api_impl.h b/src/rechecker_api_impl.h index cdc6df5..9f31601 100644 --- a/src/rechecker_api_impl.h +++ b/src/rechecker_api_impl.h @@ -28,21 +28,27 @@ #pragma once // FileConsistencyProcess hook -typedef IVoidHookChainImpl CRecheckerHook_FileConsistencyProcess; -typedef IVoidHookChainRegistryImpl CRecheckerHookRegistry_FileConsistencyProcess; +typedef IVoidHookChainImpl CRecheckerHook_FileConsistencyProcess; +typedef IVoidHookChainRegistryImpl CRecheckerHookRegistry_FileConsistencyProcess; // CmdExec hook typedef IVoidHookChainImpl CRecheckerHook_CmdExec; typedef IVoidHookChainRegistryImpl CRecheckerHookRegistry_CmdExec; +// FileConsistencyFinal hook +typedef IVoidHookChainImpl CRecheckerHook_FileConsistencyFinal; +typedef IVoidHookChainRegistryImpl CRecheckerHookRegistry_FileConsistencyFinal; + class CRecheckerHookchains: public IRecheckerHookchains { public: CRecheckerHookRegistry_FileConsistencyProcess m_FileConsistencyProcess; CRecheckerHookRegistry_CmdExec m_CmdExec; + CRecheckerHookRegistry_FileConsistencyFinal m_FileConsistencyFinal; public: virtual IRecheckerHookRegistry_FileConsistencyProcess *FileConsistencyProcess(); virtual IRecheckerHookRegistry_CmdExec *CmdExec(); + virtual IRecheckerHookRegistry_FileConsistencyFinal *FileConsistencyFinal(); }; extern CRecheckerHookchains g_RecheckerHookchains; @@ -53,11 +59,45 @@ public: virtual int GetMajorVersion(); virtual int GetMinorVersion(); - virtual const RecheckerFuncs_t* GetFuncs(); - virtual IRecheckerHookchains* GetHookchains(); + virtual const RecheckerFuncs_t *GetFuncs(); + virtual IRecheckerHookchains *GetHookchains(); }; void Rechecker_Api_Init(); -IResourceBuffer *AddElement_api(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, bool bBreak); -IResourceBuffer *FindElement_api(char *filename); -IResourceFile *GetResourceFile_api(); +IResourceBuffer *AddResource_api(const char *filename, char *cmdExec, ResourceType_e flag, uint32 hash, bool bBreak); +IResourceBuffer *AddQueryFile_api(const char *filename, ResourceType_e flag, uint32 hash, query_func_t callback, int uniqueId); +IResourceBuffer *FindResource_api(const char *filename); +IResourceFile *GetResource_api(); +IResponseBuffer *GetResponseFile_api(IGameClient *pClient, const char *filename); +bool IsResourceExists_api(IGameClient *pClient, const char *filename, uint32 &hash); +void ClearQueryFiles_api(); +void RemoveQueryFile_api(int uniqueId); + +struct query_file_t +{ + query_file_t(const char *filename, const ResourceType_e flag, uint32 hash, query_func_t func, int uniqueId); + ~query_file_t() + { + delete[] this->filename; + this->filename = nullptr; + } + + uint32 hash; + int uniqueId; + char *filename; + ResourceType_e flag; + query_func_t func; +}; + +inline query_file_t::query_file_t(const char *filename, const ResourceType_e flag, uint32 hash, query_func_t func, int uniqueId) +{ + this->filename = new char [strlen(filename) + 1]; + strcpy(this->filename, filename); + + this->flag = flag; + this->hash = hash; + this->func = func; + this->uniqueId = uniqueId; +} + +extern std::vector g_QueryFiles; diff --git a/src/resource.cpp b/src/resource.cpp index 5c482d8..5e04f86 100644 --- a/src/resource.cpp +++ b/src/resource.cpp @@ -41,7 +41,12 @@ int CResourceFile::CreateResourceList() // check limit resource if (g_RehldsServerData->GetResourcesNum() >= RESOURCE_MAX_COUNT) { - UTIL_Printf(__FUNCTION__ ": can't add resource \"%s\" on line %d; exceeded the limit of resources max '%d'\n", res->GetFileName(), res->GetLine(), RESOURCE_MAX_COUNT); + if (res->IsAddEx()) { + UTIL_Printf("%s: can't add resource \"%s\"; exceeded the limit of resources max '%d'\n", __func__, res->GetFileName(), RESOURCE_MAX_COUNT); + } else { + UTIL_Printf("%s: can't add resource \"%s\" on line %d; exceeded the limit of resources max '%d'\n", __func__, res->GetFileName(), res->GetLine(), RESOURCE_MAX_COUNT); + } + break; } @@ -49,18 +54,23 @@ int CResourceFile::CreateResourceList() // https://github.com/dreamstalker/rehlds/blob/beaeb65/rehlds/engine/sv_user.cpp#L374 if (nCustomConsistency + m_ConsistencyNum >= MAX_RANGE_CONSISTENCY) { - UTIL_Printf(__FUNCTION__ ": can't add consistency \"%s\" on line %d; index out of bounds '%d'\n", res->GetFileName(), res->GetLine(), MAX_RANGE_CONSISTENCY); + if (res->IsAddEx()) { + UTIL_Printf("%s: can't add consistency \"%s\"; index out of bounds '%d'\n", __func__, res->GetFileName(), MAX_RANGE_CONSISTENCY); + } else { + UTIL_Printf("%s: can't add consistency \"%s\" on line %d; index out of bounds '%d'\n", __func__, res->GetFileName(), res->GetLine(), MAX_RANGE_CONSISTENCY); + } + break; } - Log(LOG_DETAILED, __FUNCTION__ " -> file: (%s), cmdexec: (%s), hash: (%x), typeFind: (%s)", res->GetFileName(), res->GetCmdExec(), res->GetFileHash(), szTypeNames[ res->GetFileFlag() ]); + Log(LOG_DETAILED, "%s -> file: (%s), cmdexec: (%s), hash: (%x), typeFind: (%s), ex: (%d)", __func__, res->GetFileName(), res->GetCmdExec(), res->GetFileHash(), szTypeNames[ res->GetFileFlag() ], res->IsAddEx()); SV_AddResource(t_decal, res->GetFileName(), 0, RES_CHECKFILE, startIndex++); - ++nCustomConsistency; + nCustomConsistency++; } } std::vector sortList; - for (int i = 0; i < g_RehldsServerData->GetResourcesNum(); ++i) + for (int i = 0; i < g_RehldsServerData->GetResourcesNum(); i++) { sortList.push_back(*g_RehldsServerData->GetResource(i)); } @@ -83,7 +93,7 @@ int CResourceFile::CreateResourceList() return a.nIndex < b.nIndex; }); - for (auto res : sortList) + for (auto& res : sortList) { // Add new resource in the own order SV_AddResource(res.type, res.szFileName, res.nDownloadSize, res.ucFlags, res.nIndex); @@ -114,15 +124,20 @@ void CResourceFile::Clear(IGameClient *pClient) { // remove each entries by pClient auto nUserID = g_engfuncs.pfnGetPlayerUserId(pClient->GetEdict()); - m_responseList.erase( - std::remove_if( - m_responseList.begin(), - m_responseList.end(), - [nUserID](const CResponseBuffer *pFiles) -> bool { - return (pFiles->GetUserID() == nUserID); - } - ), m_responseList.end() - ); + auto iter = m_responseList.begin(); + while (iter != m_responseList.end()) + { + CResponseBuffer *pFiles = (*iter); + + // erase cmdexec + if (pFiles->GetUserID() == nUserID) + { + delete pFiles; + iter = m_responseList.erase(iter); + } + else + iter++; + } m_PrevHash = 0; return; @@ -133,6 +148,12 @@ void CResourceFile::Clear(IGameClient *pClient) m_ConsistencyNum = 0; // clear resources + for (auto it : m_resourceList) + delete it; + + for (auto it : m_responseList) + delete it; + m_resourceList.clear(); m_responseList.clear(); @@ -216,7 +237,7 @@ void CreateDirectory(const char *path) void CResourceFile::Init() { char *pos; - char path[MAX_PATH_LENGTH]; + char path[MAX_PATH]; strncpy(path, GET_PLUGIN_PATH(PLID), sizeof(path) - 1); path[sizeof(path) - 1] = '\0'; @@ -315,9 +336,9 @@ void CResourceFile::LoadResources() FILE *fp; int argc; int len; - flag_type_resources flag; - char filename[MAX_PATH_LENGTH]; - char cmdBufExec[MAX_PATH_LENGTH]; + ResourceType_e flag; + char filename[MAX_PATH]; + char cmdBufExec[MAX_PATH]; int cline = 0; bool bBreak; @@ -325,7 +346,7 @@ void CResourceFile::LoadResources() if (!fp) { - UTIL_Printf(__FUNCTION__ ": can't find path to " FILE_INI_RESOURCES "\n"); + //UTIL_Printf("%s: can't find path to " FILE_INI_RESOURCES "\n", __func__); return; } @@ -346,7 +367,7 @@ void CResourceFile::LoadResources() argc = 0; bBreak = false; - flag = FLAG_TYPE_NONE; + flag = RES_TYPE_NONE; memset(hash, 0, sizeof(hash)); @@ -371,18 +392,18 @@ void CResourceFile::LoadResources() if (_stricmp((const char *)pbuf, "UNKNOWN") == 0) { - flag = FLAG_TYPE_HASH_ANY; + flag = RES_TYPE_HASH_ANY; } else if (_stricmp((const char *)pbuf, "MISSING") == 0) { - flag = FLAG_TYPE_MISSING; + flag = RES_TYPE_MISSING; } else { for (int i = 0; i < sizeof(pbuf) / 2; ++i) hash[i] = hexbyte(&pbuf[i * 2]); - flag = FLAG_TYPE_EXISTS; + flag = RES_TYPE_EXISTS; } break; } @@ -393,7 +414,7 @@ void CResourceFile::LoadResources() if (_stricmp(cmdBufExec, "IGNORE") == 0) { - flag = FLAG_TYPE_IGNORE; + flag = RES_TYPE_IGNORE; cmdBufExec[0] = '\0'; } else if (_stricmp(cmdBufExec, "BREAK") == 0) @@ -412,7 +433,7 @@ void CResourceFile::LoadResources() { if (_stricmp(pToken, "IGNORE") == 0) { - flag = FLAG_TYPE_IGNORE; + flag = RES_TYPE_IGNORE; } else if (_stricmp(pToken, "BREAK") == 0) { @@ -434,7 +455,7 @@ void CResourceFile::LoadResources() } #define LOG_PRINT_FAILED(str, ...)\ - UTIL_Printf(__FUNCTION__ ": Failed to load \"" FILE_INI_RESOURCES "\"; " str, __VA_ARGS__);\ + UTIL_Printf("%s: Failed to load \"" FILE_INI_RESOURCES "\"; %s", __func__, str, __VA_ARGS__);\ continue; if (argc >= MAX_PARSE_ARGUMENT) @@ -444,24 +465,24 @@ void CResourceFile::LoadResources() { LOG_PRINT_FAILED("path to filename is empty on line %d\n", cline); } - else if (!IsFileHasExtension(filename)) - { - LOG_PRINT_FAILED("filename has no extension on line %d\n", cline); - } + //else if (!IsFileHasExtension(filename)) + //{ + // LOG_PRINT_FAILED("filename has no extension on line %d\n", cline); + //} else if (!IsValidFilename(filename, pchar)) { LOG_PRINT_FAILED("filename has invalid character '%c' on line %d\n", pchar, cline); } - else if (flag == FLAG_TYPE_NONE) + else if (flag == RES_TYPE_NONE) { LOG_PRINT_FAILED("parsing hash failed on line %d\n", cline); } - else if (strlen(cmdBufExec) <= 0 && (flag != FLAG_TYPE_IGNORE && !bBreak)) + else if (strlen(cmdBufExec) <= 0 && (flag != RES_TYPE_IGNORE && !bBreak)) { LOG_PRINT_FAILED("parsing command line is empty on line %d\n", cline); } - AddElement(filename, cmdBufExec, flag, *(uint32 *)&hash[0], cline, bBreak); + Add(filename, cmdBufExec, flag, *(uint32 *)&hash[0], cline, bBreak); } else if (pToken || argc > ARG_TYPE_FILE_NAME) { @@ -538,7 +559,7 @@ const char *CResourceFile::GetNextToken(char **pbuf) return res; } -CResourceBuffer *CResourceFile::AddElement(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, int line, bool bBreak) +CResourceBuffer *CResourceFile::Add(const char *filename, char *cmdExec, ResourceType_e flag, uint32 hash, int line, bool bBreak) { auto nRes = new CResourceBuffer(filename, cmdExec, flag, hash, line, bBreak); @@ -559,38 +580,93 @@ CResourceBuffer *CResourceFile::AddElement(char *filename, char *cmdExec, flag_t void CResourceFile::AddFileResponse(IGameClient *pSenderClient, char *filename, uint32 hash) { - m_responseList.push_back(new CResponseBuffer(pSenderClient, filename, hash)); + m_responseList.push_back(new CResponseBuffer(pSenderClient, filename, hash, m_PrevHash)); } -void EXT_FUNC FileConsistencyProcess_hook(IGameClient *pSenderClient, IResourceBuffer *res, flag_type_resources typeFind, uint32 hash) +void EXT_FUNC FileConsistencyProcess_hook(IGameClient *pSenderClient, IResourceBuffer *res, ResourceType_e typeFind, uint32 hash) { - if (typeFind == FLAG_TYPE_NONE) + if (typeFind == RES_TYPE_NONE) return; - auto nRes = static_cast(res); + auto pRes = static_cast(res); + + // Fire query to callback's + for (auto query : g_QueryFiles) + { + if (!res->IsAddEx() || strcmp(query->filename, pRes->GetFileName()) != 0) + continue; + + if (query->flag == typeFind) { + query->func(pSenderClient, hash, query->uniqueId); + } + } // push exec cmd - Exec.AddElement(pSenderClient, nRes, hash); - g_pResource->PrintLog(pSenderClient, nRes, typeFind, hash); + Exec.Add(pSenderClient, pRes, hash); + g_pResource->PrintLog(pSenderClient, pRes, typeFind, hash); } -void CResourceFile::PrintLog(IGameClient *pSenderClient, CResourceBuffer *res, flag_type_resources typeFind, uint32 hash) +void CResourceFile::PrintLog(IGameClient *pSenderClient, CResourceBuffer *res, ResourceType_e typeFind, uint32 hash) { - flag_type_log type = (typeFind == FLAG_TYPE_IGNORE) ? LOG_DETAILED : LOG_NORMAL; - Log(type, " -> file: (%s), exphash: (%x), got: (%x), typeFind: (%s), prevhash: (%x), (#%u)(%s), prevfile: (%s), findathash: (%s), md5hex: (%x)", + flag_type_log type = (typeFind == RES_TYPE_IGNORE) ? LOG_DETAILED : LOG_NORMAL; + Log(type, " -> file: (%s), exphash: (%x), got: (%x), typeFind: (%s), prevhash: (%x), (#%u)(%s), prevfile: (%s), findathash: (%s), md5hex: (%x), ex: (%d)", res->GetFileName(), res->GetFileHash(), hash, szTypeNames[ typeFind ], m_PrevHash, g_engfuncs.pfnGetPlayerUserId(pSenderClient->GetEdict()), - pSenderClient->GetName(), FindFilenameOfHash(m_PrevHash), FindFilenameOfHash(hash), _byteswap_ulong(hash)); + pSenderClient->GetName(), FindFilenameOfHash(m_PrevHash), FindFilenameOfHash(hash), _byteswap_ulong(hash), res->IsAddEx()); +} + +IResourceBuffer *CResourceFile::GetResourceFile(const char *filename) +{ + // to mark files which are not required to add to the resource again + for (auto res : m_resourceList) + { + if (_stricmp(res->GetFileName(), filename) == 0) + { + // resource name already have, return its; + return res; + } + } + + return nullptr; +} + +IResponseBuffer *CResourceFile::GetResponseFile(IGameClient *pClient, const char *filename, bool *firstFound) +{ + if (firstFound) { + *firstFound = false; + } + + int nUserID = g_engfuncs.pfnGetPlayerUserId(pClient->GetEdict()); + for (auto res : m_responseList) + { + if (res->GetUserID() != nUserID) { + continue; + } + + if (firstFound) { + *firstFound = true; + } + + if (!filename) { + break; + } + + if (_stricmp(res->GetFileName(), filename) == 0) { + return res; + } + } + + return nullptr; } bool CResourceFile::FileConsistencyResponse(IGameClient *pSenderClient, resource_t *resource, uint32 hash) { bool bHandled = false; - flag_type_resources typeFind; + ResourceType_e typeFind; std::vector tempResourceList; if (resource->type != t_decal || resource->nIndex < 4095) // if by some miracle the decals will have the flag RES_CHECKFILE - // to be sure not bypass the decals + // to be sure not bypass the decals { AddFileResponse(pSenderClient, resource->szFileName, hash); m_PrevHash = hash; @@ -611,21 +687,21 @@ bool CResourceFile::FileConsistencyResponse(IGameClient *pSenderClient, resource typeFind = res->GetFileFlag(); - if (m_PrevHash == hash && typeFind != FLAG_TYPE_MISSING) - typeFind = FLAG_TYPE_NONE; + if (m_PrevHash == hash && typeFind != RES_TYPE_MISSING) + typeFind = RES_TYPE_NONE; switch (typeFind) { - case FLAG_TYPE_IGNORE: + case RES_TYPE_IGNORE: tempResourceList.push_back(res); break; - case FLAG_TYPE_EXISTS: + case RES_TYPE_EXISTS: if (res->GetFileHash() != hash) { - typeFind = FLAG_TYPE_NONE; + typeFind = RES_TYPE_NONE; } break; - case FLAG_TYPE_HASH_ANY: + case RES_TYPE_HASH_ANY: for (auto temp : tempResourceList) { if (_stricmp(temp->GetFileName(), res->GetFileName()) != 0) @@ -633,19 +709,19 @@ bool CResourceFile::FileConsistencyResponse(IGameClient *pSenderClient, resource if (temp->GetFileHash() == hash) { - typeFind = FLAG_TYPE_NONE; + typeFind = RES_TYPE_NONE; break; } } break; - case FLAG_TYPE_MISSING: + case RES_TYPE_MISSING: if (m_PrevHash != hash) { - typeFind = FLAG_TYPE_NONE; + typeFind = RES_TYPE_NONE; } break; default: - typeFind = FLAG_TYPE_NONE; + typeFind = RES_TYPE_NONE; break; } @@ -653,8 +729,8 @@ bool CResourceFile::FileConsistencyResponse(IGameClient *pSenderClient, resource bHandled = true; } - m_PrevHash = hash; AddFileResponse(pSenderClient, resource->szFileName, hash); + m_PrevHash = hash; return !bHandled; } @@ -679,7 +755,7 @@ void CResourceFile::ClearStringsCache() m_StringsCache.clear(); } -CResourceBuffer::CResourceBuffer(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, int line, bool bBreak) +CResourceBuffer::CResourceBuffer(const char *filename, char *cmdExec, ResourceType_e flag, uint32 hash, int line, bool bBreak) { m_FileName = CResourceFile::DuplicateString(filename); m_CmdExec = (cmdExec[0] != '\0') ? CResourceFile::DuplicateString(cmdExec) : nullptr; @@ -693,12 +769,13 @@ CResourceBuffer::CResourceBuffer(char *filename, char *cmdExec, flag_type_resour m_AddEx = false; } -CResourceFile::CResponseBuffer::CResponseBuffer(IGameClient *pSenderClient, char *filename, uint32 hash) +CResourceFile::CResponseBuffer::CResponseBuffer(IGameClient *pSenderClient, char *filename, uint32 hash, uint32 prevHash) { m_pClient = pSenderClient; m_FileName = DuplicateString(filename); m_ClientHash = hash; m_UserID = g_engfuncs.pfnGetPlayerUserId(pSenderClient->GetEdict()); + m_PrevHash = prevHash; } const char *CResourceFile::FindFilenameOfHash(uint32 hash) diff --git a/src/resource.h b/src/resource.h index 527db8c..16ba359 100644 --- a/src/resource.h +++ b/src/resource.h @@ -1,11 +1,11 @@ #pragma once -#define FILE_INI_RESOURCES "resources.ini" -#define MAX_CMD_LENGTH 128 +#define FILE_INI_RESOURCES "resources.ini" +#define MAX_CMD_LENGTH 128 #define MAX_RANGE_CONSISTENCY 1024 -#define RESOURCE_INDEX_BITS 12 -#define RESOURCE_MAX_COUNT (1 << RESOURCE_INDEX_BITS) +#define RESOURCE_INDEX_BITS 12 +#define RESOURCE_MAX_COUNT (1 << RESOURCE_INDEX_BITS) enum flag_type_log { @@ -28,13 +28,13 @@ enum arg_type_e class CResourceBuffer: public IResourceBuffer { public: - CResourceBuffer(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, int line, bool bBreak); + CResourceBuffer(const char *filename, char *cmdExec, ResourceType_e flag, uint32 hash, int line, bool bBreak); uint32 GetFileHash() const { return m_FileHash; }; - flag_type_resources GetFileFlag() const { return m_Flag; }; + ResourceType_e GetFileFlag() const { return m_Flag; }; const char *GetFileName() const { return m_FileName; }; - const char *GetCmdExec() const { return m_CmdExec; }; + const char *GetCmdExec() const { return (m_CmdExec == nullptr) ? "" : m_CmdExec; }; int GetLine() const { return m_Line; }; bool IsBreak() const { return m_Break; }; @@ -47,7 +47,7 @@ public: private: uint32 m_FileHash; - flag_type_resources m_Flag; + ResourceType_e m_Flag; int m_Line; const char *m_FileName; @@ -69,7 +69,7 @@ public: void LoadResources(); int CreateResourceList(); void Log(flag_type_log type, const char *fmt, ...); - void PrintLog(IGameClient *pSenderClient, CResourceBuffer *res, flag_type_resources typeFind, uint32 hash); + void PrintLog(IGameClient *pSenderClient, CResourceBuffer *res, ResourceType_e typeFind, uint32 hash); bool FileConsistencyResponse(IGameClient *pSenderClient, resource_t *resource, uint32 hash); static const char *DuplicateString(const char *str); @@ -77,21 +77,23 @@ public: private: // buffer for response list - class CResponseBuffer + class CResponseBuffer: public IResponseBuffer { public: - CResponseBuffer(IGameClient *pSenderClient, char *filename, uint32 hash); + CResponseBuffer(IGameClient *pSenderClient, char *filename, uint32 hash, uint32 prevHash); int GetUserID() const { return m_UserID; }; IGameClient *GetGameClient() const { return m_pClient; }; const char *GetFileName() const { return m_FileName; }; uint32 GetClientHash() const { return m_ClientHash; }; + uint32 GetPrevHash() const { return m_PrevHash; }; private: int m_UserID; IGameClient *m_pClient; const char *m_FileName; uint32 m_ClientHash; + uint32 m_PrevHash; }; private: @@ -115,18 +117,20 @@ private: int m_ConsistencyNum; uint32 m_PrevHash; - char m_PathDir[MAX_PATH_LENGTH]; - char m_LogFilePath[MAX_PATH_LENGTH]; // log data + char m_PathDir[MAX_PATH]; + char m_LogFilePath[MAX_PATH]; // log data typedef std::vector StringList; static StringList m_StringsCache; public: + IResourceBuffer *GetResourceFile(const char *filename); + IResponseBuffer *GetResponseFile(IGameClient *pClient, const char *filename, bool *firstFound = nullptr); + const char *FindFilenameOfHash(uint32 hash); int GetConsistencyNum() const { return m_ConsistencyNum; } uint32 GetPrevHash() const { return m_PrevHash; } - CResourceBuffer *AddElement(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, int line, bool bBreak); - const ResourceList *GetResourceList() const { return &m_resourceList; } + CResourceBuffer *Add(const char *filename, char *cmdExec, ResourceType_e flag, uint32 hash, int line, bool bBreak); }; extern CResourceFile *g_pResource;