From d025e0edd4ba014023382f9df1bfc94e53bad334 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 13 Nov 2015 05:01:02 +0600 Subject: [PATCH] Refactoring Fix first prevhash For the future implemented config and task --- dist/config.ini | 5 + dist/resources.ini | 31 ++++ engine/rehlds_api.h | 5 + engine/rehlds_interfaces.h | 2 + msvc/rechecker.vcxproj | 27 ++- msvc/rechecker.vcxproj.filters | 15 ++ src/cmdexec.cpp | 57 +++---- src/cmdexec.h | 36 ++-- src/config.cpp | 101 +++++++++++ src/config.h | 28 +++ src/dllapi.cpp | 7 +- src/main.cpp | 116 +++++++------ src/main.h | 8 + src/meta_api.cpp | 2 +- src/precompiled.h | 7 +- src/resource.cpp | 302 +++++++++++++++++---------------- src/resource.h | 42 ++--- src/task.cpp | 74 ++++++++ src/task.h | 36 ++++ 19 files changed, 617 insertions(+), 284 deletions(-) create mode 100644 dist/config.ini create mode 100644 dist/resources.ini create mode 100644 src/config.cpp create mode 100644 src/config.h create mode 100644 src/task.cpp create mode 100644 src/task.h diff --git a/dist/config.ini b/dist/config.ini new file mode 100644 index 0000000..e9a1bdd --- /dev/null +++ b/dist/config.ini @@ -0,0 +1,5 @@ +# +# delay_exec 0|60 Delay before executing the all cmdexec +# + +delay_exec = 3.5 diff --git a/dist/resources.ini b/dist/resources.ini new file mode 100644 index 0000000..a4752da --- /dev/null +++ b/dist/resources.ini @@ -0,0 +1,31 @@ +# +# Resource checker +# -> Template keys from CMD exec +# [name] - nickname client +# [ip] - IP address client +# [userid] - userid client +# [steamid] - SteamID client +# +# [file_name] - the path of the file +# [file_hash] - hash the file of responce client +# +# -> Format +# path to file hash (exec cmd) +# "../opengl32.dll" c8005c526355d8015d462dc7f4ddb159 "kick [userid]" +# +# NOTE: Hash enough 4 bytes (or 8 characters) +# -> Example +# full md5 hash: c8005c526355d8015d462dc7f4ddb159 +# 4 bytes from the hash: c8005c52 +# +# -> Flags +# BREAK - when detected, do not check a next files +# IGNORE - no detect on specifed hash values +# +# -> Template keys from Hash +# UNKNOWN - check for any other hash +# 00000000 - check for the missing file +# c8005c52 - check for matching on hash +# + +"../opengl32.dll" UNKNOWN "kick [userid]" diff --git a/engine/rehlds_api.h b/engine/rehlds_api.h index 995feff..14280f3 100644 --- a/engine/rehlds_api.h +++ b/engine/rehlds_api.h @@ -149,6 +149,10 @@ typedef IHookChainRegistry IRehldsHoo typedef IVoidHookChain IRehldsHook_SV_DropClient; typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_DropClient; +//SV_ActivateServer hook +typedef IVoidHookChain IRehldsHook_SV_ActivateServer; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_ActivateServer; + class IRehldsHookchains { public: virtual ~IRehldsHookchains() { } @@ -181,6 +185,7 @@ public: virtual IRehldsHookRegistry_SV_WriteFullClientUpdate* SV_WriteFullClientUpdate() = 0; virtual IRehldsHookRegistry_SV_CheckConsistencyResponce* SV_CheckConsistencyResponce() = 0; virtual IRehldsHookRegistry_SV_DropClient* SV_DropClient() = 0; + virtual IRehldsHookRegistry_SV_ActivateServer* SV_ActivateServer() = 0; }; struct RehldsFuncs_t { diff --git a/engine/rehlds_interfaces.h b/engine/rehlds_interfaces.h index 9d31442..501be86 100644 --- a/engine/rehlds_interfaces.h +++ b/engine/rehlds_interfaces.h @@ -115,4 +115,6 @@ public: virtual void SetModelName(const char* modelname) = 0; virtual void SetConsistencyNum(int num) = 0; virtual int GetConsistencyNum() = 0; + virtual int GetResourcesNum() = 0; + virtual int GetDecalNameNum() = 0; }; diff --git a/msvc/rechecker.vcxproj b/msvc/rechecker.vcxproj index 0a7664b..1e1eccc 100644 --- a/msvc/rechecker.vcxproj +++ b/msvc/rechecker.vcxproj @@ -164,21 +164,35 @@ + + true + true + + + true + true + true + true + + true + true + true + true @@ -186,8 +200,17 @@ Create + Create + + true + true + + + + + {9A72E8DC-7667-46C1-899D-1E8B939564D2} @@ -266,14 +289,14 @@ REM IF EXIST "$(ProjectDir)ServerStart_cs_6153.bat" (CALL "$(ProjectDir)ServerSt true true _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(SolutionDir)../src/;$(SolutionDir)../src/sdk;%(AdditionalIncludeDirectories) + $(SolutionDir)../src/;$(SolutionDir)../common/;$(SolutionDir)../dlls/;$(SolutionDir)../engine/;$(SolutionDir)../pm_shared/;$(SolutionDir)../public/;$(SolutionDir)../metamod/;%(AdditionalIncludeDirectories) precompiled.h MultiThreaded AnySuitable Speed true true - false + Sync false NotSet diff --git a/msvc/rechecker.vcxproj.filters b/msvc/rechecker.vcxproj.filters index 98f9da1..e3f00be 100644 --- a/msvc/rechecker.vcxproj.filters +++ b/msvc/rechecker.vcxproj.filters @@ -462,6 +462,8 @@ + + @@ -480,6 +482,8 @@ + + @@ -503,5 +507,16 @@ {1bb5b890-a282-419e-912a-26d9d8fccf5b} + + {d8dea905-0ad8-4f5e-973c-fc9917c49e68} + + + + + dist + + + dist + \ No newline at end of file diff --git a/src/cmdexec.cpp b/src/cmdexec.cpp index ef2984a..82d11fa 100644 --- a/src/cmdexec.cpp +++ b/src/cmdexec.cpp @@ -1,29 +1,28 @@ #include "precompiled.h" -CExecManager Exec; +CExecMngr Exec; -CBufExec::CBufExec(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash) +CExecMngr::CBufExec::CBufExec(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash) { m_pClient = pClient; m_pResource = pResource; m_ClientHash = responseHash; } -CBufExec::~CBufExec() +CExecMngr::CBufExec::~CBufExec() { ; } -void CExecManager::AddElement(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash) +void CExecMngr::AddElement(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash) { m_execList.push_back(new CBufExec(pClient, pResource, responseHash)); } void StringReplace(char *src, const char *strold, const char *strnew) { - if (strnew == NULL) { + if (strnew == NULL) return; - } char *p = src; int oldLen = strlen(strold), newLen = strlen(strnew); @@ -44,6 +43,10 @@ char *GetExecCmdPrepare(IGameClient *pClient, CResourceBuffer *pResource, uint32 const netadr_t *net; static char string[256]; + // check cmdexec is empty + if (pResource->GetCmdExec() == NULL) + return NULL; + strncpy(string, pResource->GetCmdExec(), sizeof(string) - 1); string[sizeof(string) - 1] = '\0'; @@ -61,16 +64,15 @@ char *GetExecCmdPrepare(IGameClient *pClient, CResourceBuffer *pResource, uint32 len = strlen(string); - if (len < sizeof(string) - 2) { + if (len < sizeof(string) - 2) strcat(string, "\n"); - } else string[len - 1] = '\n'; return string; } -void CExecManager::CommandExecute(IGameClient *pClient) +void CExecMngr::CommandExecute(IGameClient *pClient) { bool bBreak = false; auto iter = m_execList.begin(); @@ -79,7 +81,8 @@ void CExecManager::CommandExecute(IGameClient *pClient) { CBufExec *pExec = (*iter); - if (pExec->GetGameClient() != pClient) { + if (pExec->GetGameClient() != pClient) + { iter++; continue; } @@ -88,38 +91,31 @@ void CExecManager::CommandExecute(IGameClient *pClient) // exit the loop if the client is out of the game // TODO: Check me! - if (!pClient->IsConnected()) { + if (!pClient->IsConnected()) + { break; } char *cmdExec = GetExecCmdPrepare(pClient, pRes, pExec->GetClientHash()); - // 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') { + if (!bBreak // erase all cmdexec because have flag is break + && cmdExec != NULL && cmdExec[0] != '\0') + { // execute cmdexec SERVER_COMMAND(cmdExec); - - // erase cmdexec - delete pExec; - iter = m_execList.erase(iter); } - else - iter++; - bBreak = (pRes->GetFileFlags() & FLAG_TYPE_BREAK) == FLAG_TYPE_BREAK; + // erase cmdexec + delete pExec; + iter = m_execList.erase(iter); + bBreak = (pRes->GetFileFlag() == FLAG_TYPE_BREAK); } } -void CExecManager::Clear(IGameClient *pClient) +void CExecMngr::Clear(IGameClient *pClient) { - if (pClient == NULL) { + if (pClient == NULL) + { m_execList.clear(); return; } @@ -130,7 +126,8 @@ void CExecManager::Clear(IGameClient *pClient) CBufExec *pExec = (*iter); // erase cmdexec - if (pExec->GetGameClient() == pClient) { + if (pExec->GetGameClient() == pClient) + { delete pExec; iter = m_execList.erase(iter); } diff --git a/src/cmdexec.h b/src/cmdexec.h index 8541d20..b0b47e2 100644 --- a/src/cmdexec.h +++ b/src/cmdexec.h @@ -1,22 +1,6 @@ #pragma once -class CBufExec -{ -public: - CBufExec(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash); - ~CBufExec(); - - IGameClient *GetGameClient() const { return m_pClient; }; - CResourceBuffer *GetResource() const { return m_pResource; }; - uint32 GetClientHash() const { return m_ClientHash; }; - -private: - IGameClient *m_pClient; - CResourceBuffer *m_pResource; - uint32 m_ClientHash; -}; - -class CExecManager +class CExecMngr { public: void AddElement(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash); @@ -24,10 +8,26 @@ public: void Clear(IGameClient *pClient = NULL); private: + class CBufExec + { + public: + CBufExec(IGameClient *pClient, CResourceBuffer *pResource, uint32 responseHash); + ~CBufExec(); + + IGameClient *GetGameClient() const { return m_pClient; }; + CResourceBuffer *GetResource() const { return m_pResource; }; + uint32 GetClientHash() const { return m_ClientHash; }; + + private: + IGameClient *m_pClient; + CResourceBuffer *m_pResource; + uint32 m_ClientHash; + }; + typedef std::list CBufExecList; CBufExecList m_execList; }; -extern CExecManager Exec; +extern CExecMngr Exec; extern void StringReplace(char *src, const char *strold, const char *strnew); diff --git a/src/config.cpp b/src/config.cpp new file mode 100644 index 0000000..f3369f7 --- /dev/null +++ b/src/config.cpp @@ -0,0 +1,101 @@ +#include "precompiled.h" + +#define TRY_READ_INT(a,b,min,max) if (_stricmp(argv[0], ##a) == 0) b = clamp(atoi(argv[1]), min, max); +#define TRY_READ_FLOAT(a,b,min,max) if (_stricmp(argv[0], ##a) == 0) b = clamp(atof(argv[1]), min, max); +#define TRY_READ_STRING(a,b) if (_stricmp(argv[0], ##a) == 0) strncpy(b, argv[1], sizeof(b) - 1); b[sizeof(b) - 1] = '\0'; + +CConfig Config; + +void CConfig::Init() +{ + char *pos; + char path[MAX_PATH_LENGTH]; + + strncpy(path, GET_PLUGIN_PATH(PLID), sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + pos = strrchr(path, '/'); + + if (*pos == '\0') + return; + + *(pos + 1) = '\0'; + + // config.ini + snprintf(m_PathDir, sizeof(m_PathDir), "%s" FILE_INI_CONFIG, path); +} + +int parse(char *line, char **argv, int max_args) +{ + int count = 0; + + while (*line) + { + // null whitespaces + while (*line == ' ' || *line == '\t' || *line == '\n' || *line == '\r' || *line == '=' || *line == '"') + *line++ = '\0'; + + if (*line) + { + // save arg address + argv[count++] = line; + + if (count == max_args) + break; + + // skip arg + while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n' && *line != '\r' && *line != '=' && *line != '"') + line++; + } + } + + return count; +} + +void CConfig::ResetValues() +{ + m_DelayExec = 2.5f; + // [..] +} + +void CConfig::Load() +{ + FILE *fp; + char line[1024]; + char *argv[3]; + int argc; + char *pos; + + // reset config + ResetValues(); + + fp = fopen(m_PathDir, "rt"); + + if (fp == NULL) + { + m_ConfigFailed = true; + UTIL_Printf(__FUNCTION__ ": can't find path to " FILE_INI_CONFIG "\n"); + return; + } + + while (!feof(fp) && fgets(line, sizeof(line), fp)) + { + pos = line; + + if (*pos == '\0' || *pos == ';' || *pos == '\\' || *pos == '/' || *pos == '#') + continue; + + if ((pos = strchr(line, ';')) != NULL || (pos = strstr(line, "//")) != NULL) + *pos = '\0'; + + argc = parse(line, argv, ARRAYSIZE(argv)); + + if (argc != 2) + continue; + + else TRY_READ_FLOAT("delay_exec", m_DelayExec, 0.0, 60.0) + } + + fclose(fp); + m_ConfigFailed = false; +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..8bc8a38 --- /dev/null +++ b/src/config.h @@ -0,0 +1,28 @@ +#pragma once + +#define FILE_INI_CONFIG "config.ini" + +class CConfig +{ +public: + void Init(); + void Load(); + + float GetDelay() const { return m_DelayExec; }; + bool IsConfigLoaded() const { return !m_ConfigFailed; }; + +private: + void ResetValues(); + +private: + bool m_ConfigFailed; + char m_PathDir[MAX_PATH_LENGTH]; + + // settings + float m_DelayExec; +}; + +template +T clamp(T a, T min, T max) { return (a > max) ? max : (a < min) ? min : a; } + +extern CConfig Config; diff --git a/src/dllapi.cpp b/src/dllapi.cpp index 470ce67..44b9921 100644 --- a/src/dllapi.cpp +++ b/src/dllapi.cpp @@ -2,10 +2,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); static DLL_FUNCTIONS gFunctionTable = @@ -92,13 +89,13 @@ static DLL_FUNCTIONS gFunctionTable_Post = NULL, // pfnRestoreGlobalState NULL, // pfnResetGlobalState - &ClientConnect_Post, // pfnClientConnect + NULL, // pfnClientConnect NULL, // pfnClientDisconnect NULL, // pfnClientKill &ClientPutInServer_Post, // pfnClientPutInServer NULL, // pfnClientCommand NULL, // pfnClientUserInfoChanged - &ServerActivate_Post, // pfnServerActivate + NULL, // pfnServerActivate &ServerDeactivate_Post, // pfnServerDeactivate NULL, // pfnPlayerPreThink diff --git a/src/main.cpp b/src/main.cpp index ce26af4..bc16727 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,45 +1,44 @@ #include "precompiled.h" -bool g_bInitialized = false; +cvar_t mp_consistency = { "mp_consistency", "0", 0, 0.0f, NULL }; -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() { - if (RehldsApi_Init() != RETURN_LOAD) { + if (RehldsApi_Init() != RETURN_LOAD) return false; - } // register function from ReHLDS API - g_RehldsApi->GetHookchains()->SV_CheckConsistencyResponce()->registerHook(&SV_CheckConsistencyResponce); g_RehldsApi->GetHookchains()->SV_DropClient()->registerHook(&SV_DropClient); + g_RehldsApi->GetHookchains()->SV_ActivateServer()->registerHook(&SV_ActivateServer); + g_RehldsApi->GetHookchains()->SV_CheckConsistencyResponce()->registerHook(&SV_CheckConsistencyResponce); SV_AddResource = g_RehldsApi->GetFuncs()->SV_AddResource; // initialize resource config Resource.Init(); + /* + // initialize config + Config.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.value = mp_consistency_old->value; + mp_consistency.string = mp_consistency_old->string; + mp_consistency.flags = mp_consistency_old->flags; 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 Resource.IsConfigLoaded(); + // if all config's is OK go to attach + return (Resource.IsConfigLoaded()/* && Config.IsConfigLoaded()*/); } void OnMetaDetach() @@ -48,74 +47,87 @@ void OnMetaDetach() // clear Exec.Clear(); + /*Task.Clear();*/ Resource.Clear(); } void ServerDeactivate_Post() { - if (g_bInitialized) { - // clear - Exec.Clear(); - Resource.Clear(); - g_bInitialized = false; - } + // clear + Exec.Clear(); + /*Task.Clear();*/ + Resource.Clear(); SET_META_RESULT(MRES_IGNORED); } -void ServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax) -{ - 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); - } + // clear buffer cmdexec the client when was disconnected up to perform cmdexec + Exec.Clear(pClient); + /*Task.Clear(pClient);*/ // call next hook chain->callNext(pClient, crash, string); } +/* +void StartFrame() +{ + Task.StartFrame(); + SET_META_RESULT(MRES_IGNORED); +} +*/ + +void SV_ActivateServer(IRehldsHook_SV_ActivateServer *chain, int runPhysics) +{ + /*Config.Load();*/ + Resource.LoadResources(); + + chain->callNext(runPhysics); + + // add to the resource + Resource.CreateResourceList(); +} + +/* +void TaskHandler(IGameClient *pClient) +{ + if (!pClient->IsConnected()) + return; + + // client is connected to putinserver, go execute cmd out buffer + Exec.CommandExecute(pClient); +} +*/ + void ClientPutInServer_Post(edict_t *pEntity) { int nIndex = ENTINDEX(pEntity) - 1; - if (nIndex < 0 || nIndex >= gpGlobals->maxClients) { + if (nIndex < 0 || nIndex >= gpGlobals->maxClients) RETURN_META(MRES_IGNORED); - } IGameClient *pClient = g_RehldsApi->GetServerStatic()->GetClient(nIndex); - if (pClient != NULL) { + /* + float time = Config.GetDelay(); + if (time <= 0.0f) + */ // client is connected to putinserver, go execute cmd out buffer Exec.CommandExecute(pClient); - } + /* + else + Task.AddTask(pClient, time, (xtask_t)TaskHandler); + */ SET_META_RESULT(MRES_IGNORED); } -qboolean ClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]) -{ - if (!g_bInitialized) { - Resource.Add(); - g_bInitialized = true; - } - - SET_META_RESULT(MRES_IGNORED); - return META_RESULT_ORIG_RET(qboolean); -} - bool SV_CheckConsistencyResponce(IRehldsHook_SV_CheckConsistencyResponce *chain, IGameClient *pSenderClient, resource_t *resource, uint32 hash) { - if (resource->type == t_decal) { - if (!Resource.FileConsistencyResponce(pSenderClient, resource, hash)) - return false; - } + if (!Resource.FileConsistencyResponce(pSenderClient, resource, hash)) + return false; // call next hook and take return of values from original func return chain->callNext(pSenderClient, resource, hash); diff --git a/src/main.h b/src/main.h index 4595c1f..d754e98 100644 --- a/src/main.h +++ b/src/main.h @@ -1,3 +1,11 @@ #pragma once +void StartFrame(); +void SV_ActivateServer(IRehldsHook_SV_ActivateServer *chain, int runPhysics); +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); + +/* +extern DLL_FUNCTIONS *g_pFunctionTable; +*/ extern void (*SV_AddResource)(resourcetype_t type, const char *name, int size, unsigned char flags, int index); diff --git a/src/meta_api.cpp b/src/meta_api.cpp index 30a2a8f..5b95524 100644 --- a/src/meta_api.cpp +++ b/src/meta_api.cpp @@ -8,7 +8,7 @@ plugin_info_t Plugin_info = __DATE__, "s1lent", "http://www.dedicated-server.ru/", - "ReChecker", + "Rechecker", PT_STARTUP, PT_NEVER, }; diff --git a/src/precompiled.h b/src/precompiled.h index 912ba14..cd7d5a6 100644 --- a/src/precompiled.h +++ b/src/precompiled.h @@ -8,6 +8,8 @@ #undef __FUNCTION__ #endif // _WIN32 +#define MAX_PATH_LENGTH 260 + #include #include #include // strrchr @@ -21,7 +23,10 @@ #include "rehlds_api.h" #include "engine_rehlds.h" -#include "main.h" +//#include "main.h" +//#include "task.h" + +#include "config.h" #include "resource.h" #include "cmdexec.h" //#include "sdk_util.h" // UTIL_LogPrintf, etc diff --git a/src/resource.cpp b/src/resource.cpp index ac38b57..e6b2a2e 100644 --- a/src/resource.cpp +++ b/src/resource.cpp @@ -3,27 +3,35 @@ CResourceFile Resource; std::vector StringsCache; -void CResourceFile::Add() +void CResourceFile::CreateResourceList() { int nConsistency = g_RehldsServerData->GetConsistencyNum(); + m_DecalsNum = g_RehldsServerData->GetDecalNameNum(); - for (auto iter = m_resourceList.cbegin(); iter != m_resourceList.cend(); ++iter) + for (auto iter = m_resourceList.cbegin(), end = m_resourceList.cend(); iter != end; ++iter) { CResourceBuffer *pRes = (*iter); // prevent duplicate of filenames // check if filename is been marked so do not add the resource again - if (!pRes->IsDuplicate()) { -//#ifdef _DEBUG - if (CVAR_GET_FLOAT("developer") == 1.0f) { - UTIL_Printf(__FUNCTION__ " :: (%s)(%s)(%x)\n", pRes->GetFileName(), pRes->GetCmdExec(), pRes->GetFileHash()); + if (!pRes->IsDuplicate()) + { + // check limit resource + if (g_RehldsServerData->GetResourcesNum() >= MAX_RESOURCE_LIST) + { + UTIL_Printf(__FUNCTION__ ": can't add resource \"%s\" on line %d; exceeded the limit of resources max '%d'\n", pRes->GetFileName(), pRes->GetLine(), MAX_RESOURCE_LIST); + break; } -//#endif // _DEBUG - SV_AddResource(t_decal, pRes->GetFileName(), 0, RES_CHECKFILE, 4095); + +#ifdef _DEBUG + UTIL_Printf(__FUNCTION__ " :: (%s)(%s)(%x)\n", pRes->GetFileName(), pRes->GetCmdExec(), pRes->GetFileHash()); +#endif // _DEBUG + SV_AddResource(t_decal, pRes->GetFileName(), 0, RES_CHECKFILE, m_DecalsNum++); nConsistency++; } } + m_DecalsNum = g_RehldsServerData->GetDecalNameNum(); g_RehldsServerData->SetConsistencyNum(nConsistency); } @@ -71,16 +79,17 @@ inline bool invalidchar(const char c) || c == '>' || c == '|') != 0; } -bool IsValidFilename(char *psrc, char &pchar) { - +bool IsValidFilename(char *psrc, char &pchar) +{ char *pch = strrchr(psrc, '/'); - if (pch == NULL) { + if (pch == NULL) pch = psrc; - } - while (*pch++) { - if (invalidchar(*pch)) { + while (*pch++) + { + if (invalidchar(*pch)) + { pchar = *pch; return false; } @@ -89,32 +98,30 @@ bool IsValidFilename(char *psrc, char &pchar) { return true; } -bool IsFileHasExtension(char *psrc) { - +bool IsFileHasExtension(char *psrc) +{ // find the extension filename char *pch = strrchr(psrc, '.'); - if (pch == NULL) { + if (pch == NULL) return false; - } // the size extension - if (strlen(&pch[1]) <= 0) { + if (strlen(&pch[1]) <= 0) return false; - } return strchr(pch, '/') == NULL; } -void CResourceFile::Load() +void CResourceFile::LoadResources() { char *pos; - char buffer[4096]; + char line[4096]; uint8 hash[16]; FILE *fp; int argc; int len; - int flags; + flag_type_resources flag; char filename[MAX_PATH_LENGTH]; char cmdBufExec[MAX_PATH_LENGTH]; int cline = 0; @@ -128,19 +135,19 @@ void CResourceFile::Load() return; } - while (!feof(fp) && fgets(buffer, sizeof(buffer), fp)) + while (!feof(fp) && fgets(line, sizeof(line), fp)) { - pos = buffer; + pos = line; cline++; - + if (*pos == '\0' || *pos == ';' || *pos == '\\' || *pos == '/' || *pos == '#') continue; const char *pToken = GetNextToken(&pos); argc = 0; - flags = FLAG_TYPE_NONE; + flag = FLAG_TYPE_NONE; memset(hash, 0, sizeof(hash)); @@ -152,8 +159,8 @@ void CResourceFile::Load() { case ARG_TYPE_FILE_NAME: { - strncpy(filename, pToken, len + 1); - filename[len + 1] = '\0'; + strncpy(filename, pToken, len); + filename[len] = '\0'; break; } case ARG_TYPE_FILE_HASH: @@ -163,44 +170,50 @@ void CResourceFile::Load() strncpy((char *)pbuf, pToken, len); pbuf[len] = '\0'; - if (_stricmp((const char *)pbuf, "UNKNOWN") == 0) { - flags = FLAG_TYPE_HASH_ANY; + if (_stricmp((const char *)pbuf, "UNKNOWN") == 0) + { + flag = FLAG_TYPE_HASH_ANY; } else { for (int i = 0; i < sizeof(pbuf) / 2; i++) hash[i] = hexbyte(&pbuf[i * 2]); - flags = (*(uint32 *)&hash[0] != 0x00000000) ? FLAG_TYPE_EXISTS : FLAG_TYPE_MISSGIN; + flag = (*(uint32 *)&hash[0] != 0x00000000) ? FLAG_TYPE_EXISTS : FLAG_TYPE_MISSING; } - break; } case ARG_TYPE_CMD_EXEC: { - strncpy(cmdBufExec, pToken, len + 1); - cmdBufExec[len + 1] = '\0'; + strncpy(cmdBufExec, pToken, len); + cmdBufExec[len] = '\0'; - if (_stricmp(cmdBufExec, "IGNORE") == 0) { - flags = FLAG_TYPE_IGNORE; + if (_stricmp(cmdBufExec, "IGNORE") == 0) + { + flag = FLAG_TYPE_IGNORE; cmdBufExec[0] = '\0'; } - else if (_stricmp(cmdBufExec, "BREAK") == 0) { - flags |= FLAG_TYPE_BREAK; + else if (_stricmp(cmdBufExec, "BREAK") == 0) + { + flag = FLAG_TYPE_BREAK; cmdBufExec[0] = '\0'; } - else { + else + { // replface \' to " StringReplace(cmdBufExec, "'", "\""); } + break; } case ARG_TYPE_FLAG: { - if (_stricmp(pToken, "IGNORE") == 0) { - flags = FLAG_TYPE_IGNORE; + if (_stricmp(pToken, "IGNORE") == 0) + { + flag = FLAG_TYPE_IGNORE; } - else if (_stricmp(pToken, "BREAK") == 0) { - flags |= FLAG_TYPE_BREAK; + else if (_stricmp(pToken, "BREAK") == 0) + { + flag = FLAG_TYPE_BREAK; } break; } @@ -211,44 +224,47 @@ void CResourceFile::Load() argc++; pToken = GetNextToken(&pos); - if (pToken == NULL && argc == ARG_TYPE_FLAG) { + if (pToken == NULL && argc == ARG_TYPE_FLAG) + { // go to next argument argc++; } } - if (argc >= MAX_PARSE_ARGUMENT) { - + if (argc >= MAX_PARSE_ARGUMENT) + { char pchar; - if (strlen(filename) <= 0) { + if (strlen(filename) <= 0) + { UTIL_Printf(__FUNCTION__ ": Failed to load \"" FILE_INI_RESOURCES "\"; path to filename is empty on line %d\n", cline); continue; } - - else if (!IsFileHasExtension(filename)) { + else if (!IsFileHasExtension(filename)) + { UTIL_Printf(__FUNCTION__ ": Failed to load \"" FILE_INI_RESOURCES "\"; filename has no extension on line %d\n", cline); continue; } - - else if (!IsValidFilename(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 (flags == FLAG_TYPE_NONE) { + else if (flag == FLAG_TYPE_NONE) + { UTIL_Printf(__FUNCTION__ ": Failed to load \"" FILE_INI_RESOURCES "\"; parsing hash failed on line %d\n", cline); continue; } - // TODO: is there a need to flag FLAG_TYPE_BREAK without cmdexec? - else if (strlen(cmdBufExec) <= 0 && !(flags & (FLAG_TYPE_IGNORE | FLAG_TYPE_BREAK))) { + else if (strlen(cmdBufExec) <= 0 && (flag != FLAG_TYPE_IGNORE && flag != 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, flags, *(uint32 *)&hash[0]); + AddElement(filename, cmdBufExec, flag, *(uint32 *)&hash[0], cline); } - else if (pToken != NULL || argc > ARG_TYPE_FILE_NAME) { + 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); } } @@ -267,7 +283,8 @@ const char *CResourceFile::GetNextToken(char **pbuf) while (*rpos != 0 && isspace(*rpos)) rpos++; - if (*rpos == '\0') { + if (*rpos == '\0') + { *pbuf = rpos; return NULL; } @@ -320,45 +337,17 @@ const char *CResourceFile::GetNextToken(char **pbuf) return res; } -void TrimSpace(char *pbuf) +void CResourceFile::AddElement(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, int line) { - char *pend = pbuf; - char *pstart = pbuf; - - while ((*pstart == ' ' - || *pstart == '"' - || *pstart == '\'' - || *pstart == '\t' - || *pstart == '\r' - || *pstart == '\n')) - ++pstart; - - while (*pstart) - *pend++ = *pstart++; - - *pend = '\0'; - - while (pend > pbuf && *--pend && - (*pend == ' ' - || *pend == '"' - || *pend == '\'' - || *pend == '\t' - || *pend == '\r' - || *pend == '\n' - || *pend == ';')) - *pend = '\0'; -} - -void CResourceFile::AddElement(char *filename, char *cmdExec, int flags, uint32 hash) -{ - auto nRes = new CResourceBuffer(filename, cmdExec, flags, hash); + auto nRes = new CResourceBuffer(filename, cmdExec, flag, hash, line); // to mark files which are not required to add to the resource again - for (auto iter = m_resourceList.cbegin(); iter != m_resourceList.cend(); ++iter) + for (auto iter = m_resourceList.cbegin(), end = m_resourceList.cend(); iter != end; ++iter) { CResourceBuffer *pRes = (*iter); - - if (_stricmp(pRes->GetFileName(), filename) == 0) { + + if (_stricmp(pRes->GetFileName(), filename) == 0) + { // resource name already registered nRes->SetDuplicate(); break; @@ -370,106 +359,123 @@ void CResourceFile::AddElement(char *filename, char *cmdExec, int flags, uint32 bool CResourceFile::FileConsistencyResponce(IGameClient *pSenderClient, resource_t *resource, uint32 hash) { + if (resource->type != t_decal + || resource->nIndex < m_DecalsNum) // if by some miracle the decals will have the flag RES_CHECKFILE + // to be sure not bypass the decals + { + m_PrevHash = hash; + return true; + } + + // strange thing + // if this happened when missing all the files from client + if (!m_PrevHash) + { + return true; + } + bool bHandled = false; - find_type_e typeFind = FIND_TYPE_NONE; + flag_type_resources typeFind; std::vector tempResourceList; - for (auto iter = m_resourceList.begin(); iter != m_resourceList.end(); ++iter) + for (auto iter = m_resourceList.cbegin(), end = m_resourceList.cend(); iter != end; ++iter) { CResourceBuffer *pRes = (*iter); if (strcmp(resource->szFileName, pRes->GetFileName()) != 0) continue; - bHandled = true; + typeFind = pRes->GetFileFlag(); - int flags = pRes->GetFileFlags(); + if (m_PrevHash == hash && typeFind != FLAG_TYPE_MISSING) + typeFind = FLAG_TYPE_NONE; - if (flags & FLAG_TYPE_IGNORE) + switch (typeFind) { - if (m_PrevHash != hash) { - tempResourceList.push_back(pRes); - typeFind = FIND_TYPE_IGNORE; - } - } - else if (flags & FLAG_TYPE_EXISTS) - { - if (m_PrevHash != hash && pRes->GetFileHash() == hash) { - typeFind = FIND_TYPE_ON_HASH; - } - } - else if (flags & FLAG_TYPE_MISSGIN) - { - if (m_PrevHash == hash) { - typeFind = FIND_TYPE_MISSING; - } - } - else if (flags & FLAG_TYPE_HASH_ANY) - { - if (m_PrevHash != hash) + case FLAG_TYPE_BREAK: + /* empty */ + break; + case FLAG_TYPE_IGNORE: + tempResourceList.push_back(pRes); + break; + case FLAG_TYPE_EXISTS: + if (pRes->GetFileHash() == hash) { - typeFind = FIND_TYPE_ANY_HASH; + typeFind = FLAG_TYPE_EXISTS; + } + break; + case FLAG_TYPE_HASH_ANY: + for (auto it = tempResourceList.cbegin(); it != tempResourceList.cend(); ++it) + { + CResourceBuffer *pTemp = (*it); - for (size_t i = 0; i < tempResourceList.size(); i++) { - CResourceBuffer *pTemp = tempResourceList[i]; + if (_stricmp(pTemp->GetFileName(), pRes->GetFileName()) != 0) + continue; - if (_stricmp(pTemp->GetFileName(), pRes->GetFileName()) != 0) { - continue; - } - - if (pTemp->GetFileHash() == hash) { - typeFind = FIND_TYPE_NONE; - break; - } + if (pTemp->GetFileHash() == hash) + { + typeFind = FLAG_TYPE_NONE; + break; } } + break; + case FLAG_TYPE_MISSING: + if (m_PrevHash != hash) + { + typeFind = FLAG_TYPE_NONE; + } + break; + default: + typeFind = FLAG_TYPE_NONE; + break; } - else - typeFind = FIND_TYPE_NONE; - - if (typeFind != FIND_TYPE_NONE) { + if (typeFind != FLAG_TYPE_NONE) + { // push exec cmd 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->GetFileHash()); - } -//#endif // _DEBUG +#ifdef _DEBUG + UTIL_Printf(" -> filename: (%s), cmdexec: (%s), hash: (%x), typeFind: (%d)\n", pRes->GetFileName(), pRes->GetCmdExec(), pRes->GetFileHash(), typeFind); +#endif // _DEBUG } + + bHandled = true; } m_PrevHash = hash; return !bHandled; } -const char* DuplicateString(const char* str) +const char *DuplicateString(const char *str) { - for (auto it = StringsCache.begin(), end = StringsCache.end(); it != end; ++it) + for (auto iter = StringsCache.cbegin(), end = StringsCache.cend(); iter != end; ++iter) { - if (!strcmp(*it, str)) - return *it; + if (!strcmp(*iter, str)) + return *iter; } - const char* s = strcpy(new char[strlen(str) + 1], str); + const char *s = strcpy(new char[strlen(str) + 1], str); StringsCache.push_back(s); return s; } void ClearStringsCache() { - for (auto it = StringsCache.begin(), end = StringsCache.end(); it != end; ++it) - delete *it; + for (auto iter = StringsCache.begin(), end = StringsCache.end(); iter != end; ++iter) + delete [] *iter; + + StringsCache.clear(); } -CResourceBuffer::CResourceBuffer(char *filename, char *cmdExec, int flags, uint32 hash) +CResourceBuffer::CResourceBuffer(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, int line) { m_FileName = DuplicateString(filename); - m_CmdExec = DuplicateString(cmdExec); + m_CmdExec = (cmdExec[0] != '\0') ? DuplicateString(cmdExec) : NULL; m_Duplicate = false; - m_Flags = flags; + m_Flag = flag; m_FileHash = hash; + m_Line = line; } diff --git a/src/resource.h b/src/resource.h index b48c8da..709d4b5 100644 --- a/src/resource.h +++ b/src/resource.h @@ -2,27 +2,17 @@ #define FILE_INI_RESOURCES "resources.ini" -#define MAX_CLIENTS 32 #define MAX_CMD_LENGTH 128 -#define MAX_PATH_LENGTH 260 +#define MAX_RESOURCE_LIST 1280 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, + 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_BREAK, // do not check a next files + FLAG_TYPE_HASH_ANY, // any file with any the hash value }; enum arg_type_e @@ -38,16 +28,14 @@ enum arg_type_e class CResourceBuffer { public: - CResourceBuffer(char *filename, char *cmdExec, int flags, uint32 hash); + CResourceBuffer(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, int line); uint32 GetFileHash() const { return m_FileHash; }; - int GetFileFlags() const { return m_Flags; }; + flag_type_resources GetFileFlag() const { return m_Flag; }; const char *GetFileName() const { return m_FileName; }; const char *GetCmdExec() const { return m_CmdExec; }; - - bool GetBreak() const { return m_Break; }; - void SetBreak() { m_Break = true; }; + int GetLine() const { return m_Line; }; bool IsDuplicate() const { return m_Duplicate; }; void SetDuplicate() { m_Duplicate = true; }; @@ -55,28 +43,27 @@ public: private: uint32 m_FileHash; - int m_Flags; + flag_type_resources m_Flag; + int m_Line; const char *m_FileName; const char *m_CmdExec; bool m_Duplicate; - bool m_Break; }; class CResourceFile { public: void Init(); - void Load(); - - void Add(); void Clear(); + void LoadResources(); + void CreateResourceList(); 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); + void AddElement(char *filename, char *cmdExec, flag_type_resources flag, uint32 hash, int line); // parse const char *GetNextToken(char **pbuf); @@ -85,6 +72,7 @@ private: typedef std::vector ResourceList; ResourceList m_resourceList; + int m_DecalsNum; uint32 m_PrevHash; bool m_ConfigFailed; char m_PathDir[MAX_PATH_LENGTH]; diff --git a/src/task.cpp b/src/task.cpp new file mode 100644 index 0000000..c70faf3 --- /dev/null +++ b/src/task.cpp @@ -0,0 +1,74 @@ +#include "precompiled.h" + +CTaskMngr Task; + +CTaskMngr::CBufTask::CBufTask(IGameClient *pClient, float time, xtask_t handler) +{ + m_pClient = pClient; + m_Handler = handler; + m_EndTime = gpGlobals->time + time; +} + +void CTaskMngr::AddTask(IGameClient *pClient, float time, xtask_t handler) +{ + g_pFunctionTable->pfnStartFrame = ::StartFrame; + m_taskList.push_back(new CBufTask(pClient, time, handler)); +} + +void CTaskMngr::StartFrame() +{ + if (m_taskList.empty()) + { + // more not to call + g_pFunctionTable->pfnStartFrame = NULL; + return; + } + + if (m_nextFrame > gpGlobals->time) + return; + + auto iter = m_taskList.begin(); + while (iter != m_taskList.end()) + { + CBufTask *pTask = (*iter); + + if (pTask->GetEndTime() >= gpGlobals->time) + { + iter++; + continue; + } + + pTask->Handler(); + + // erase task + delete pTask; + iter = m_taskList.erase(iter); + } + + m_nextFrame = gpGlobals->time + TASK_FREQUENCY_TIME; +} + +void CTaskMngr::Clear(IGameClient *pClient) +{ + if (pClient == NULL) + { + // reset next frame + m_nextFrame = 0; + } + + auto iter = m_taskList.begin(); + while (iter != m_taskList.end()) + { + CBufTask *pTask = (*iter); + + if (pClient != NULL && pTask->GetClient() != pClient) + { + iter++; + continue; + } + + // erase task + delete pTask; + iter = m_taskList.erase(iter); + } +} diff --git a/src/task.h b/src/task.h new file mode 100644 index 0000000..3ca3b01 --- /dev/null +++ b/src/task.h @@ -0,0 +1,36 @@ +#pragma once + +#define TASK_FREQUENCY_TIME 1.0f // check frequency current tasks + +typedef void (*xtask_t)(IGameClient *); + +class CTaskMngr +{ +public: + void AddTask(IGameClient *pClient, float time, xtask_t handler); + void StartFrame(); + void Clear(IGameClient *pClient = NULL); + +private: + class CBufTask + { + public: + CBufTask(IGameClient *pClient, float time, xtask_t handler); + + IGameClient *GetClient() const { return m_pClient; }; + float GetEndTime() const { return m_EndTime; }; + void Handler() const { m_Handler(m_pClient); }; + + private: + IGameClient *m_pClient; + xtask_t m_Handler; + float m_EndTime; + }; + + typedef std::vector CBufTaskList; + + CBufTaskList m_taskList; + float m_nextFrame; +}; + +extern CTaskMngr Task;