diff --git a/common/const.h b/common/const.h index e8e3743..aa081dc 100644 --- a/common/const.h +++ b/common/const.h @@ -71,6 +71,9 @@ #define FL_KILLME (1<<30) // This entity is marked for death -- This allows the engine to kill ents at the appropriate time #define FL_DORMANT (1<<31) // Entity is dormant, no updates to client +// SV_EmitSound2 flags +#define SND_EMIT2_NOPAS (1<<0) // never to do check PAS +#define SND_EMIT2_INVOKER (1<<1) // do not send to the client invoker // Engine edict->spawnflags #define SF_NOTINDEATHMATCH 0x0800 // Do not spawn when deathmatch and loading entities from a file diff --git a/engine/rehlds_api.h b/engine/rehlds_api.h index fc6fe89..0e3ada2 100644 --- a/engine/rehlds_api.h +++ b/engine/rehlds_api.h @@ -35,7 +35,7 @@ #include "model.h" #define REHLDS_API_VERSION_MAJOR 2 -#define REHLDS_API_VERSION_MINOR 7 +#define REHLDS_API_VERSION_MINOR 12 //Steam_NotifyClientConnect hook typedef IHookChain IRehldsHook_Steam_NotifyClientConnect; @@ -169,6 +169,26 @@ typedef IHookChainRegistry IRehldsHookRegistry_SV_TransferConsistencyInfo; typedef IHookChain IRehldsHook_Steam_GSBUpdateUserData; typedef IHookChainRegistry IRehldsHookRegistry_Steam_GSBUpdateUserData; +//Cvar_DirectSet hook +typedef IVoidHookChain IRehldsHook_Cvar_DirectSet; +typedef IVoidHookChainRegistry IRehldsHookRegistry_Cvar_DirectSet; + +//SV_EstablishTimeBase hook +typedef IVoidHookChain IRehldsHook_SV_EstablishTimeBase; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_EstablishTimeBase; + +//SV_Spawn_f hook +typedef IVoidHookChain<> IRehldsHook_SV_Spawn_f; +typedef IVoidHookChainRegistry<> IRehldsHookRegistry_SV_Spawn_f; + +//SV_CreatePacketEntities hook +typedef IHookChain IRehldsHook_SV_CreatePacketEntities; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CreatePacketEntities; + +//SV_EmitSound2 hook +typedef IHookChain IRehldsHook_SV_EmitSound2; +typedef IHookChainRegistry IRehldsHookRegistry_SV_EmitSound2; + class IRehldsHookchains { public: virtual ~IRehldsHookchains() { } @@ -206,6 +226,11 @@ public: virtual IRehldsHookRegistry_Steam_GSGetSteamID* Steam_GSGetSteamID() = 0; virtual IRehldsHookRegistry_SV_TransferConsistencyInfo* SV_TransferConsistencyInfo() = 0; virtual IRehldsHookRegistry_Steam_GSBUpdateUserData* Steam_GSBUpdateUserData() = 0; + virtual IRehldsHookRegistry_Cvar_DirectSet* Cvar_DirectSet() = 0; + virtual IRehldsHookRegistry_SV_EstablishTimeBase* SV_EstablishTimeBase() = 0; + virtual IRehldsHookRegistry_SV_Spawn_f* SV_Spawn_f() = 0; + virtual IRehldsHookRegistry_SV_CreatePacketEntities* SV_CreatePacketEntities() = 0; + virtual IRehldsHookRegistry_SV_EmitSound2* SV_EmitSound2() = 0; }; struct RehldsFuncs_t { @@ -251,6 +276,10 @@ struct RehldsFuncs_t { void*(*GetPluginApi)(const char *name); void(*RegisterPluginApi)(const char *name, void *impl); qboolean(*SV_FileInConsistencyList)(const char *filename, struct consistency_s **ppconsist); + qboolean(*Steam_NotifyClientConnect)(IGameClient *cl, const void *pvSteam2Key, unsigned int ucbSteam2Key); + void(*Steam_NotifyClientDisconnect)(IGameClient* cl); + void(*SV_StartSound)(int recipients, edict_t *entity, int channel, const char *sample, int volume, float attenuation, int flags, int pitch); + bool(*SV_EmitSound2)(edict_t *entity, IGameClient *receiver, int channel, const char *sample, float volume, float attenuation, int flags, int pitch, int emitFlags, const float *pOrigin); }; class IRehldsApi { @@ -266,4 +295,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/rehlds_interfaces.h b/engine/rehlds_interfaces.h index 0a47112..e2b909f 100644 --- a/engine/rehlds_interfaces.h +++ b/engine/rehlds_interfaces.h @@ -71,6 +71,7 @@ public: virtual void SetLastVoiceTime(double time) = 0; virtual double GetLastVoiceTime() = 0; virtual bool GetLoopback() = 0; + virtual struct usercmd_s *GetLastCmd() = 0; // this must be the last virtual function in class #ifdef REHLDS_SELF @@ -125,4 +126,7 @@ public: virtual double GetTime() = 0; virtual void SetResourcesNum(int num) = 0; virtual struct resource_s *GetResource(int index) = 0; + virtual void SetName(const char* name) = 0; + virtual class ISteamGameServer *GetSteamGameServer() = 0; + virtual struct netadr_s *GetNetFrom() = 0; }; diff --git a/engine/sys_shared.cpp b/engine/sys_shared.cpp index b5d4409..a642c76 100644 --- a/engine/sys_shared.cpp +++ b/engine/sys_shared.cpp @@ -35,6 +35,7 @@ #define SSSE3_FLAG (1<<9) #define SSE4_1_FLAG (1<<19) #define SSE4_2_FLAG (1<<20) +#define POPCNT_FLAG (1<<23) #define AVX_FLAG (1<<28) #define AVX2_FLAG (1<<5) @@ -56,6 +57,7 @@ void Sys_CheckCpuInstructionsSupport(void) cpuinfo.ssse3 = (cpuid_data[2] & SSSE3_FLAG) ? 1 : 0; cpuinfo.sse4_1 = (cpuid_data[2] & SSE4_1_FLAG) ? 1 : 0; cpuinfo.sse4_2 = (cpuid_data[2] & SSE4_2_FLAG) ? 1 : 0; + cpuinfo.popcnt = (cpuid_data[2] & POPCNT_FLAG) ? 1 : 0; cpuinfo.avx = (cpuid_data[2] & AVX_FLAG) ? 1 : 0; #if defined ASMLIB_H diff --git a/engine/sys_shared.h b/engine/sys_shared.h index a9665bf..5b5da98 100644 --- a/engine/sys_shared.h +++ b/engine/sys_shared.h @@ -31,7 +31,7 @@ typedef struct cpuinfo_s { - uint8 sse3, ssse3, sse4_1, sse4_2, avx, avx2; + uint8 sse3, ssse3, sse4_1, sse4_2, avx, avx2, popcnt; } cpuinfo_t; extern cpuinfo_t cpuinfo; diff --git a/msvc/rechecker.vcxproj b/msvc/rechecker.vcxproj index 5c51048..ded7358 100644 --- a/msvc/rechecker.vcxproj +++ b/msvc/rechecker.vcxproj @@ -163,7 +163,11 @@ + + + + @@ -176,6 +180,8 @@ + + diff --git a/msvc/rechecker.vcxproj.filters b/msvc/rechecker.vcxproj.filters index 216e9fe..55170fd 100644 --- a/msvc/rechecker.vcxproj.filters +++ b/msvc/rechecker.vcxproj.filters @@ -462,6 +462,14 @@ + + + + public + + + public + @@ -480,6 +488,8 @@ + + @@ -506,6 +516,9 @@ {d8dea905-0ad8-4f5e-973c-fc9917c49e68} + + {ec8144a1-347d-47dc-9f5f-ffe4670ac29d} + diff --git a/public/rechecker_api.h b/public/rechecker_api.h new file mode 100644 index 0000000..a52d383 --- /dev/null +++ b/public/rechecker_api.h @@ -0,0 +1,102 @@ +/* +* +* 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 "hookchains.h" +#include "interface.h" + +#define RECHECKER_API_VERSION_MAJOR 1 +#define RECHECKER_API_VERSION_MINOR 0 + +enum flag_type_resources +{ + 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 +}; + +class IResourceBuffer; + +// FileConsistencyProcess hook +typedef IHookChain IRecheckerHook_FileConsistencyProcess; +typedef IHookChainRegistry IRecheckerHookRegistry_FileConsistencyProcess; + +// CmdExec hook +typedef IVoidHookChain IRecheckerHook_CmdExec; +typedef IVoidHookChainRegistry IRecheckerHookRegistry_CmdExec; + +class IRecheckerHookchains { +public: + virtual ~IRecheckerHookchains() { } + + virtual IRecheckerHookRegistry_FileConsistencyProcess* FileConsistencyProcess() = 0; + virtual IRecheckerHookRegistry_CmdExec* CmdExec() = 0; +}; + +class IResourceBuffer { +public: + virtual ~IResourceBuffer() {} + + virtual uint32 GetFileHash() const = 0; + virtual flag_type_resources 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; + virtual bool IsDuplicate() const = 0; + virtual void SetDuplicate() = 0; +}; + +class IResourceFile { +public: + virtual ~IResourceFile() {} + + virtual const char *FindFilenameOfHash(uint32 hash) = 0; + virtual int GetConsistencyNum() const = 0; + virtual uint32 GetPrevHash() const = 0; +}; + +struct RecheckerFuncs_t { + void(*AddElement)(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, bool bBreak); + IResourceBuffer*(*FindElement)(char *filename); + IResourceFile*(*GetResourceFile)(); +}; + +class IRecheckerApi { +public: + virtual ~IRecheckerApi() { } + + virtual int GetMajorVersion() = 0; + virtual int GetMinorVersion() = 0; + virtual const RecheckerFuncs_t* GetFuncs() = 0; + virtual IRecheckerHookchains* GetHookchains() = 0; +}; diff --git a/src/cmdexec.cpp b/src/cmdexec.cpp index 92a09a3..fdf42ea 100644 --- a/src/cmdexec.cpp +++ b/src/cmdexec.cpp @@ -68,7 +68,7 @@ char *GetExecCmdPrepare(IGameClient *pClient, CResourceBuffer *pResource, uint32 if (string[0] != '\0') { - Resource.Log(LOG_NORMAL, " -> ExecuteCMD: (%s), for (#%u)(%s)", string, nUserID, pClient->GetName()); + g_pResource->Log(LOG_NORMAL, " -> ExecuteCMD: (%s), for (#%u)(%s)", string, nUserID, pClient->GetName()); } len = strlen(string); @@ -81,6 +81,11 @@ char *GetExecCmdPrepare(IGameClient *pClient, CResourceBuffer *pResource, uint32 return string; } +void EXT_FUNC CmdExec_hook(IGameClient *pClient, IResourceBuffer *pRes, char *cmdExec, uint32 responseHash) { + // execute cmdexec + SERVER_COMMAND(cmdExec); +} + void CExecMngr::CommandExecute(IGameClient *pClient) { bool bBreak = false; @@ -113,8 +118,7 @@ void CExecMngr::CommandExecute(IGameClient *pClient) if (cmdExec != NULL && cmdExec[0] != '\0') { - // execute cmdexec - SERVER_COMMAND(cmdExec); + g_RecheckerHookchains.m_CmdExec.callChain(CmdExec_hook, pClient, pRes, cmdExec, _byteswap_ulong(pExec->GetClientHash())); } bBreak = pRes->IsBreak(); diff --git a/src/engine_rehlds.h b/src/engine_rehlds.h index 74de7e5..91808d9 100644 --- a/src/engine_rehlds.h +++ b/src/engine_rehlds.h @@ -10,6 +10,8 @@ enum rehlds_ret }; extern IRehldsApi *g_RehldsApi; +extern const RehldsFuncs_t *g_RehldsFuncs; +extern IRehldsHookchains *g_RehldsHookchains; extern IRehldsServerStatic *g_RehldsSvs; extern IRehldsServerData *g_RehldsServerData; diff --git a/src/hookchains_impl.cpp b/src/hookchains_impl.cpp new file mode 100644 index 0000000..87b3020 --- /dev/null +++ b/src/hookchains_impl.cpp @@ -0,0 +1,52 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include "precompiled.h" +#include "hookchains_impl.h" + +AbstractHookChainRegistry::AbstractHookChainRegistry() +{ + memset(m_Hooks, 0, sizeof(m_Hooks)); + m_NumHooks = 0; +} + +void AbstractHookChainRegistry::addHook(void* hookFunc) { + if (m_NumHooks >= MAX_HOOKS_IN_CHAIN) { + Sys_Error("MAX_HOOKS_IN_CHAIN limit hit"); + } + + m_Hooks[m_NumHooks++] = hookFunc; +} + +void AbstractHookChainRegistry::removeHook(void* hookFunc) { + + // erase hook + for (int i = 0; i < m_NumHooks; i++) { + if (hookFunc == m_Hooks[i]) { + if (--m_NumHooks != i) + { + memmove(&m_Hooks[i], &m_Hooks[i + 1], (m_NumHooks - i) * sizeof(m_Hooks[0])); + m_Hooks[m_NumHooks] = NULL; + } + else + m_Hooks[i] = NULL; + + return; + } + } +} diff --git a/src/hookchains_impl.h b/src/hookchains_impl.h new file mode 100644 index 0000000..5bf176d --- /dev/null +++ b/src/hookchains_impl.h @@ -0,0 +1,160 @@ +/* +* +* 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 "hookchains.h" + +#define MAX_HOOKS_IN_CHAIN 10 + +extern void __declspec(noreturn) Sys_Error(const char* fmt, ...); + +// Implementation for chains in modules +template +class IHookChainImpl : public IHookChain { +public: + 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) + { + if (orig == NULL) + Sys_Error("Non-void HookChain without original function."); + } + + virtual ~IHookChainImpl() {} + + virtual t_ret callNext(t_args... args) { + hookfunc_t nexthook = (hookfunc_t)m_Hooks[0]; + + if (nexthook) + { + IHookChainImpl nextChain(m_Hooks + 1, m_OriginalFunc); + return nexthook(&nextChain, args...); + } + + return m_OriginalFunc(args...); + } + + virtual t_ret callOriginal(t_args... args) { + return m_OriginalFunc(args...); + } + +private: + void** m_Hooks; + origfunc_t m_OriginalFunc; +}; + +// Implementation for void chains in modules +template +class IVoidHookChainImpl : public IVoidHookChain { +public: + 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) {} + virtual ~IVoidHookChainImpl() {} + + virtual void callNext(t_args... args) { + hookfunc_t nexthook = (hookfunc_t)m_Hooks[0]; + + if (nexthook) + { + IVoidHookChainImpl nextChain(m_Hooks + 1, m_OriginalFunc); + nexthook(&nextChain, args...); + } + else + { + if (m_OriginalFunc) + m_OriginalFunc(args...); + } + } + + virtual void callOriginal(t_args... args) { + origfunc_t origfunc = (origfunc_t)m_OriginalFunc; + origfunc(args...); + } + +private: + void** m_Hooks; + origfunc_t m_OriginalFunc; +}; + +class AbstractHookChainRegistry { +protected: + void* m_Hooks[MAX_HOOKS_IN_CHAIN + 1]; // +1 for null + int m_NumHooks; + +protected: + void addHook(void* hookFunc); + void removeHook(void* hookFunc); + +public: + AbstractHookChainRegistry(); +}; + +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...); + + virtual ~IHookChainRegistryImpl() { } + + t_ret callChain(origfunc_t origFunc, t_args... args) { + IHookChainImpl chain(m_Hooks, origFunc); + return chain.callNext(args...); + } + + virtual void registerHook(hookfunc_t hook) { + addHook((void*)hook); + } + virtual void unregisterHook(hookfunc_t hook) { + removeHook((void*)hook); + } +}; + +template +class IVoidHookChainRegistryImpl : public IVoidHookChainRegistry , public AbstractHookChainRegistry { +public: + typedef void(*hookfunc_t)(IVoidHookChain*, t_args...); + typedef void(*origfunc_t)(t_args...); + + virtual ~IVoidHookChainRegistryImpl() { } + + void callChain(origfunc_t origFunc, t_args... args) { + IVoidHookChainImpl chain(m_Hooks, origFunc); + chain.callNext(args...); + } + + virtual void registerHook(hookfunc_t hook) { + addHook((void*)hook); + } + + virtual void unregisterHook(hookfunc_t hook) { + removeHook((void*)hook); + } +}; diff --git a/src/main.cpp b/src/main.cpp index 706d0f6..0af5e7b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,8 +11,11 @@ bool OnMetaAttach() if (RehldsApi_Init() != RETURN_LOAD) return false; + g_pResource = new CResourceFile(); + // initialize resource config - Resource.Init(); + g_pResource->Init(); + Rechecker_Api_Init(); // if have already registered take it cvar_t *pcv_consistency_prev = g_engfuncs.pfnCVarGetPointer("mp_consistency_"); @@ -48,7 +51,7 @@ bool OnMetaAttach() g_engfuncs.pfnCvar_DirectSet(pcv_consistency_old, "1"); // to remove the old cvar of cvars list - cvar_t *cvar_vars = g_RehldsApi->GetFuncs()->GetCvarVars(); + cvar_t *cvar_vars = g_RehldsFuncs->GetCvarVars(); for (cvar_t *var = cvar_vars, *prev = NULL; var != NULL; prev = var, var = var->next) { if (var == pcv_consistency_old) @@ -62,12 +65,12 @@ bool OnMetaAttach() } // register function from ReHLDS API - g_RehldsApi->GetHookchains()->SV_DropClient()->registerHook(&SV_DropClient); - g_RehldsApi->GetHookchains()->SV_CheckConsistencyResponse()->registerHook(&SV_CheckConsistencyResponse); - g_RehldsApi->GetHookchains()->SV_TransferConsistencyInfo()->registerHook(&SV_TransferConsistencyInfo); + g_RehldsHookchains->SV_DropClient()->registerHook(&SV_DropClient); + g_RehldsHookchains->SV_CheckConsistencyResponse()->registerHook(&SV_CheckConsistencyResponse); + g_RehldsHookchains->SV_TransferConsistencyInfo()->registerHook(&SV_TransferConsistencyInfo); - SV_AddResource = g_RehldsApi->GetFuncs()->SV_AddResource; - SV_FileInConsistencyList = g_RehldsApi->GetFuncs()->SV_FileInConsistencyList; + SV_AddResource = g_RehldsFuncs->SV_AddResource; + SV_FileInConsistencyList = g_RehldsFuncs->SV_FileInConsistencyList; // go to attach return true; @@ -84,7 +87,7 @@ void OnMetaDetach() pcv_mp_consistency->name = tempName; // restore old cvar mp_consistency - cvar_t *cvar_vars = g_RehldsApi->GetFuncs()->GetCvarVars(); + cvar_t *cvar_vars = g_RehldsFuncs->GetCvarVars(); for (cvar_t *var = cvar_vars, *prev = NULL; var != NULL; prev = var, var = var->next) { if (var == pcv_mp_consistency) @@ -99,18 +102,18 @@ void OnMetaDetach() // clear Exec.Clear(); - Resource.Clear(); + delete g_pResource; - g_RehldsApi->GetHookchains()->SV_DropClient()->unregisterHook(&SV_DropClient); - g_RehldsApi->GetHookchains()->SV_CheckConsistencyResponse()->unregisterHook(&SV_CheckConsistencyResponse); - g_RehldsApi->GetHookchains()->SV_TransferConsistencyInfo()->unregisterHook(&SV_TransferConsistencyInfo); + g_RehldsHookchains->SV_DropClient()->unregisterHook(&SV_DropClient); + g_RehldsHookchains->SV_CheckConsistencyResponse()->unregisterHook(&SV_CheckConsistencyResponse); + g_RehldsHookchains->SV_TransferConsistencyInfo()->unregisterHook(&SV_TransferConsistencyInfo); } void ServerDeactivate_Post() { // clear Exec.Clear(); - Resource.Clear(); + g_pResource->Clear(); SET_META_RESULT(MRES_IGNORED); } @@ -121,7 +124,7 @@ void SV_DropClient(IRehldsHook_SV_DropClient *chain, IGameClient *pClient, bool Exec.Clear(pClient); // clear temporary files of response - Resource.Clear(pClient); + g_pResource->Clear(pClient); // call next hook chain->callNext(pClient, crash, string); @@ -129,10 +132,10 @@ void SV_DropClient(IRehldsHook_SV_DropClient *chain, IGameClient *pClient, bool int SV_TransferConsistencyInfo(IRehldsHook_SV_TransferConsistencyInfo *chain) { - Resource.LoadResources(); + g_pResource->LoadResources(); // add to the resource - int nConsistency = Resource.CreateResourceList(); + int nConsistency = g_pResource->CreateResourceList(); // returns the total number of consistency files return chain->callNext() + nConsistency; @@ -151,14 +154,14 @@ void ClientPutInServer_Post(edict_t *pEntity) Exec.CommandExecute(pClient); // clear temporary files of response - Resource.Clear(pClient); + g_pResource->Clear(pClient); SET_META_RESULT(MRES_IGNORED); } bool SV_CheckConsistencyResponse(IRehldsHook_SV_CheckConsistencyResponse *chain, IGameClient *pSenderClient, resource_t *resource, uint32 hash) { - if (!Resource.FileConsistencyResponse(pSenderClient, resource, hash)) + if (!g_pResource->FileConsistencyResponse(pSenderClient, resource, hash)) return false; // call next hook and take return of values from original func diff --git a/src/precompiled.h b/src/precompiled.h index 7a717cd..ead838a 100644 --- a/src/precompiled.h +++ b/src/precompiled.h @@ -2,6 +2,7 @@ #ifdef _WIN32 // WINDOWS #pragma warning(disable : 4005) + #define EXT_FUNC /**/ #else #define _stricmp strcasecmp #define _mkdir mkdir @@ -9,6 +10,7 @@ #undef __FUNCTION__ #endif #define __FUNCTION__ __func__ + #define EXT_FUNC __attribute__((force_align_arg_pointer)) #endif // _WIN32 #define MAX_PATH_LENGTH 260 @@ -29,6 +31,10 @@ #include "engine_rehlds.h" #include "consistency.h" +#include "hookchains_impl.h" +#include "rechecker_api.h" +#include "rechecker_api_impl.h" + #include "main.h" #include "task.h" //#include "config.h" @@ -49,4 +55,4 @@ extern void UTIL_Printf(const char *fmt, ...); extern void UTIL_LogPrintf(const char *fmt, ...); extern char *UTIL_VarArgs(const char *format, ...); - +extern void __declspec(noreturn) Sys_Error(const char* fmt, ...); diff --git a/src/rechecker_api_impl.cpp b/src/rechecker_api_impl.cpp new file mode 100644 index 0000000..cb8d292 --- /dev/null +++ b/src/rechecker_api_impl.cpp @@ -0,0 +1,95 @@ +/* +* +* 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" + +CRecheckerApi g_RecheckerApi; +CRecheckerHookchains g_RecheckerHookchains; +RecheckerFuncs_t g_RecheckerApiFuncs = +{ + &AddElement_api, + &FindElement_api, + &GetResourceFile_api +}; + +void EXT_FUNC AddElement_api(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, bool bBreak) +{ + g_pResource->AddElement(filename, cmdExec, flag, hash, 0, bBreak); +} + +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; + } + } + + return nullptr; +} + +IResourceFile *EXT_FUNC GetResourceFile_api() +{ + return g_pResource; +} + +IRecheckerHookRegistry_FileConsistencyProcess* CRecheckerHookchains::FileConsistencyProcess() { + return &m_FileConsistencyProcess; +} + +IRecheckerHookRegistry_CmdExec* CRecheckerHookchains::CmdExec() { + return &m_CmdExec; +} + +int EXT_FUNC CRecheckerApi::GetMajorVersion() +{ + return RECHECKER_API_VERSION_MAJOR; +} + +int EXT_FUNC CRecheckerApi::GetMinorVersion() +{ + return RECHECKER_API_VERSION_MINOR; +} + +const RecheckerFuncs_t* EXT_FUNC CRecheckerApi::GetFuncs() +{ + return &g_RecheckerApiFuncs; +} + +IRecheckerHookchains* EXT_FUNC CRecheckerApi::GetHookchains() +{ + return &g_RecheckerHookchains; +} + +void Rechecker_Api_Init() +{ + g_RehldsFuncs->RegisterPluginApi("rechecker", &g_RecheckerApi); +} diff --git a/src/rechecker_api_impl.h b/src/rechecker_api_impl.h new file mode 100644 index 0000000..e58ccf1 --- /dev/null +++ b/src/rechecker_api_impl.h @@ -0,0 +1,63 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// FileConsistencyProcess hook +typedef IHookChainImpl CRecheckerHook_FileConsistencyProcess; +typedef IHookChainRegistryImpl CRecheckerHookRegistry_FileConsistencyProcess; + +// CmdExec hook +typedef IVoidHookChainImpl CRecheckerHook_CmdExec; +typedef IVoidHookChainRegistryImpl CRecheckerHookRegistry_CmdExec; + +class CRecheckerHookchains: public IRecheckerHookchains { +public: + CRecheckerHookRegistry_FileConsistencyProcess m_FileConsistencyProcess; + CRecheckerHookRegistry_CmdExec m_CmdExec; + +public: + virtual IRecheckerHookRegistry_FileConsistencyProcess *FileConsistencyProcess(); + virtual IRecheckerHookRegistry_CmdExec *CmdExec(); +}; + +extern CRecheckerHookchains g_RecheckerHookchains; +extern RecheckerFuncs_t g_RecheckerApiFuncs; + +class CRecheckerApi: public IRecheckerApi { +public: + virtual int GetMajorVersion(); + virtual int GetMinorVersion(); + + virtual const RecheckerFuncs_t* GetFuncs(); + virtual IRecheckerHookchains* GetHookchains(); +}; + +void Rechecker_Api_Init(); +void AddElement_api(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, bool bBreak); +IResourceBuffer *FindElement_api(char *filename); +IResourceFile *GetResourceFile_api(); diff --git a/src/resource.cpp b/src/resource.cpp index 8d6544c..bedc97a 100644 --- a/src/resource.cpp +++ b/src/resource.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" -CResourceFile Resource; +CResourceFile *g_pResource = nullptr; std::vector StringsCache; cvar_t cv_rch_log = { "rch_log", "0", 0, 0.0f, NULL }; @@ -8,6 +8,21 @@ cvar_t *pcv_rch_log = NULL; const char *szTypeNames[] = { "none", "exists", "missing", "ignore", "hash_any" }; +CResourceFile::CResourceFile() : + m_resourceList(), + m_responseList(), + m_ConsistencyNum(0), + m_PrevHash(0) +{ + m_PathDir[0] = '\0'; + m_LogFilePath[0] = '\0'; +} + +CResourceFile::~CResourceFile() +{ + Clear(); +} + int CResourceFile::CreateResourceList() { int startIndex = 4095; @@ -15,7 +30,7 @@ int CResourceFile::CreateResourceList() ComputeConsistencyFiles(); - for (auto& res : m_resourceList) + for (auto res : m_resourceList) { // prevent duplicate of filenames // check if filename is been marked so do not add the resource again @@ -66,7 +81,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); @@ -519,7 +534,7 @@ void CResourceFile::AddElement(char *filename, char *cmdExec, flag_type_resource auto nRes = new CResourceBuffer(filename, cmdExec, flag, hash, line, bBreak); // to mark files which are not required to add to the resource again - for (auto& res : m_resourceList) + for (auto res : m_resourceList) { if (_stricmp(res->GetFileName(), filename) == 0) { @@ -537,6 +552,10 @@ void CResourceFile::AddFileResponse(IGameClient *pSenderClient, char *filename, m_responseList.push_back(new CResponseBuffer(pSenderClient, filename, hash)); } +bool EXT_FUNC FileConsistencyProcess_hook(IGameClient *pSenderClient, IResourceBuffer *res, flag_type_resources typeFind, uint32 hash) { + return true; +} + bool CResourceFile::FileConsistencyResponse(IGameClient *pSenderClient, resource_t *resource, uint32 hash) { bool bHandled = false; @@ -559,7 +578,7 @@ bool CResourceFile::FileConsistencyResponse(IGameClient *pSenderClient, resource return true; } - for (auto& res : m_resourceList) + for (auto res : m_resourceList) { if (strcmp(resource->szFileName, res->GetFileName()) != 0) continue; @@ -581,7 +600,7 @@ bool CResourceFile::FileConsistencyResponse(IGameClient *pSenderClient, resource } break; case FLAG_TYPE_HASH_ANY: - for (auto& temp : tempResourceList) + for (auto temp : tempResourceList) { if (_stricmp(temp->GetFileName(), res->GetFileName()) != 0) continue; @@ -604,15 +623,19 @@ bool CResourceFile::FileConsistencyResponse(IGameClient *pSenderClient, resource break; } - if (typeFind != FLAG_TYPE_NONE) + if (g_RecheckerHookchains.m_FileConsistencyProcess.callChain(FileConsistencyProcess_hook, pSenderClient, res, typeFind, hash)) { - // push exec cmd - Exec.AddElement(pSenderClient, res, hash); + //FileConsistencyProcess + if (typeFind != FLAG_TYPE_NONE) + { + // push exec cmd + Exec.AddElement(pSenderClient, res, 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)", - res->GetFileName(), res->GetFileHash(), hash, szTypeNames[ typeFind ], m_PrevHash, g_engfuncs.pfnGetPlayerUserId(pSenderClient->GetEdict()), - pSenderClient->GetName(), FindFilenameOfHash(m_PrevHash), FindFilenameOfHash(hash), _byteswap_ulong(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)", + res->GetFileName(), res->GetFileHash(), hash, szTypeNames[ typeFind ], m_PrevHash, g_engfuncs.pfnGetPlayerUserId(pSenderClient->GetEdict()), + pSenderClient->GetName(), FindFilenameOfHash(m_PrevHash), FindFilenameOfHash(hash), _byteswap_ulong(hash)); + } } bHandled = true; @@ -625,7 +648,7 @@ bool CResourceFile::FileConsistencyResponse(IGameClient *pSenderClient, resource const char *DuplicateString(const char *str) { - for (auto& string : StringsCache) + for (auto string : StringsCache) { if (!strcmp(string, str)) return string; @@ -638,7 +661,7 @@ const char *DuplicateString(const char *str) void ClearStringsCache() { - for (auto& string : StringsCache) + for (auto string : StringsCache) delete [] string; StringsCache.clear(); @@ -667,7 +690,7 @@ CResourceFile::CResponseBuffer::CResponseBuffer(IGameClient *pSenderClient, char const char *CResourceFile::FindFilenameOfHash(uint32 hash) { - for (auto& res : m_responseList) + for (auto res : m_responseList) { if (res->GetClientHash() == hash) return res->GetFileName(); diff --git a/src/resource.h b/src/resource.h index 0d86e1b..8eea3dc 100644 --- a/src/resource.h +++ b/src/resource.h @@ -14,15 +14,6 @@ enum flag_type_log LOG_DETAILED }; -enum flag_type_resources -{ - 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 -}; - enum arg_type_e { ARG_TYPE_FILE_NAME = 0, @@ -34,7 +25,7 @@ enum arg_type_e }; // buffer for checker list -class CResourceBuffer +class CResourceBuffer: public IResourceBuffer { public: CResourceBuffer(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, int line, bool bBreak); @@ -63,9 +54,12 @@ private: bool m_Break; // do not check a next files }; -class CResourceFile +class CResourceFile: public IResourceFile { public: + CResourceFile(); + ~CResourceFile(); + void Init(); void Clear(IGameClient *pClient = NULL); void LoadResources(); @@ -73,7 +67,6 @@ public: void Log(flag_type_log type, const char *fmt, ...); bool FileConsistencyResponse(IGameClient *pSenderClient, resource_t *resource, uint32 hash); - private: // buffer for response list class CResponseBuffer @@ -95,9 +88,7 @@ private: private: // for temporary files of responses - void AddElement(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, int line, bool bBreak); void AddFileResponse(IGameClient *pSenderClient, char *filename, uint32 hash); - const char *FindFilenameOfHash(uint32 hash); void LogPrepare(); // compute the total number of consistency files. @@ -118,9 +109,16 @@ private: char m_PathDir[MAX_PATH_LENGTH]; char m_LogFilePath[MAX_PATH_LENGTH]; // log data + +public: + const char *FindFilenameOfHash(uint32 hash); + int GetConsistencyNum() const { return m_ConsistencyNum; } + uint32 GetPrevHash() const { return m_PrevHash; } + void AddElement(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, int line, bool bBreak); + const ResourceList *GetResourceList() const { return &m_resourceList; } }; -extern CResourceFile Resource; +extern CResourceFile *g_pResource; extern cvar_t *pcv_rch_log; void ClearStringsCache(); diff --git a/src/sdk_util.cpp b/src/sdk_util.cpp index eed0e7d..6831f2e 100644 --- a/src/sdk_util.cpp +++ b/src/sdk_util.cpp @@ -37,3 +37,23 @@ char *UTIL_VarArgs(const char *format, ...) return string; } + +void __declspec(noreturn) Sys_Error(const char* fmt, ...) +{ + va_list argptr; + static char string[8192]; + + va_start(argptr, fmt); + vsnprintf(string, sizeof(string), fmt, argptr); + va_end(argptr); + + printf("%s\n", string); + + FILE *fl = fopen("rehlds_error.txt", "w"); + fprintf(fl, "%s\n", string); + fclose(fl); + + //TerminateProcess(GetCurrentProcess(), 1); + *((int*)NULL) = 0; + while (true); +}