diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..18f3f01 --- /dev/null +++ b/Makefile @@ -0,0 +1,48 @@ +NAME = rechecker +COMPILER = /opt/intel/bin/icpc + +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 public/interface.cpp + +LINK = -lm -ldl -static-intel -static-libgcc -no-intel-extensions + +OPT_FLAGS = -O3 -msse3 -ipo -no-prec-div -fp-model fast=2 -funroll-loops -fomit-frame-pointer -fno-stack-protector + +INCLUDE = -I. -Isrc -Icommon -Idlls -Iengine -Ipm_shared -Ipublic -Imetamod + +BIN_DIR = Release +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 + +OBJ_LINUX := $(OBJECTS:%.c=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.c + $(COMPILER) $(INCLUDE) $(CFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR) + mkdir -p $(BIN_DIR)/sdk + + $(MAKE) $(NAME) && strip -x $(BIN_DIR)/$(NAME)_mm_i386.so + +$(NAME): $(OBJ_LINUX) + $(COMPILER) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -o$(BIN_DIR)/$(NAME)_mm_i386.so + +check: + cppcheck $(INCLUDE) --quiet --max-configs=100 -D__linux__ -DNDEBUG -DHAVE_STDINT_H . + +debug: + $(MAKE) all DEBUG=false + +default: all + +clean: + rm -rf Release/sdk/*.o + rm -rf Release/*.o + rm -rf Release/$(NAME)_mm_i386.so + + diff --git a/engine/rehlds_api.h b/engine/rehlds_api.h index bb25873..995feff 100644 --- a/engine/rehlds_api.h +++ b/engine/rehlds_api.h @@ -145,6 +145,10 @@ typedef IVoidHookChainRegistry IRehldsHook_SV_CheckConsistencyResponce; typedef IHookChainRegistry IRehldsHookRegistry_SV_CheckConsistencyResponce; +//SV_DropClient hook +typedef IVoidHookChain IRehldsHook_SV_DropClient; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_DropClient; + class IRehldsHookchains { public: virtual ~IRehldsHookchains() { } @@ -176,6 +180,7 @@ public: virtual IRehldsHookRegistry_PF_BuildSoundMsg_I* PF_BuildSoundMsg_I() = 0; virtual IRehldsHookRegistry_SV_WriteFullClientUpdate* SV_WriteFullClientUpdate() = 0; virtual IRehldsHookRegistry_SV_CheckConsistencyResponce* SV_CheckConsistencyResponce() = 0; + virtual IRehldsHookRegistry_SV_DropClient* SV_DropClient() = 0; }; struct RehldsFuncs_t { diff --git a/msvc/rechecker.vcxproj b/msvc/rechecker.vcxproj index 81e17be..0a7664b 100644 --- a/msvc/rechecker.vcxproj +++ b/msvc/rechecker.vcxproj @@ -164,7 +164,7 @@ - + @@ -175,9 +175,11 @@ - + - + + true + diff --git a/msvc/rechecker.vcxproj.filters b/msvc/rechecker.vcxproj.filters index 5514b97..98f9da1 100644 --- a/msvc/rechecker.vcxproj.filters +++ b/msvc/rechecker.vcxproj.filters @@ -460,8 +460,8 @@ - + @@ -478,8 +478,8 @@ - + diff --git a/src/cmdexec.cpp b/src/cmdexec.cpp index cc05f2e..707c055 100644 --- a/src/cmdexec.cpp +++ b/src/cmdexec.cpp @@ -1,21 +1,22 @@ #include "precompiled.h" -CBufExec CmdExec; +CExecManager Exec; -CBufExecNew::CBufExecNew(IGameClient *pClient, CResourceCheckerNew *pResource) +CBufExec::CBufExec(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash) { m_pClient = pClient; m_pResource = pResource; + m_Hash = responseHash; } -CBufExecNew::~CBufExecNew() +CBufExec::~CBufExec() { ; } -void CBufExec::AddElement(IGameClient *pClient, CResourceCheckerNew *pResource) +void CExecManager::AddElement(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash) { - m_vector.push_back(new CBufExecNew(pClient, pResource)); + m_execList.push_back(new CBufExec(pClient, pResource, responseHash)); } void StringReplace(char *src, const char *strold, const char *strnew) @@ -37,7 +38,7 @@ void StringReplace(char *src, const char *strold, const char *strnew) } } -char *GetExecCmdPrepare(IGameClient *pClient, CResourceCheckerNew *pResource) +char *GetExecCmdPrepare(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash) { int len; const netadr_t *net; @@ -48,15 +49,15 @@ char *GetExecCmdPrepare(IGameClient *pClient, CResourceCheckerNew *pResource) net = pClient->GetNetChan()->GetRemoteAdr(); + // replace key values + StringReplace(string, "[file_name]", pResource->GetFileName()); + StringReplace(string, "[file_hash]", UTIL_VarArgs("%x", responseHash)); + // replace of templates for identification - StringReplace(string, "[name]", pClient->GetName()); StringReplace(string, "[userid]", UTIL_VarArgs("#%u", g_engfuncs.pfnGetPlayerUserId(pClient->GetEdict()))); StringReplace(string, "[steamid]", UTIL_VarArgs("%s", g_engfuncs.pfnGetPlayerAuthId(pClient->GetEdict()))); StringReplace(string, "[ip]", UTIL_VarArgs("%i.%i.%i.%i", net->ip[0], net->ip[1], net->ip[2], net->ip[3])); - - // replace key values - StringReplace(string, "[file_name]", pResource->GetFileName()); - StringReplace(string, "[file_hash]", UTIL_VarArgs("%x", pResource->GetHashFile())); + StringReplace(string, "[name]", pClient->GetName()); len = strlen(string); @@ -69,42 +70,71 @@ char *GetExecCmdPrepare(IGameClient *pClient, CResourceCheckerNew *pResource) return string; } -void CBufExec::Exec(IGameClient *pClient) +void CExecManager::CommandExecute(IGameClient *pClient) { - CBufExecVectorIt it = m_vector.begin(); - - while (it != m_vector.end()) + bool bBreak = false; + auto iter = m_execList.begin(); + + while (iter != m_execList.end()) { - CBufExecNew *exc = (*it); + CBufExec *pExec = (*iter); - if (exc->GetGameClient() != pClient) { - it++; + if (pExec->GetGameClient() != pClient) { + iter++; continue; } + CResourceBuffer *pRes = pExec->GetResource(); + // exit the loop if the client is out of the game // TODO: Check me! - if (!pClient->IsConnected()) { break; } - char *cmdExec = GetExecCmdPrepare(pClient, exc->GetResource()); + char *cmdExec = GetExecCmdPrepare(pClient, pRes, pExec->GetHash()); + + // erase all cmdexec because have flag is break + if (bBreak) { + // erase cmd exec + delete pExec; + iter = m_execList.erase(iter); + continue; + } if (cmdExec != NULL && cmdExec[0] != '\0') { - // execute cmd + // execute cmdexec SERVER_COMMAND(cmdExec); - // erase cmd exec - delete exc; - it = m_vector.erase(it); + // erase cmdexec + delete pExec; + iter = m_execList.erase(iter); } else - it++; + iter++; + + bBreak = (pRes->GetFlagsFile() & FLAG_TYPE_BREAK) == FLAG_TYPE_BREAK; } } -void CBufExec::Clear() +void CExecManager::Clear(IGameClient *pClient) { - m_vector.clear(); + if (pClient == NULL) { + m_execList.clear(); + return; + } + + auto iter = m_execList.begin(); + while (iter != m_execList.end()) + { + CBufExec *pExec = (*iter); + + // erase cmdexec + if (pExec->GetGameClient() == pClient) { + delete pExec; + iter = m_execList.erase(iter); + } + else + iter++; + } } diff --git a/src/cmdexec.h b/src/cmdexec.h index 3475cc2..0f207d3 100644 --- a/src/cmdexec.h +++ b/src/cmdexec.h @@ -1,35 +1,33 @@ #pragma once -#include - -class CBufExecNew -{ -public: - CBufExecNew(IGameClient *pClient, CResourceCheckerNew *pResource); - ~CBufExecNew(); - - IGameClient *GetGameClient() { return m_pClient; }; - CResourceCheckerNew *GetResource() { return m_pResource; }; - -private: - IGameClient *m_pClient; - CResourceCheckerNew *m_pResource; -}; - -typedef std::vector CBufExecVector; -typedef CBufExecVector::iterator CBufExecVectorIt; - class CBufExec { public: - void AddElement(IGameClient *pClient, CResourceCheckerNew *pResource); + CBufExec(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash); + ~CBufExec(); - void Exec(IGameClient *pClient); - void Clear(); + IGameClient *GetGameClient() const { return m_pClient; }; + CResourceBuffer *GetResource() const { return m_pResource; }; + uint32 GetHash() const { return m_Hash; }; private: - CBufExecVector m_vector; + IGameClient *m_pClient; + CResourceBuffer *m_pResource; + uint32 m_Hash; }; -extern CBufExec CmdExec; +class CExecManager +{ +public: + void AddElement(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash); + void CommandExecute(IGameClient *pClient); + void Clear(IGameClient *pClient = NULL); + +private: + typedef std::vector CBufExecList; + CBufExecList m_execList; +}; + +extern CExecManager Exec; extern void StringReplace(char *src, const char *strold, const char *strnew); + diff --git a/src/config.h b/src/config.h deleted file mode 100644 index f1b3bdf..0000000 --- a/src/config.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include - -#define FILE_INI_CONFIG "config.ini" -#define FILE_INI_RESOURCES "resources.ini" - -//#ifdef MAX_PATH -//#define MAX_PATH 260 -//#endif // MAX_PATH - -#define MAX_CLIENTS 32 -#define MAX_CMD_LENGTH 128 -#define MAX_PATH_LENGTH 260 - -enum find_type_e -{ - FIND_TYPE_NONE = 0, - FIND_TYPE_ON_HASH, - FIND_TYPE_ANY_HASH, - FIND_TYPE_MISSING -}; - -enum arg_type_e -{ - ARG_TYPE_FILE_NAME = 0, - ARG_TYPE_FILE_HASH, - ARG_TYPE_CMD_EXEC, - - MAX_PARSE_ARGUMENT, -}; - -enum flag_type_resources -{ - FLAG_TYPE_NONE = 0, - FLAG_TYPE_EXISTS, - FLAG_TYPE_MISSGIN, - FLAG_TYPE_HASH_ANY, -}; - -class CResourceCheckerNew -{ -public: - CResourceCheckerNew(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash); - ~CResourceCheckerNew(); - - uint32 GetHashFile() { return m_HashFile; }; - flag_type_resources GetFlagFile() { return m_Flag; }; - - char *GetFileName() { return m_FileName; }; - char *GetCmdExec() { return m_CmdExec; }; - bool GetMark() { return m_Mark; }; - void SetMark() { m_Mark = true; }; - -private: - uint32 m_HashFile; - flag_type_resources m_Flag; - - char *m_FileName; - char *m_CmdExec; - bool m_Mark; -}; - -typedef std::vector ResourceCheckerVector; -typedef ResourceCheckerVector::iterator ResourceCheckerVectorIt; - -class CConfig -{ -public: - void Init(); - void Load(); - - void AddResource(); - void ClearResources(); - - bool FileConsistencyResponce(IGameClient *pSenderClient, resource_t *resource, uint32 hash); - bool IsConfigLoaded() { return !m_ConfigFailed; }; - -private: - void ParseConfig(); - void ParseResources(); - void AddElement(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash); - - // parse - const char *GetNextToken(char **pbuf); - -private: - ResourceCheckerVector m_vector; - - uint32 m_PreHash; - bool m_ConfigFailed; - char m_szPathConfirDir[MAX_PATH_LENGTH]; - char m_szPathResourcesDir[MAX_PATH_LENGTH]; -}; - -extern CConfig Config; -extern void UTIL_Printf(char *fmt, ...); diff --git a/src/dllapi.cpp b/src/dllapi.cpp index 955dcda..470ce67 100644 --- a/src/dllapi.cpp +++ b/src/dllapi.cpp @@ -3,6 +3,7 @@ DLL_FUNCTIONS *g_pFunctionTable; extern qboolean ClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]); + extern void ServerDeactivate_Post(); extern void ServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax); extern void ClientPutInServer_Post(edict_t *pEntity); @@ -28,7 +29,7 @@ static DLL_FUNCTIONS gFunctionTable = NULL, // pfnResetGlobalState NULL, // pfnClientConnect - NULL, // pfnClientDisconnect + NULL, // pfnClientDisconnect NULL, // pfnClientKill NULL, // pfnClientPutInServer NULL, // pfnClientCommand diff --git a/src/main.cpp b/src/main.cpp index 082ca74..8f57013 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,12 @@ #include "precompiled.h" bool g_bInitialized = false; + +void SV_DropClient(IRehldsHook_SV_DropClient *chain, IGameClient *pClient, bool crash, const char *string); bool SV_CheckConsistencyResponce(IRehldsHook_SV_CheckConsistencyResponce *chain, IGameClient *pSenderClient, resource_t *resource, uint32 hash); void (*SV_AddResource)(resourcetype_t type, const char *name, int size, unsigned char flags, int index); -bool OnMetaAttach(void) +bool OnMetaAttach() { if (RehldsApi_Init() != RETURN_LOAD) { return false; @@ -12,30 +14,49 @@ bool OnMetaAttach(void) // register function from ReHLDS API g_RehldsApi->GetHookchains()->SV_CheckConsistencyResponce()->registerHook(&SV_CheckConsistencyResponce); + g_RehldsApi->GetHookchains()->SV_DropClient()->registerHook(&SV_DropClient); + SV_AddResource = reinterpret_cast(g_RehldsApi->GetFuncs()->SV_AddResource); - // initialize config - Config.Init(); + // initialize resource config + Resource.Init(); + + // set force cvar on own value and replacement of original + // NOTE: in gamedll used this cvar not through a pointer thus we create own cvar for gamedll with default values + // so for engine set it the cvar values is 1. + + cvar_t *mp_consistency_old = g_engfuncs.pfnCVarGetPointer("mp_consistency"); + cvar_t mp_consistency = { + mp_consistency_old->name, + mp_consistency_old->string, + mp_consistency_old->flags, + mp_consistency_old->value, + NULL + }; + + mp_consistency_old->name = "mp_consistency_orig"; + g_engfuncs.pfnCVarRegister(&mp_consistency); + g_engfuncs.pfnCvar_DirectSet(mp_consistency_old, "1"); // if is OK go to attach - return Config.IsConfigLoaded(); + return Resource.IsConfigLoaded(); } -void OnMetaDetach(void) +void OnMetaDetach() { g_RehldsApi->GetHookchains()->SV_CheckConsistencyResponce()->unregisterHook(&SV_CheckConsistencyResponce); // clear - CmdExec.Clear(); - Config.ClearResources(); + Exec.Clear(); + Resource.Clear(); } void ServerDeactivate_Post() { if (g_bInitialized) { // clear - CmdExec.Clear(); - Config.ClearResources(); + Exec.Clear(); + Resource.Clear(); g_bInitialized = false; } @@ -44,10 +65,22 @@ void ServerDeactivate_Post() void ServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax) { - Config.Load(); + Resource.Load(); SET_META_RESULT(MRES_IGNORED); } +void SV_DropClient(IRehldsHook_SV_DropClient *chain, IGameClient *pClient, bool crash, const char *string) +{ + if (pClient != NULL) { // TODO: sure? + + // clear buffer cmdexec the client when was disconnected up to perform cmdexec + Exec.Clear(pClient); + } + + // call next hook + chain->callNext(pClient, crash, string); +} + void ClientPutInServer_Post(edict_t *pEntity) { int nIndex = ENTINDEX(pEntity) - 1; @@ -60,7 +93,7 @@ void ClientPutInServer_Post(edict_t *pEntity) if (pClient != NULL) { // client is connected to putinserver, go execute cmd out buffer - CmdExec.Exec(pClient); + Exec.CommandExecute(pClient); } SET_META_RESULT(MRES_IGNORED); @@ -69,7 +102,7 @@ void ClientPutInServer_Post(edict_t *pEntity) qboolean ClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]) { if (!g_bInitialized) { - Config.AddResource(); + Resource.Add(); g_bInitialized = true; } @@ -80,9 +113,10 @@ qboolean ClientConnect_Post(edict_t *pEntity, const char *pszName, const char *p bool SV_CheckConsistencyResponce(IRehldsHook_SV_CheckConsistencyResponce *chain, IGameClient *pSenderClient, resource_t *resource, uint32 hash) { if (resource->type == t_decal) { - if (!Config.FileConsistencyResponce(pSenderClient, resource, hash)) + if (!Resource.FileConsistencyResponce(pSenderClient, resource, hash)) return false; } - return chain->callNext(pSenderClient, resource, hash);; + // call next hook and take return of values from original func + return chain->callNext(pSenderClient, resource, hash); } diff --git a/src/meta_api.cpp b/src/meta_api.cpp index 9e83b10..30a2a8f 100644 --- a/src/meta_api.cpp +++ b/src/meta_api.cpp @@ -3,8 +3,8 @@ plugin_info_t Plugin_info = { META_INTERFACE_VERSION, - "ReChecker", - "1.0", + "Rechecker", + "1.1", __DATE__, "s1lent", "http://www.dedicated-server.ru/", @@ -25,7 +25,7 @@ META_FUNCTIONS gMetaFunctionTable; extern bool OnMetaAttach(); extern void OnMetaDetach(); -C_DLLEXPORT int Meta_Query(char *,plugin_info_t **pPlugInfo,mutil_funcs_t *pMetaUtilFuncs) +C_DLLEXPORT int Meta_Query(char *, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) { *pPlugInfo = &(Plugin_info); gpMetaUtilFuncs = pMetaUtilFuncs; @@ -33,7 +33,7 @@ C_DLLEXPORT int Meta_Query(char *,plugin_info_t **pPlugInfo,mutil_funcs_t *pMeta return 1; } -C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now,META_FUNCTIONS *pFunctionTable,meta_globals_t *pMGlobals,gamedll_funcs_t *pGamedllFuncs) +C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) { gpMetaGlobals = pMGlobals; gpGamedllFuncs = pGamedllFuncs; diff --git a/src/precompiled.h b/src/precompiled.h index 4cf4b7d..8f710e8 100644 --- a/src/precompiled.h +++ b/src/precompiled.h @@ -2,8 +2,13 @@ #ifdef _WIN32 // WINDOWS #pragma warning(disable : 4005) +#else + #define _stricmp strcasecmp + // Deail with stupid macro in kernel.h + #undef __FUNCTION__ #endif // _WIN32 +#include #include // strrchr #include @@ -16,19 +21,21 @@ #include "engine_rehlds.h" #include "main.h" -#include "config.h" +#include "resource.h" #include "cmdexec.h" -#include "sdk_util.h" // UTIL_LogPrintf, etc +//#include "sdk_util.h" // UTIL_LogPrintf, etc -/* <7508> ../engine/consistency.h:9 */ -typedef struct consistency_s -{ - char * filename; - int issound; - int orig_index; - int value; - int check_type; - float mins[3]; - float maxs[3]; -} consistency_t; +#undef DLLEXPORT +#ifdef _WIN32 +#define DLLEXPORT __declspec(dllexport) +#define NOINLINE __declspec(noinline) +#else +#define DLLEXPORT __attribute__((visibility("default"))) +#define NOINLINE __attribute__((noinline)) +#define WINAPI /* */ +#endif // _WIN32 + +extern void UTIL_Printf(const char *fmt, ...); +extern void UTIL_LogPrintf(const char *fmt, ...); +extern char *UTIL_VarArgs(const char *format, ...); diff --git a/src/config.cpp b/src/resource.cpp similarity index 57% rename from src/config.cpp rename to src/resource.cpp index 0328f5c..f3aa46b 100644 --- a/src/config.cpp +++ b/src/resource.cpp @@ -1,40 +1,40 @@ #include "precompiled.h" -CConfig Config; +CResourceFile Resource; -void CConfig::AddResource() +void CResourceFile::Add() { - ResourceCheckerVectorIt it = m_vector.begin(); int nConsistency = g_RehldsServerData->GetConsistencyNum(); - while (it != m_vector.end()) + for (auto iter = m_resourceList.cbegin(); iter != m_resourceList.cend(); ++iter) { - CResourceCheckerNew *pRes = (*it); + CResourceBuffer *pRes = (*iter); // prevent duplicate of filenames // check if filename is been marked so do not add the resource again if (pRes->GetMark() != true) { -#ifdef _DEBUG - printf(__FUNCTION__ " :: (%s)(%s)\n", pRes->GetFileName(), pRes->GetCmdExec()); -#endif // _DEBUG +//#ifdef _DEBUG + if (CVAR_GET_FLOAT("developer") == 1.0f) { + UTIL_Printf(__FUNCTION__ " :: (%s)(%s)(%x)\n", pRes->GetFileName(), pRes->GetCmdExec(), pRes->GetHashFile()); + } +//#endif // _DEBUG SV_AddResource(t_decal, pRes->GetFileName(), 0, RES_CHECKFILE, 4095); nConsistency++; } - - it++; } + g_RehldsServerData->SetConsistencyNum(nConsistency); } -void CConfig::ClearResources() +void CResourceFile::Clear() { - m_PreHash = 0; + m_PrevHash = 0; // clear resources - m_vector.clear(); + m_resourceList.clear(); } -void CConfig::Init() +void CResourceFile::Init() { char *pos; char path[MAX_PATH_LENGTH]; @@ -49,32 +49,8 @@ void CConfig::Init() *(pos + 1) = '\0'; - // config.ini - snprintf(m_szPathConfirDir, sizeof(m_szPathConfirDir) - 1, "%s" FILE_INI_CONFIG, path); - // resources.ini - snprintf(m_szPathResourcesDir, sizeof(m_szPathResourcesDir) - 1, "%s" FILE_INI_RESOURCES, path); -} - -void CConfig::Load() -{ - //ParseConfig(); - ParseResources(); -} - -void CConfig::ParseConfig() -{ - FILE *fp = fopen(m_szPathResourcesDir, "r"); - - if (fp == NULL) - { - UTIL_Printf(__FUNCTION__ ": can't find path to " FILE_INI_CONFIG "\n"); - return; - } - - // soon coming.. - - fclose(fp); + snprintf(m_PathDir, sizeof(m_PathDir) - 1, "%s" FILE_INI_RESOURCES, path); } inline uint8 hexbyte(uint8 *hex) @@ -92,7 +68,7 @@ inline bool invalidchar(const char c) || c == '>' || c == '|') != 0; } -bool FileIsValidChar(char *psrc, char &pchar) { +bool IsValidFilename(char *psrc, char &pchar) { char *pch = strrchr(psrc, '/'); @@ -127,7 +103,7 @@ bool FileIsExtension(char *psrc) { return strchr(pch, '/') == NULL; } -void CConfig::ParseResources() +void CResourceFile::Load() { char *pos; char buffer[4096]; @@ -135,12 +111,12 @@ void CConfig::ParseResources() FILE *fp; int argc; int len; - flag_type_resources flag = FLAG_TYPE_NONE; + int flags; char filename[MAX_PATH_LENGTH]; char cmdBufExec[MAX_PATH_LENGTH]; int cline = 0; - fp = fopen(m_szPathResourcesDir, "r"); + fp = fopen(m_PathDir, "r"); if (fp == NULL) { @@ -154,16 +130,17 @@ void CConfig::ParseResources() pos = buffer; cline++; - + if (*pos == '\0' || *pos == ';' || *pos == '\\' || *pos == '/' || *pos == '#') continue; const char *pToken = GetNextToken(&pos); argc = 0; - hash[0] = '\0'; - flag = FLAG_TYPE_NONE; - + flags = FLAG_TYPE_NONE; + + memset(hash, 0, sizeof(hash)); + while (pToken != NULL && argc <= MAX_PARSE_ARGUMENT) { len = strlen(pToken); @@ -184,14 +161,14 @@ void CConfig::ParseResources() pbuf[len] = '\0'; if (_stricmp((const char *)pbuf, "UNKNOWN") == 0) { - flag = FLAG_TYPE_HASH_ANY; + flags = FLAG_TYPE_HASH_ANY; } else { for (int i = 0; i < sizeof(pbuf) / 2; i++) hash[i] = hexbyte(&pbuf[i * 2]); - flag = (*(uint32 *)&hash[0] != 0x00000000) ? FLAG_TYPE_EXISTS : FLAG_TYPE_MISSGIN; + flags = (*(uint32 *)&hash[0] != 0x00000000) ? FLAG_TYPE_EXISTS : FLAG_TYPE_MISSGIN; } break; @@ -201,8 +178,27 @@ void CConfig::ParseResources() strncpy(cmdBufExec, pToken, len + 1); cmdBufExec[len + 1] = '\0'; - // replface \' to " - StringReplace(cmdBufExec, "'", "\""); + if (_stricmp(cmdBufExec, "IGNORE") == 0) { + flags = FLAG_TYPE_IGNORE; + cmdBufExec[0] = '\0'; + } + else if (_stricmp(cmdBufExec, "BREAK") == 0) { + flags |= FLAG_TYPE_BREAK; + cmdBufExec[0] = '\0'; + } + else { + // replface \' to " + StringReplace(cmdBufExec, "'", "\""); + } + } + case ARG_TYPE_FLAG: + { + if (_stricmp(pToken, "IGNORE") == 0) { + flags = FLAG_TYPE_IGNORE; + } + else if (_stricmp(pToken, "BREAK") == 0) { + flags |= FLAG_TYPE_BREAK; + } break; } default: @@ -211,6 +207,11 @@ void CConfig::ParseResources() argc++; pToken = GetNextToken(&pos); + + if (pToken == NULL && argc == ARG_TYPE_FLAG) { + // go to next argument + argc++; + } } if (argc >= MAX_PARSE_ARGUMENT) { @@ -226,29 +227,33 @@ void CConfig::ParseResources() continue; } - else if (!FileIsValidChar(filename, pchar)) { + else if (!IsValidFilename(filename, pchar)) { UTIL_Printf(__FUNCTION__ ": Failed to load \"" FILE_INI_RESOURCES "\"; filename has invalid character '%c' on line %d\n", pchar, cline); continue; } - else if (flag == FLAG_TYPE_NONE) { + else if (flags == FLAG_TYPE_NONE) { UTIL_Printf(__FUNCTION__ ": Failed to load \"" FILE_INI_RESOURCES "\"; parsing hash failed on line %d\n", cline); continue; } - else if (strlen(cmdBufExec) <= 0) { - UTIL_Printf(__FUNCTION__ ": Failed to load \"" FILE_INI_RESOURCES "\"; command line is empty on line %d\n", cline); + // TODO: is there a need to flag FLAG_TYPE_BREAK without cmdexec? + else if (strlen(cmdBufExec) <= 0 && !(flags & (FLAG_TYPE_IGNORE | FLAG_TYPE_BREAK))) { + UTIL_Printf(__FUNCTION__ ": Failed to load \"" FILE_INI_RESOURCES "\"; parsing command line is empty on line %d\n", cline); continue; } - AddElement(filename, cmdBufExec, flag, *(uint32 *)&hash[0]); + AddElement(filename, cmdBufExec, flags, *(uint32 *)&hash[0]); + } + else if (pToken != NULL || argc > ARG_TYPE_FILE_NAME) { + UTIL_Printf(__FUNCTION__ ": Failed to load \"" FILE_INI_RESOURCES "\"; parsing not enough arguments on line %d (got '%d', expected '%d')\n", cline, argc, MAX_PARSE_ARGUMENT); } } fclose(fp); } -const char *CConfig::GetNextToken(char **pbuf) +const char *CResourceFile::GetNextToken(char **pbuf) { char *rpos = *pbuf; if (*rpos == '\0') @@ -340,17 +345,17 @@ void TrimSpace(char *pbuf) *pend = '\0'; } -void CConfig::AddElement(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash) +void CResourceFile::AddElement(char *filename, char *cmdExec, int flags, uint32 hash) { - m_vector.push_back(new CResourceCheckerNew(filename, cmdExec, flag, hash)); + m_resourceList.push_back(new CResourceBuffer(filename, cmdExec, flags, hash)); // to mark files which are not required to add to the resource again - for (ResourceCheckerVectorIt it = m_vector.begin(); it != m_vector.end(); ++it) + for (auto iter = m_resourceList.cbegin(); iter != m_resourceList.cend(); ++iter) { - CResourceCheckerNew *pRes = (*it); + CResourceBuffer *pRes = (*iter); // do not check the last element - if (pRes == m_vector.back()) + if (pRes == m_resourceList.back()) continue; if (_stricmp(pRes->GetFileName(), filename) == 0) { @@ -360,75 +365,103 @@ void CConfig::AddElement(char *filename, char *cmdExec, flag_type_resources flag } } -bool CConfig::FileConsistencyResponce(IGameClient *pSenderClient, resource_t *resource, uint32 hash) +bool CResourceFile::FileConsistencyResponce(IGameClient *pSenderClient, resource_t *resource, uint32 hash) { bool bCheckeFiles = false; find_type_e typeFind = FIND_TYPE_NONE; + std::vector tempResourceList; - for (ResourceCheckerVectorIt it = m_vector.begin(); it != m_vector.end(); ++it) + for (auto iter = m_resourceList.begin(); iter != m_resourceList.end(); ++iter) { - CResourceCheckerNew *pRes = (*it); + CResourceBuffer *pRes = (*iter); if (strcmp(resource->szFileName, pRes->GetFileName()) != 0) continue; bCheckeFiles = true; - switch (pRes->GetFlagFile()) + int flags = pRes->GetFlagsFile(); + + if (flags & FLAG_TYPE_IGNORE) { - case FLAG_TYPE_EXISTS: - if (m_PreHash != hash && pRes->GetHashFile() == hash) { + if (m_PrevHash != hash) { + tempResourceList.push_back(pRes); + typeFind = FIND_TYPE_IGNORE; + } + } + else if (flags & FLAG_TYPE_EXISTS) + { + if (m_PrevHash != hash && pRes->GetHashFile() == hash) { typeFind = FIND_TYPE_ON_HASH; } - break; - case FLAG_TYPE_MISSGIN: - if (m_PreHash == hash) { + } + else if (flags & FLAG_TYPE_MISSGIN) + { + if (m_PrevHash == hash) { typeFind = FIND_TYPE_MISSING; } - break; - case FLAG_TYPE_HASH_ANY: - if (m_PreHash != hash) { - typeFind = FIND_TYPE_ANY_HASH; - } - break; - default: - typeFind = FIND_TYPE_NONE; - break; } + else if (flags & FLAG_TYPE_HASH_ANY) + { + if (m_PrevHash != hash) + { + typeFind = FIND_TYPE_ANY_HASH; + + for (size_t i = 0; i < tempResourceList.size(); i++) { + CResourceBuffer *pTemp = tempResourceList[i]; + + if (_stricmp(pTemp->GetFileName(), pRes->GetFileName()) != 0) { + continue; + } + + if (pTemp->GetHashFile() == hash) { + typeFind = FIND_TYPE_NONE; + break; + } + } + } + } + else + typeFind = FIND_TYPE_NONE; if (typeFind != FIND_TYPE_NONE) { + // push exec cmd - CmdExec.AddElement(pSenderClient, pRes); -#ifdef _DEBUG - printf("* (%s)(%s)(%x)\n", pRes->GetFileName(), pRes->GetCmdExec(), pRes->GetHashFile()); -#endif // _DEBUG + Exec.AddElement(pSenderClient, pRes, hash); + +//#ifdef _DEBUG + if (CVAR_GET_FLOAT("developer") == 1.0f) { + UTIL_Printf(" -> filename: (%s), cmdexec: (%s), hash: (%x)\n", pRes->GetFileName(), pRes->GetCmdExec(), pRes->GetHashFile()); + } +//#endif // _DEBUG } } - m_PreHash = hash; + m_PrevHash = hash; return !bCheckeFiles; } -CResourceCheckerNew::CResourceCheckerNew(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash) +CResourceBuffer::CResourceBuffer(char *filename, char *cmdExec, int flags, uint32 hash) { - int iLenFile = strlen(filename); - int iLenExec = strlen(cmdExec); + int lenFile = strlen(filename); + int lenExec = strlen(cmdExec); - m_FileName = new char[iLenFile + 1]; - m_CmdExec = new char[iLenExec + 1]; - - strncpy(m_FileName, filename, iLenFile); - strncpy(m_CmdExec, cmdExec, iLenExec); + m_FileName = new char[lenFile + 1]; + m_CmdExec = new char[lenExec + 1]; + + strncpy(m_FileName, filename, lenFile); + strncpy(m_CmdExec, cmdExec, lenExec); + + m_FileName[lenFile] = '\0'; + m_CmdExec[lenExec] = '\0'; - m_FileName[iLenFile] = '\0'; - m_CmdExec[iLenExec] = '\0'; m_Mark = false; - m_Flag = flag; + m_Flags = flags; m_HashFile = hash; } -CResourceCheckerNew::~CResourceCheckerNew() +CResourceBuffer::~CResourceBuffer() { // free me delete[] m_FileName, diff --git a/src/resource.h b/src/resource.h new file mode 100644 index 0000000..7457ddf --- /dev/null +++ b/src/resource.h @@ -0,0 +1,95 @@ +#pragma once + +#define FILE_INI_RESOURCES "resources.ini" + +#define MAX_CLIENTS 32 +#define MAX_CMD_LENGTH 128 +#define MAX_PATH_LENGTH 260 + +enum flag_type_resources +{ + FLAG_TYPE_NONE = 0, + FLAG_TYPE_EXISTS = (1 << 0), // to comparison with the specified hash value + FLAG_TYPE_MISSGIN = (1 << 1), // check it missing file on client + FLAG_TYPE_IGNORE = (1 << 2), // ignore the specified hash value + FLAG_TYPE_BREAK = (1 << 3), // do not check a next files + FLAG_TYPE_HASH_ANY = (1 << 4), // any file with any the hash value +}; + +enum find_type_e +{ + FIND_TYPE_NONE = 0, + FIND_TYPE_ON_HASH, + FIND_TYPE_MISSING, + FIND_TYPE_IGNORE, + FIND_TYPE_ANY_HASH, +}; + +enum arg_type_e +{ + ARG_TYPE_FILE_NAME = 0, + ARG_TYPE_FILE_HASH, + ARG_TYPE_CMD_EXEC, + ARG_TYPE_FLAG, + + MAX_PARSE_ARGUMENT, +}; + +class CResourceBuffer +{ +public: + CResourceBuffer(char *filename, char *cmdExec, int flags, uint32 hash); + ~CResourceBuffer(); + + uint32 GetHashFile() const { return m_HashFile; }; + int GetFlagsFile() const { return m_Flags; }; + + char *GetFileName() const { return m_FileName; }; + char *GetCmdExec() const { return m_CmdExec; }; + + bool GetBreak() const { return m_Break; }; + void SetBreak() { m_Break = true; }; + + bool GetMark() const { return m_Mark; }; + void SetMark() { m_Mark = true; }; + +private: + uint32 m_HashFile; + + int m_Flags; + + char *m_FileName; + char *m_CmdExec; + bool m_Mark; + bool m_Break; +}; + +class CResourceFile +{ +public: + void Init(); + void Load(); + + void Add(); + void Clear(); + + bool FileConsistencyResponce(IGameClient *pSenderClient, resource_t *resource, uint32 hash); + bool IsConfigLoaded() const { return !m_ConfigFailed; }; + +private: + void AddElement(char *filename, char *cmdExec, int flags, uint32 hash); + + // parse + const char *GetNextToken(char **pbuf); + +private: + typedef std::vector ResourceList; + ResourceList m_resourceList; + + uint32 m_PrevHash; + bool m_ConfigFailed; + char m_PathDir[MAX_PATH_LENGTH]; +}; + +extern CResourceFile Resource; + diff --git a/src/sdk_util.cpp b/src/sdk_util.cpp index d6a1e95..eed0e7d 100644 --- a/src/sdk_util.cpp +++ b/src/sdk_util.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" -void UTIL_Printf(char *fmt, ...) +void UTIL_Printf(const char *fmt, ...) { va_list argptr; static char string[1024]; @@ -13,7 +13,7 @@ void UTIL_Printf(char *fmt, ...) SERVER_PRINT(string); } -void UTIL_LogPrintf(char *fmt, ...) +void UTIL_LogPrintf(const char *fmt, ...) { va_list argptr; static char string[1024]; @@ -26,7 +26,7 @@ void UTIL_LogPrintf(char *fmt, ...) ALERT(at_logged, "%s", string); } -char *UTIL_VarArgs(char *format, ...) +char *UTIL_VarArgs(const char *format, ...) { va_list argptr; static char string[1024];