From 5b72d06bfb1d09a147711536b8d878e959494094 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 10 May 2024 17:38:09 +0700 Subject: [PATCH 01/10] Fix default value for sv_net_incoming_decompression_max_ratio --- rehlds/engine/net_chan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rehlds/engine/net_chan.cpp b/rehlds/engine/net_chan.cpp index 71fc0f6d4..b4b75e9ce 100644 --- a/rehlds/engine/net_chan.cpp +++ b/rehlds/engine/net_chan.cpp @@ -38,7 +38,7 @@ cvar_t net_drawslider = { "net_drawslider", "0", 0, 0.0f, nullptr}; cvar_t net_chokeloopback = { "net_chokeloop", "0", 0, 0.0f, nullptr}; cvar_t sv_net_incoming_decompression = { "sv_net_incoming_decompression", "1", 0, 1.0f, nullptr }; -cvar_t sv_net_incoming_decompression_max_ratio = { "sv_net_incoming_decompression_max_ratio", "75.0", 0, 75.0f, nullptr }; +cvar_t sv_net_incoming_decompression_max_ratio = { "sv_net_incoming_decompression_max_ratio", "80.0", 0, 80.0f, nullptr }; cvar_t sv_net_incoming_decompression_max_size = { "sv_net_incoming_decompression_max_size", "65536", 0, 65536.0f, nullptr }; cvar_t sv_net_incoming_decompression_punish = { "sv_net_incoming_decompression_punish", "-1", 0, -1.0f, NULL }; From 3c4acbb046196f2ee05c2d8f1a7eef1740f1276b Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 10 May 2024 17:42:05 +0700 Subject: [PATCH 02/10] Fix warning --- rehlds/engine/sv_upld.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rehlds/engine/sv_upld.cpp b/rehlds/engine/sv_upld.cpp index 425e439e1..eced090b5 100644 --- a/rehlds/engine/sv_upld.cpp +++ b/rehlds/engine/sv_upld.cpp @@ -207,14 +207,13 @@ void SV_Customization(client_t *pPlayer, resource_t *pResource, qboolean bSkipPl // Creates customizations list for the current player and sends resources to other players. void SV_RegisterResources(void) { - resource_t *pResource; client_t *pHost = host_client; pHost->uploading = FALSE; #ifdef REHLDS_FIXES SV_CreateCustomizationList(pHost); // FIXED: Call this function only once. It was crazy to call it for each resource available. #else // REHLDS_FIXES - for (pResource = pHost->resourcesonhand.pNext; pResource != &pHost->resourcesonhand; pResource = pResource->pNext) + for (resource_t *pResource = pHost->resourcesonhand.pNext; pResource != &pHost->resourcesonhand; pResource = pResource->pNext) { SV_CreateCustomizationList(pHost); SV_Customization(pHost, pResource, TRUE); From 47ffe4b257e388fc0cc24d6c2bb2230c961fbfde Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 10 May 2024 17:43:24 +0700 Subject: [PATCH 03/10] Fix rehlsdk --- rehlds/engine/server.h | 7 ------- rehlds/public/rehlds/maintypes.h | 8 ++++++++ rehlds/public/rehlds/rehlds_interfaces.h | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/rehlds/engine/server.h b/rehlds/engine/server.h index c59332e16..cbf31e81c 100644 --- a/rehlds/engine/server.h +++ b/rehlds/engine/server.h @@ -95,13 +95,6 @@ typedef enum redirect_e RD_PACKET = 2, } redirect_t; -typedef enum server_state_e -{ - ss_dead = 0, - ss_loading = 1, - ss_active = 2, -} server_state_t; - typedef struct server_s { qboolean active; diff --git a/rehlds/public/rehlds/maintypes.h b/rehlds/public/rehlds/maintypes.h index b211e2d8c..158a3542e 100644 --- a/rehlds/public/rehlds/maintypes.h +++ b/rehlds/public/rehlds/maintypes.h @@ -67,4 +67,12 @@ typedef enum sv_delta_s sv_packet_delta, } sv_delta_t; +// From engine/server.h +typedef enum server_state_e +{ + ss_dead = 0, + ss_loading = 1, + ss_active = 2, +} server_state_t; + #endif // MAINTYPES_H diff --git a/rehlds/public/rehlds/rehlds_interfaces.h b/rehlds/public/rehlds/rehlds_interfaces.h index da3768c6a..438838c14 100644 --- a/rehlds/public/rehlds/rehlds_interfaces.h +++ b/rehlds/public/rehlds/rehlds_interfaces.h @@ -36,6 +36,7 @@ class IGameClient; #include "common_rehlds.h" #include "userid_rehlds.h" +#include "FileSystem.h" #ifdef REHLDS_SELF #include "server.h" From 693b51c8839847270048be40b62fb1d37f9954ae Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 10 May 2024 18:04:43 +0700 Subject: [PATCH 04/10] Improved behavior of sv_filterban 0. Fixes #1027 --- README.md | 1 + rehlds/engine/sv_main.cpp | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b824c1537..9098f1279 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
  • sv_net_incoming_decompression_max_size <16|65536> // Sets the max allowed size for decompressed file transfer data. Default: 65536 bytes
  • sv_net_incoming_decompression_punish // Time in minutes for which the player will be banned for malformed/abnormal bzip2 fragments (0 - Permanent, use a negative number for a kick). Default: -1
  • sv_tags <comma-delimited string list of tags> // Sets a string defining the "gametags" for this server, this is optional, but if it is set it allows users/scripts to filter in the matchmaking/server-browser interfaces based on the value. Default: "" +
  • sv_filterban <-1|0|1>// Set packet filtering by IP mode. -1 - All players will be rejected without any exceptions. 0 - No checks will happen. 1 - All incoming players will be checked if they're IP banned (if they have an IP filter entry), if they are, they will be kicked. Default: 1 diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index 8f99c0fab..dc2c51727 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -3836,13 +3836,20 @@ void SV_ProcessFile(client_t *cl, char *filename) qboolean SV_FilterPacket(void) { + // sv_filterban filtering IP mode + // -1: all players will be rejected without any exceptions + // 0: no checks will happen + // 1: all incoming players will be checked if they're IP banned (if they have an IP filter entry), if they are, they will be kicked + + qboolean bNegativeFilter = (sv_filterban.value == 1) ? TRUE : FALSE; + for (int i = numipfilters - 1; i >= 0; i--) { ipfilter_t* curFilter = &ipfilters[i]; if (curFilter->compare.u32 == 0xFFFFFFFF || curFilter->banEndTime == 0.0f || curFilter->banEndTime > realtime) { if ((*(uint32*)net_from.ip & curFilter->mask) == curFilter->compare.u32) - return (int)sv_filterban.value; + return bNegativeFilter; } else { @@ -3852,7 +3859,8 @@ qboolean SV_FilterPacket(void) --numipfilters; } } - return sv_filterban.value == 0.0f; + + return !bNegativeFilter; } void SV_SendBan(void) From 82a3d1d08412d53a0f48f01283ea36d38dd905c8 Mon Sep 17 00:00:00 2001 From: Adrian Cirstea <54354938+ShadowsAdi@users.noreply.github.com> Date: Fri, 10 May 2024 14:15:22 +0300 Subject: [PATCH 05/10] Add `SV_SendResources` hook (#1024) * Implement `SV_AddResources` hook --- rehlds/engine/server.h | 1 + rehlds/engine/sv_main.cpp | 5 +++++ rehlds/public/rehlds/rehlds_api.h | 7 ++++++- rehlds/rehlds/rehlds_api_impl.cpp | 4 ++++ rehlds/rehlds/rehlds_api_impl.h | 6 ++++++ rehlds/version/version.h | 2 +- 6 files changed, 23 insertions(+), 2 deletions(-) diff --git a/rehlds/engine/server.h b/rehlds/engine/server.h index cbf31e81c..9446f1461 100644 --- a/rehlds/engine/server.h +++ b/rehlds/engine/server.h @@ -461,6 +461,7 @@ void SV_QueryMovevarsChanged(void); void SV_SendServerinfo(sizebuf_t *msg, client_t *client); void SV_SendServerinfo_internal(sizebuf_t *msg, client_t *client); void SV_SendResources(sizebuf_t *msg); +void SV_SendResources_internal(sizebuf_t *msg); void SV_WriteClientdataToMessage(client_t *client, sizebuf_t *msg); void SV_WriteSpawn(sizebuf_t *msg); void SV_SendUserReg(sizebuf_t *msg); diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index dc2c51727..c015f49a5 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -1199,6 +1199,11 @@ void SV_SendServerinfo_internal(sizebuf_t *msg, client_t *client) } void SV_SendResources(sizebuf_t *msg) +{ + g_RehldsHookchains.m_SV_SendResources.callChain(SV_SendResources_internal, msg); +} + +void EXT_FUNC SV_SendResources_internal(sizebuf_t *msg) { unsigned char nullbuffer[32]; Q_memset(nullbuffer, 0, sizeof(nullbuffer)); diff --git a/rehlds/public/rehlds/rehlds_api.h b/rehlds/public/rehlds/rehlds_api.h index bc8358194..b82f332f3 100644 --- a/rehlds/public/rehlds/rehlds_api.h +++ b/rehlds/public/rehlds/rehlds_api.h @@ -37,7 +37,7 @@ #include "pr_dlls.h" #define REHLDS_API_VERSION_MAJOR 3 -#define REHLDS_API_VERSION_MINOR 13 +#define REHLDS_API_VERSION_MINOR 14 //Steam_NotifyClientConnect hook typedef IHookChain IRehldsHook_Steam_NotifyClientConnect; @@ -259,6 +259,10 @@ typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_ClientPrintf typedef IHookChain IRehldsHook_SV_AllowPhysent; typedef IHookChainRegistry IRehldsHookRegistry_SV_AllowPhysent; +//SV_SendResources hook +typedef IVoidHookChain IRehldsHook_SV_SendResources; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_SendResources; + class IRehldsHookchains { public: virtual ~IRehldsHookchains() { } @@ -318,6 +322,7 @@ class IRehldsHookchains { virtual IRehldsHookRegistry_SV_AddResource* SV_AddResource() = 0; virtual IRehldsHookRegistry_SV_ClientPrintf* SV_ClientPrintf() = 0; virtual IRehldsHookRegistry_SV_AllowPhysent* SV_AllowPhysent() = 0; + virtual IRehldsHookRegistry_SV_SendResources* SV_SendResources() = 0; }; struct RehldsFuncs_t { diff --git a/rehlds/rehlds/rehlds_api_impl.cpp b/rehlds/rehlds/rehlds_api_impl.cpp index 8d7f9dad6..2b4ede0b2 100644 --- a/rehlds/rehlds/rehlds_api_impl.cpp +++ b/rehlds/rehlds/rehlds_api_impl.cpp @@ -885,6 +885,10 @@ IRehldsHookRegistry_SV_AllowPhysent* CRehldsHookchains::SV_AllowPhysent() { return &m_SV_AllowPhysent; } +IRehldsHookRegistry_SV_SendResources* CRehldsHookchains::SV_SendResources() { + return &m_SV_SendResources; +} + int EXT_FUNC CRehldsApi::GetMajorVersion() { return REHLDS_API_VERSION_MAJOR; diff --git a/rehlds/rehlds/rehlds_api_impl.h b/rehlds/rehlds/rehlds_api_impl.h index 699bd1649..6aece98cf 100644 --- a/rehlds/rehlds/rehlds_api_impl.h +++ b/rehlds/rehlds/rehlds_api_impl.h @@ -254,6 +254,10 @@ typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_SV_ClientPri typedef IHookChainImpl CRehldsHook_SV_AllowPhysent; typedef IHookChainRegistryImpl CRehldsHookRegistry_SV_AllowPhysent; +//SV_SendResources hook +typedef IVoidHookChainImpl CRehldsHook_SV_SendResources; +typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_SV_SendResources; + class CRehldsHookchains : public IRehldsHookchains { public: CRehldsHookRegistry_Steam_NotifyClientConnect m_Steam_NotifyClientConnect; @@ -311,6 +315,7 @@ class CRehldsHookchains : public IRehldsHookchains { CRehldsHookRegistry_SV_AddResource m_SV_AddResource; CRehldsHookRegistry_SV_ClientPrintf m_SV_ClientPrintf; CRehldsHookRegistry_SV_AllowPhysent m_SV_AllowPhysent; + CRehldsHookRegistry_SV_SendResources m_SV_SendResources; public: EXT_FUNC virtual IRehldsHookRegistry_Steam_NotifyClientConnect* Steam_NotifyClientConnect(); @@ -368,6 +373,7 @@ class CRehldsHookchains : public IRehldsHookchains { EXT_FUNC virtual IRehldsHookRegistry_SV_AddResource* SV_AddResource(); EXT_FUNC virtual IRehldsHookRegistry_SV_ClientPrintf* SV_ClientPrintf(); EXT_FUNC virtual IRehldsHookRegistry_SV_AllowPhysent* SV_AllowPhysent(); + EXT_FUNC virtual IRehldsHookRegistry_SV_SendResources* SV_SendResources(); }; extern CRehldsHookchains g_RehldsHookchains; diff --git a/rehlds/version/version.h b/rehlds/version/version.h index 55a454b1e..3bed179d4 100644 --- a/rehlds/version/version.h +++ b/rehlds/version/version.h @@ -6,5 +6,5 @@ #pragma once #define VERSION_MAJOR 3 -#define VERSION_MINOR 13 +#define VERSION_MINOR 14 #define VERSION_MAINTENANCE 0 From a761efa75df820ebf5fb4899e863ce41fda099bd Mon Sep 17 00:00:00 2001 From: s1lentq Date: Mon, 13 May 2024 18:48:35 +0700 Subject: [PATCH 06/10] Minor cleanup --- rehlds/common/quakedef.h | 3 +++ rehlds/engine/pr_cmds.cpp | 5 +++-- rehlds/engine/sv_main.cpp | 8 +++++++- rehlds/engine/usermsg.h | 5 ++++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/rehlds/common/quakedef.h b/rehlds/common/quakedef.h index 21f88e21b..17f166d95 100644 --- a/rehlds/common/quakedef.h +++ b/rehlds/common/quakedef.h @@ -29,6 +29,9 @@ typedef int BOOL; +// The maximum user messages +#define MAX_USERMESSAGES 256 + // user message #define MAX_USER_MSG_DATA 192 diff --git a/rehlds/engine/pr_cmds.cpp b/rehlds/engine/pr_cmds.cpp index dfd284683..d53a74bc7 100644 --- a/rehlds/engine/pr_cmds.cpp +++ b/rehlds/engine/pr_cmds.cpp @@ -2124,7 +2124,7 @@ void EXT_FUNC PF_MessageBegin_I(int msg_dest, int msg_type, const float *pOrigin if (msg_type == 0) Sys_Error("%s: Tried to create a message with a bogus message type ( 0 )", __func__); - gMsgStarted = 1; + gMsgStarted = TRUE; gMsgType = msg_type; gMsgEntity = ed; gMsgDest = msg_dest; @@ -2151,7 +2151,7 @@ void EXT_FUNC PF_MessageEnd_I(void) qboolean MsgIsVarLength = 0; if (!gMsgStarted) Sys_Error("%s: called with no active message\n", __func__); - gMsgStarted = 0; + gMsgStarted = FALSE; if (gMsgEntity && (gMsgEntity->v.flags & FL_FAKECLIENT)) return; @@ -2275,6 +2275,7 @@ void EXT_FUNC PF_WriteByte_I(int iValue) { if (!gMsgStarted) Sys_Error("%s: called with no active message\n", __func__); + MSG_WriteByte(&gMsgBuffer, iValue); } diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index c015f49a5..5dd76f27a 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -6568,7 +6568,13 @@ void SV_ClearEntities(void) } int EXT_FUNC RegUserMsg(const char *pszName, int iSize) { - if (giNextUserMsg > 255 || !pszName || Q_strlen(pszName) > 11 || iSize > 192) + if (giNextUserMsg >= MAX_USERMESSAGES) + return 0; + + if (iSize > MAX_USER_MSG_DATA) + return 0; + + if (!pszName || Q_strlen(pszName) >= MAX_USERMESSAGES_LENGTH - 1) return 0; UserMsg *pUserMsgs = sv_gpUserMsgs; diff --git a/rehlds/engine/usermsg.h b/rehlds/engine/usermsg.h index ffff648dd..b75205576 100644 --- a/rehlds/engine/usermsg.h +++ b/rehlds/engine/usermsg.h @@ -31,11 +31,14 @@ #include "maintypes.h" #include "quakedef.h" +// The maximum length of a usermessage name in a network transmission +#define MAX_USERMESSAGES_LENGTH 16 + typedef struct _UserMsg { int iMsg; int iSize; - char szName[16]; + char szName[MAX_USERMESSAGES_LENGTH]; struct _UserMsg *next; pfnUserMsgHook pfn; } UserMsg; From c9f9bbfff98cdb6e8ca45b9ab626f40d0c7bb22b Mon Sep 17 00:00:00 2001 From: s1lentq Date: Mon, 13 May 2024 19:20:19 +0700 Subject: [PATCH 07/10] Implement API interface game message manager --- rehlds/CMakeLists.txt | 1 + rehlds/engine/sys_dll.cpp | 4 + rehlds/msvc/ReHLDS.vcxproj | 3 + rehlds/msvc/ReHLDS.vcxproj.filters | 9 + rehlds/public/rehlds/IMessageManager.h | 223 ++++++++++ rehlds/public/rehlds/rehlds_api.h | 2 + rehlds/rehlds/hookchains_impl.cpp | 4 + rehlds/rehlds/hookchains_impl.h | 12 +- rehlds/rehlds/precompiled.h | 1 + rehlds/rehlds/rehlds_api_impl.cpp | 4 + rehlds/rehlds/rehlds_api_impl.h | 1 + rehlds/rehlds/rehlds_messagemngr_impl.cpp | 508 ++++++++++++++++++++++ rehlds/rehlds/rehlds_messagemngr_impl.h | 277 ++++++++++++ 13 files changed, 1048 insertions(+), 1 deletion(-) create mode 100644 rehlds/public/rehlds/IMessageManager.h create mode 100644 rehlds/rehlds/rehlds_messagemngr_impl.cpp create mode 100644 rehlds/rehlds/rehlds_messagemngr_impl.h diff --git a/rehlds/CMakeLists.txt b/rehlds/CMakeLists.txt index a9b371b28..e48e87d16 100644 --- a/rehlds/CMakeLists.txt +++ b/rehlds/CMakeLists.txt @@ -182,6 +182,7 @@ set(ENGINE_SRCS rehlds/public_amalgamation.cpp rehlds/rehlds_api_impl.cpp rehlds/rehlds_interfaces_impl.cpp + rehlds/rehlds_messagemngr_impl.cpp rehlds/rehlds_security.cpp ) diff --git a/rehlds/engine/sys_dll.cpp b/rehlds/engine/sys_dll.cpp index 08431a490..ddfcef34d 100644 --- a/rehlds/engine/sys_dll.cpp +++ b/rehlds/engine/sys_dll.cpp @@ -1083,6 +1083,10 @@ void LoadThisDll(const char *szDllFilename) goto IgnoreThisDLL; } +#ifdef REHLDS_API + MessageManager().Init(); +#endif + pfnGiveFnptrsToDll(&g_engfuncsExportedToDlls, &gGlobalVariables); if (g_iextdllMac == MAX_EXTENSION_DLL) { diff --git a/rehlds/msvc/ReHLDS.vcxproj b/rehlds/msvc/ReHLDS.vcxproj index dc153551e..6b2a50bce 100644 --- a/rehlds/msvc/ReHLDS.vcxproj +++ b/rehlds/msvc/ReHLDS.vcxproj @@ -119,6 +119,7 @@ + @@ -386,6 +387,7 @@ + @@ -439,6 +441,7 @@ + diff --git a/rehlds/msvc/ReHLDS.vcxproj.filters b/rehlds/msvc/ReHLDS.vcxproj.filters index a59f265d8..9d0731a25 100644 --- a/rehlds/msvc/ReHLDS.vcxproj.filters +++ b/rehlds/msvc/ReHLDS.vcxproj.filters @@ -341,6 +341,9 @@ testsuite + + rehlds + @@ -1060,5 +1063,11 @@ testsuite + + rehlds + + + public\rehlds + \ No newline at end of file diff --git a/rehlds/public/rehlds/IMessageManager.h b/rehlds/public/rehlds/IMessageManager.h new file mode 100644 index 000000000..cf818dbc2 --- /dev/null +++ b/rehlds/public/rehlds/IMessageManager.h @@ -0,0 +1,223 @@ +/* +* +* 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 +* +*/ + +#pragma once + +/** + * @brief Interface for defining message parameters and behavior for a individual message object + */ +class IMessage +{ +public: + /** + * @brief The parameter types for a message + */ + enum class ParamType : uint8 + { + Byte, + Char, + Short, + Long, + Angle, + Coord, + String, + Entity, + }; + + /** + * @brief Blocking behavior types for messages + */ + enum class BlockType : uint8 + { + Not, // Not a block + Once, // Block once + Set // Set block + }; + + /** + * @brief Message destinations + */ + enum class Dest : uint8 + { + BROADCAST, // Unreliable to all + ONE, // Reliable to one (msg_entity) + ALL, // Reliable to all + INIT, // Write to the init string + PVS, // Ents in PVS of org + PAS, // Ents in PAS of org + PVS_R, // Reliable to PVS + PAS_R, // Reliable to PAS + ONE_UNRELIABLE, // Send to one client, but don't put in reliable stream, put in unreliable datagram + SPEC, // Sends to all spectator proxies + }; + + virtual ~IMessage() {}; + + /** + * @brief Returns the number of parameters in the message + * @return The number of parameters + */ + virtual int getParamCount() const = 0; + + /** + * @brief Returns the type of the parameter at the given index + * @param index The index of the parameter + * @return The type of the parameter + */ + virtual ParamType getParamType(size_t index) const = 0; + + /** + * @brief Returns the integer value of the parameter at the given index + * @param index The index of the parameter + * @return The integer value of the parameter + */ + virtual int getParamInt(size_t index) const = 0; + + /** + * @brief Returns the float value of the parameter at the given index + * @param index The index of the parameter + * @return The float value of the parameter + */ + virtual float getParamFloat(size_t index) const = 0; + + /** + * @brief Returns the string value of the parameter at the given index + * @param index The index of the parameter + * @return The string value of the parameter + */ + virtual const char* getParamString(size_t index) const = 0; + + /** + * @brief Sets the integer value of the parameter at the given index + * @param index The index of the parameter + * @param value The integer value to set + */ + virtual void setParamInt(size_t index, int value) = 0; + + /** + * @brief Sets the float value of the parameter at the given index + * @param index The index of the parameter + * @param value The float value to set + */ + virtual void setParamFloat(size_t index, float value) = 0; + + /** + * @brief Sets the vector value of the parameter at the given index + * @param index The index of the parameter + * @param pos The vector value to set + */ + virtual void setParamVec(size_t index, const float *pos) = 0; + + /** + * @brief Sets the string value of the parameter at the given index + * @param index The index of the parameter + * @param string The string value to set + */ + virtual void setParamString(size_t index, const char *string) = 0; + + /** + * @brief Returns the destination of the message + * @return The destination of the message + */ + virtual Dest getDest() const = 0; + + /** + * @brief Returns the type of the message + * @return The type of the message + */ + virtual int getType() const = 0; + + /** + * @brief Returns the origin of the message + * @return The origin of the message + */ + virtual const float* getOrigin() const = 0; + + /** + * @brief Returns the edict associated with the message + * @return The edict associated with the message + */ + virtual struct edict_s* getEdict() const = 0; + + /** + * @brief Returns whether the message has been modified + * @return True if the message has been modified, false otherwise + */ + virtual bool isModified() const = 0; + + // This must be the last virtual function in class +#ifdef REHLDS_SELF + // Set the copyback buffer for the message + virtual void setCopybackBuffer(struct sizebuf_s *pbuf) = 0; +#endif +}; + +#define MESSAGEMNGR_VERSION_MAJOR 1 +#define MESSAGEMNGR_VERSION_MINOR 0 + +/** + * @brief Interface manages hooks and blocking behavior game messages + */ +class IMessageManager +{ +public: + using hookfunc_t = void (*)(IVoidHookChain *chain, IMessage *msg); + + virtual ~IMessageManager() {}; + + /** + * @brief Returns the major version of the MessageManager + * @return The major version + */ + virtual int getMajorVersion() const = 0; + + /** + * @brief Returns the minor version of the MessageManager + * @return The minor version + */ + virtual int getMinorVersion() const = 0; + + /** + * @brief Returns the blocking behavior for the given message type + * @param msgType The message type + * @return The blocking behavior for the given message type + */ + virtual IMessage::BlockType getMessageBlock(int msgType) const = 0; + + /** + * @brief Sets the blocking behavior for the given message type + * @param msgType The message type + * @param blockType The blocking behavior to set + */ + virtual void setMessageBlock(int msgType, IMessage::BlockType blockType) = 0; + + /** + * @brief Registers a hook function for the given message type + * @param msgType The message type to register the hook for + * @param handler The hook function to register + * @param priority The priority of the hook function (see enum HookChainPriority) + */ + virtual void registerHook(int msgType, hookfunc_t handler, int priority = HC_PRIORITY_DEFAULT) = 0; + + /** + * @brief Unregisters a hook function for the given message type + * @param msgType The message type to unregister the hook for + * @param handler The hook function to unregister + */ + virtual void unregisterHook(int msgType, hookfunc_t handler) = 0; +}; diff --git a/rehlds/public/rehlds/rehlds_api.h b/rehlds/public/rehlds/rehlds_api.h index b82f332f3..743e47d21 100644 --- a/rehlds/public/rehlds/rehlds_api.h +++ b/rehlds/public/rehlds/rehlds_api.h @@ -31,6 +31,7 @@ #include "rehlds_interfaces.h" #include "hookchains.h" #include "FlightRecorder.h" +#include "IMessageManager.h" #include "interface.h" #include "model.h" #include "ObjectList.h" @@ -446,6 +447,7 @@ class IRehldsApi { virtual IRehldsServerStatic* GetServerStatic() = 0; virtual IRehldsServerData* GetServerData() = 0; virtual IRehldsFlightRecorder* GetFlightRecorder() = 0; + virtual IMessageManager *GetMessageManager() = 0; }; #define VREHLDS_HLDS_API_VERSION "VREHLDS_HLDS_API_VERSION001" diff --git a/rehlds/rehlds/hookchains_impl.cpp b/rehlds/rehlds/hookchains_impl.cpp index 13f6e36e6..eaa49fcc7 100644 --- a/rehlds/rehlds/hookchains_impl.cpp +++ b/rehlds/rehlds/hookchains_impl.cpp @@ -90,3 +90,7 @@ void AbstractHookChainRegistry::removeHook(void* hookFunc) { } } } + +int AbstractHookChainRegistry::getCount() const { + return m_NumHooks; +} diff --git a/rehlds/rehlds/hookchains_impl.h b/rehlds/rehlds/hookchains_impl.h index dd2523c91..0ab780097 100644 --- a/rehlds/rehlds/hookchains_impl.h +++ b/rehlds/rehlds/hookchains_impl.h @@ -109,10 +109,11 @@ class AbstractHookChainRegistry { protected: void addHook(void* hookFunc, int priority); - bool findHook(void* hookFunc) const; void removeHook(void* hookFunc); public: + int getCount() const; + bool findHook(void* hookFunc) const; AbstractHookChainRegistry(); }; @@ -132,9 +133,14 @@ class IHookChainRegistryImpl : public IHookChainRegistry < t_ret, t_args...>, pu EXT_FUNC virtual void registerHook(hookfunc_t hook, int priority) { addHook((void*)hook, priority); } + EXT_FUNC virtual void unregisterHook(hookfunc_t hook) { removeHook((void*)hook); } + + bool isEmpty() const { + return getCount() == 0; + } }; template @@ -157,4 +163,8 @@ class IVoidHookChainRegistryImpl : public IVoidHookChainRegistry , pu EXT_FUNC virtual void unregisterHook(hookfunc_t hook) { removeHook((void*)hook); } + + bool isEmpty() const { + return getCount() == 0; + } }; diff --git a/rehlds/rehlds/precompiled.h b/rehlds/rehlds/precompiled.h index de99a0301..a947fcf29 100644 --- a/rehlds/rehlds/precompiled.h +++ b/rehlds/rehlds/precompiled.h @@ -49,6 +49,7 @@ #include "rehlds_api_impl.h" #include "FlightRecorderImpl.h" #include "flight_recorder.h" +#include "rehlds_messagemngr_impl.h" #include "rehlds_security.h" #include "dlls/cdll_dll.h" diff --git a/rehlds/rehlds/rehlds_api_impl.cpp b/rehlds/rehlds/rehlds_api_impl.cpp index 2b4ede0b2..62a392070 100644 --- a/rehlds/rehlds/rehlds_api_impl.cpp +++ b/rehlds/rehlds/rehlds_api_impl.cpp @@ -917,6 +917,10 @@ IRehldsServerData* EXT_FUNC CRehldsApi::GetServerData() { return &g_RehldsServerData; } +IMessageManager* EXT_FUNC CRehldsApi::GetMessageManager() { + return &MessageManager(); +} + IRehldsFlightRecorder* EXT_FUNC CRehldsApi::GetFlightRecorder() { return g_FlightRecorder; } diff --git a/rehlds/rehlds/rehlds_api_impl.h b/rehlds/rehlds/rehlds_api_impl.h index 6aece98cf..cda2b5a13 100644 --- a/rehlds/rehlds/rehlds_api_impl.h +++ b/rehlds/rehlds/rehlds_api_impl.h @@ -391,6 +391,7 @@ class CRehldsApi : public IRehldsApi { virtual IRehldsServerStatic* GetServerStatic(); virtual IRehldsServerData* GetServerData(); virtual IRehldsFlightRecorder* GetFlightRecorder(); + virtual IMessageManager* GetMessageManager(); }; extern sizebuf_t* GetNetMessage_api(); diff --git a/rehlds/rehlds/rehlds_messagemngr_impl.cpp b/rehlds/rehlds/rehlds_messagemngr_impl.cpp new file mode 100644 index 000000000..617ceb1a7 --- /dev/null +++ b/rehlds/rehlds/rehlds_messagemngr_impl.cpp @@ -0,0 +1,508 @@ +/* +* +* 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" + +// Constructs a Message object +MessageImpl::MessageImpl() +{ + m_buffer.buffername = "MessageManager/Begin/End"; + m_buffer.data = m_bufferData; + m_buffer.flags = SIZEBUF_ALLOW_OVERFLOW; + m_buffer.cursize = 0; + m_buffer.maxsize = sizeof(m_bufferData); + + m_paramCount = 0; +} + +// Sets the active state of the message with the given parameters +void MessageImpl::setActive(int dest, int type, const float *origin, edict_t *edict) +{ + m_dest = static_cast(dest); + m_type = type; + m_edict = edict; + + // Reset buffer size + m_buffer.flags = SIZEBUF_ALLOW_OVERFLOW; + m_buffer.cursize = 0; + + // Copy origin vector if provided + if (origin) + VectorCopy(origin, m_origin); + else + VectorClear(m_origin); +} + +// Sets the buffer for the message +void MessageImpl::setBuffer(sizebuf_t *pbuf) +{ + // Copy data from the provided buffer to the message buffer + memcpy(m_buffer.data, pbuf->data, pbuf->cursize); + m_buffer.cursize = pbuf->cursize; +} + +// Sets the copyback buffer for the message +void MessageImpl::setCopybackBuffer(sizebuf_t *pbuf) +{ + // Copy data from the message buffer back to the provided buffer + memcpy(pbuf->data, m_buffer.data, m_buffer.cursize); + pbuf->cursize = m_buffer.cursize; +} + +// Clears the message parameters +void MessageImpl::clear() +{ + m_paramCount = 0; +} + +// An array containing fixed sizes for various types of parameters +static size_t SIZEOF_PARAMTYPE[] = +{ + sizeof(uint8), // Byte + sizeof(int8), // Char + sizeof(int16), // Short + sizeof(uint32), // Long + sizeof(uint8), // Angle + sizeof(int16), // Coord + 0, // String + sizeof(int16), // Entity +}; + +// Adds a parameter to the message +void MessageImpl::addParam(IMessage::ParamType type, size_t length) +{ + Param_t ¶m = m_params[m_paramCount++]; + param.type = type; + param.len = (length == -1) ? SIZEOF_PARAMTYPE[static_cast(type)] : length; + param.pos = gMsgBuffer.cursize; +} + +// Sets the value of a primitive parameter at the given index +template +void MessageImpl::setParamPrimitive(size_t index, T value) +{ + // Ensure index is within bounds + if (index < 0 || index >= m_paramCount) + return; + + const Param_t ¶m = m_params[index]; + + void *pbuf = m_buffer.data + param.pos; + + // Set value based on parameter type + switch (param.type) + { + case IMessage::ParamType::Byte: + *(uint8 *)pbuf = value; + break; + case IMessage::ParamType::Char: + *(int8 *)pbuf = value; + break; + case IMessage::ParamType::Short: + case IMessage::ParamType::Entity: + *(int16 *)pbuf = value; + break; + case IMessage::ParamType::Long: + *(uint16 *)pbuf = value; + break; + case IMessage::ParamType::Angle: + // Convert angle value to byte representation with loss of precision + *(uint8 *)pbuf = (int64)(fmod((double)value, 360.0) * 256.0 / 360.0) & 0xff; + break; + case IMessage::ParamType::Coord: + // Convert coordinate value to short integer representation with loss of precision + *(int16 *)pbuf = (int16)(int)(value * 8.0); + break; + default: + return; // bad type + } + + // Mark message as modified + m_modified = true; +} + +// Transforms the buffer after setting a string parameter at the given index +void MessageImpl::setTxformBuffer(size_t index, size_t startPos, size_t oldLength, size_t newLength) +{ + // Calculate the difference in length + int32_t diffLength = newLength - oldLength; + if (diffLength != 0) + { + // Check if the buffer size limit will be exceeded + if (m_buffer.cursize + diffLength > m_buffer.maxsize) + { + Sys_Error( + "%s: Refusing to transform string with %i param of user message of %i bytes, " + "user message size limit is %i bytes\n", __func__, index, gMsgBuffer.cursize + diffLength, gMsgBuffer.maxsize); + } + + // Move the data in the buffer + size_t moveLength = m_buffer.cursize - (startPos + oldLength); + Q_memmove(m_buffer.data + startPos + newLength, m_buffer.data + startPos + oldLength, moveLength); + m_buffer.cursize += diffLength; + + // Update the position of all subsequent parameters + for (size_t i = index + 1; i < m_paramCount; i++) + m_params[i].pos += diffLength; + } +} + +// Returns the integer value of the parameter at the given index +int MessageImpl::getParamInt(size_t index) const +{ + // Ensure index is within bounds + if (index < 0 || index >= m_paramCount) + return 0; + + // Get the parameter value based on its type + void *buf = m_buffer.data + m_params[index].pos; + switch (m_params[index].type) + { + case IMessage::ParamType::Byte: + return *(uint8 *)buf; + case IMessage::ParamType::Char: + return *(int8 *)buf; + case IMessage::ParamType::Short: + case IMessage::ParamType::Entity: + return *(int16 *)buf; + case IMessage::ParamType::Long: + return *(uint16 *)buf; + default: + return 0; // bad type + } +} + +// Returns the float value of the parameter at the given index +float MessageImpl::getParamFloat(size_t index) const +{ + // Ensure index is within bounds + if (index < 0 || index >= m_paramCount) + return 0; + + // Get the parameter value based on its type + const Param_t ¶m = m_params[index]; + void *buf = m_buffer.data + param.pos; + switch (param.type) + { + case IMessage::ParamType::Angle: + return (float)(*(uint8 *)buf * (360.0 / 256.0)); + case IMessage::ParamType::Coord: + return (float)(*(int16 *)buf * (1.0 / 8)); + default: + break; // bad type + } + + return 0; +} + +// Returns the string value of the parameter at the given index +const char *MessageImpl::getParamString(size_t index) const +{ + // Ensure index is within bounds + if (index < 0 || index >= m_paramCount) + return nullptr; + + // Get the parameter value if it is a string + const Param_t ¶m = m_params[index]; + if (param.type == IMessage::ParamType::String) + return (const char *)m_buffer.data + param.pos; + + return nullptr; +} + +// Sets the integer value of the parameter at the given index +void MessageImpl::setParamInt(size_t index, int value) +{ + setParamPrimitive(index, value); +} + +// Sets the float value of the parameter at the given index +void MessageImpl::setParamFloat(size_t index, float value) +{ + setParamPrimitive(index, value); +} + +// Sets the vector value of the parameter at the given index +void MessageImpl::setParamVec(size_t index, const float *pos) +{ + if (!pos) + return; + + // Ensure index is within bounds + if (index < 0 || (index + 3) >= m_paramCount) + return; + + // Get the parameter position in the buffer + const Param_t ¶m = m_params[index]; + + int16 *pbuf = (int16 *)m_buffer.data + param.pos; + + // Set each component of the vector parameter + *(int16 *)pbuf++ = (int16)(pos[0] * 8.0); + *(int16 *)pbuf++ = (int16)(pos[1] * 8.0); + *(int16 *)pbuf++ = (int16)(pos[2] * 8.0); + + // Mark message as modified + m_modified = true; +} + +// Sets the string value of the parameter at the given index +void MessageImpl::setParamString(size_t index, const char *value) +{ + if (!value) + return; + + // Ensure index is within bounds + if (index < 0 || index >= m_paramCount) + return; + + // Calculate the length of the string + size_t length = Q_strlen(value) + 1; + const Param_t ¶m = m_params[index]; + + // Transform buffer to accommodate the new string length + setTxformBuffer(index, param.pos, param.len, length); + + // Copy the string value to the buffer + memcpy(m_buffer.data + param.pos, value, length); + + // Mark message as modified + m_modified = true; +} + +MessageManagerImpl::MessageManagerImpl() +{ + m_inblock = false; + m_inhook = false; +} + +// Register hook function for the game message type +void MessageManagerImpl::registerHook(int msgType, hookfunc_t handler, int priority) +{ + m_hooks[msgType].registerHook(handler, priority); +} + +// Unregister hook function for the game message type +void MessageManagerImpl::unregisterHook(int msgType, hookfunc_t handler) +{ + m_hooks[msgType].unregisterHook(handler); +} + +// Get the block type for the game message type +IMessage::BlockType MessageManagerImpl::getMessageBlock(int msgType) const +{ + return m_blocks[msgType]; +} + +// Set the block type for the game message type +void MessageManagerImpl::setMessageBlock(int msgType, IMessage::BlockType blockType) +{ + m_blocks[msgType] = blockType; +} + +bool MessageManagerImpl::MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) +{ + // Check if the message type is blocked + if (m_blocks[msg_type] != IMessage::BlockType::Not) + { + m_inblock = true; + return false; + } + + // Check if there are hooks registered for the message type + m_inhook = m_hooks[msg_type].getCount() > 0; + + if (m_inhook) + { + // Check for stack overflow + if (m_stack.size() >= m_stack.max_size() - 1) + Sys_Error("%s: stack overflow in #%i user message.\nIndicate potential recursive calls...\n", __func__, msg_type); + + // Push a new game message onto the stack + m_stack.push(); + + // Initialize the message + MessageImpl &msg = m_stack.back(); + msg.setActive(msg_dest, msg_type, pOrigin, ed); + } + + return true; +} + +static void EXT_FUNC SendUserMessageData(IMessage *msg) +{ + // Set global variables with message data + gMsgType = msg->getType(); + gMsgEntity = msg->getEdict(); + gMsgDest = static_cast(msg->getDest()); + + gMsgOrigin[0] = msg->getOrigin()[0]; + gMsgOrigin[1] = msg->getOrigin()[1]; + gMsgOrigin[2] = msg->getOrigin()[2]; + + gMsgStarted = TRUE; + + // Copy message data to global buffer and call end of the hookchain + msg->setCopybackBuffer(&gMsgBuffer); + PF_MessageEnd_I(); +} + +bool MessageManagerImpl::MessageEnd() +{ + // Check if in block mode + if (m_inblock) + { + m_inblock = false; + + // Unblock the message type if it was blocked once + if (m_blocks[gMsgType] == IMessage::BlockType::Once) + m_blocks[gMsgType] = IMessage::BlockType::Not; + + return false; + } + + // Check if not in hook + if (!m_inhook) + return true; + + gMsgStarted = FALSE; + + // Get the message from the top of the stack + MessageImpl &msg = m_stack.back(); + + // Set buffer from global buffer and call hookchain + msg.setBuffer(&gMsgBuffer); + m_hooks[msg.getType()].callChain(SendUserMessageData, &msg); + m_inhook = false; + + // Clear the message and pop from the stack + msg.clear(); + m_stack.pop(); + + return false; +} + +bool MessageManagerImpl::WriteParam(IMessage::ParamType type, size_t length) +{ + // Check if in block mode + if (m_inblock) + return false; + + // Check if in hook mode + if (m_inhook) + { + // Add parameter to top stack message + MessageImpl &msg = m_stack.back(); + msg.addParam(type, length); + } + + return true; +} + +// +// Functions intercept to handle messages +// + +void EXT_FUNC PF_MessageBegin_Intercept(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) +{ + // Set global message type + gMsgType = msg_type; + + // Begin message manager + if (MessageManager().MessageBegin(msg_dest, msg_type, pOrigin, ed)) + PF_MessageBegin_I(msg_dest, msg_type, pOrigin, ed); +} + +void EXT_FUNC PF_MessageEnd_Intercept(void) +{ + // End message manager + if (MessageManager().MessageEnd()) + PF_MessageEnd_I(); // Call original message end function if the manager allows it +} + +void EXT_FUNC PF_WriteByte_Intercept(int iValue) +{ + // Write byte parameter to the message if the manager allows it + if (MessageManager().WriteParam(IMessage::ParamType::Byte)) + PF_WriteByte_I(iValue); +} + +void EXT_FUNC PF_WriteChar_Intercept(int iValue) +{ + if (MessageManager().WriteParam(IMessage::ParamType::Char)) + PF_WriteChar_I(iValue); +} + +void EXT_FUNC PF_WriteShort_Intercept(int iValue) +{ + if (MessageManager().WriteParam(IMessage::ParamType::Short)) + PF_WriteShort_I(iValue); +} + +void EXT_FUNC PF_WriteLong_Intercept(int iValue) +{ + if (MessageManager().WriteParam(IMessage::ParamType::Long)) + PF_WriteLong_I(iValue); +} + +void EXT_FUNC PF_WriteAngle_Intercept(float flValue) +{ + if (MessageManager().WriteParam(IMessage::ParamType::Angle)) + PF_WriteAngle_I(flValue); +} + +void EXT_FUNC PF_WriteCoord_Intercept(float flValue) +{ + if (MessageManager().WriteParam(IMessage::ParamType::Coord)) + PF_WriteCoord_I(flValue); +} + +void EXT_FUNC PF_WriteString_Intercept(const char *sz) +{ + if (MessageManager().WriteParam(IMessage::ParamType::String, sz ? Q_strlen(sz) + 1 : 1)) + PF_WriteString_I(sz); +} + +void EXT_FUNC PF_WriteEntity_Intercept(int iValue) +{ + if (MessageManager().WriteParam(IMessage::ParamType::Entity)) + PF_WriteEntity_I(iValue); +} + +// Initialization function to set up function interception +void MessageManagerImpl::Init() +{ + // Set function callback to intercept functions + g_engfuncsExportedToDlls.pfnMessageBegin = PF_MessageBegin_Intercept; + g_engfuncsExportedToDlls.pfnWriteByte = PF_WriteByte_Intercept; + g_engfuncsExportedToDlls.pfnWriteChar = PF_WriteChar_Intercept; + g_engfuncsExportedToDlls.pfnWriteShort = PF_WriteShort_Intercept; + g_engfuncsExportedToDlls.pfnWriteLong = PF_WriteLong_Intercept; + g_engfuncsExportedToDlls.pfnWriteAngle = PF_WriteAngle_Intercept; + g_engfuncsExportedToDlls.pfnWriteCoord = PF_WriteCoord_Intercept; + g_engfuncsExportedToDlls.pfnWriteString = PF_WriteString_Intercept; + g_engfuncsExportedToDlls.pfnWriteEntity = PF_WriteEntity_Intercept; + g_engfuncsExportedToDlls.pfnMessageEnd = PF_MessageEnd_Intercept; +} + +MessageManagerImpl &MessageManager() +{ + // Instance of the message manager singleton + static MessageManagerImpl instance{}; + return instance; +} diff --git a/rehlds/rehlds/rehlds_messagemngr_impl.h b/rehlds/rehlds/rehlds_messagemngr_impl.h new file mode 100644 index 000000000..b0ad18cb8 --- /dev/null +++ b/rehlds/rehlds/rehlds_messagemngr_impl.h @@ -0,0 +1,277 @@ +/* +* +* 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 +* +*/ + +#pragma once + +#include "IMessageManager.h" +#include "hookchains.h" + +/** + * @brief Implementation interface for defining message parameters and behavior for a game message object + */ +class MessageImpl: public IMessage +{ +public: + MessageImpl(); + ~MessageImpl() = default; + + /** + * @brief Returns the number of parameters in the message + * @return The number of parameters + */ + int getParamCount() const { return m_paramCount; } + + /** + * @brief Returns the type of the parameter at the given index + * @param index The index of the parameter + * @return The type of the parameter + */ + ParamType getParamType(size_t index) const { return m_params[index].type; } + + /** + * @brief Returns the integer value of the parameter at the given index + * @param index The index of the parameter + * @return The integer value of the parameter + */ + int getParamInt(size_t index) const; + + /** + * @brief Returns the float value of the parameter at the given index + * @param index The index of the parameter + * @return The float value of the parameter + */ + float getParamFloat(size_t index) const; + + /** + * @brief Returns the string value of the parameter at the given index + * @param index The index of the parameter + * @return The string value of the parameter + */ + const char *getParamString(size_t index) const; + + /** + * @brief Sets the integer value of the parameter at the given index + * @param index The index of the parameter + * @param value The integer value to set + */ + void setParamInt(size_t index, int value); + + /** + * @brief Sets the float value of the parameter at the given index + * @param index The index of the parameter + * @param value The float value to set + */ + void setParamFloat(size_t index, float value); + + /** + * @brief Sets the vector value of the parameter at the given index + * @param index The index of the parameter + * @param pos The vector value to set + */ + void setParamVec(size_t index, const float *pos); + + /** + * @brief Sets the string value of the parameter at the given index + * @param index The index of the parameter + * @param string The string value to set + */ + void setParamString(size_t index, const char *string); + + /** + * @brief Returns the destination of the message + * @return The destination of the message + */ + Dest getDest() const { return m_dest; } + + /** + * @brief Returns the type of the message + * @return The type of the message + */ + int getType() const { return m_type; } + + /** + * @brief Returns the origin of the message + * @return The origin of the message + */ + const float *getOrigin() const { return m_origin; } + + /** + * @brief Returns the edict associated with the message + * @return The edict associated with the message + */ + edict_t *getEdict() const { return m_edict; } + + /** + * @brief Returns whether the message has been modified + * @return True if the message has been modified, false otherwise + */ + bool isModified() const { return m_modified; } + +private: + + friend class MessageManagerImpl; + + // Sets the active state of the message with the given parameters + void setActive(int dest, int type, const float *origin, edict_t *edict); + + // Sets the buffer for the message + void setBuffer(sizebuf_t *pbuf); + + // Set the copyback buffer for the message + void setCopybackBuffer(sizebuf_t *pbuf); + + // Adds a parameter to the message + void addParam(IMessage::ParamType type, size_t length); + + // Clears the message after execution + void clear(); + + template + void setParamPrimitive(size_t index, T value); + + // Transforms buffer after sets string for a parameter at the given index + void setTxformBuffer(size_t index, size_t startPos, size_t oldLength, size_t newLength); + + bool m_modified; // Flag indicating whether the message has been modified + Dest m_dest; // The destination of the message + int m_type; // The type of the message + float m_origin[3]; // The origin of the message + edict_t* m_edict; // The edict associated with the message + + uint8 m_bufferData[512]; // The buffer data for the message 'm_buffer' + sizebuf_t m_buffer; // The buffer for the message + + struct Param_t + { + ParamType type; // The type of the parameter + size_t pos; // The position of the parameter in the buffer + size_t len; // The length of the parameter in the buffer + }; + + static const size_t MAX_PARAMS = 16; // The maximum number of parameters allowed in the message + Param_t m_params[MAX_PARAMS]; // The array of parameters in the message + size_t m_paramCount; // The number of parameters in the message +}; + +/** + * @brief Implementation interface manages hooks and blocking behavior game messages + */ +class MessageManagerImpl: public IMessageManager +{ +public: + + void Init(); + + MessageManagerImpl(); + ~MessageManagerImpl() = default; + + /** + * @brief Returns the major version of the MessageManager + * @return The major version + */ + int getMajorVersion() const { return MESSAGEMNGR_VERSION_MAJOR; } + + /** + * @brief Returns the minor version of the MessageManager + * @return The minor version + */ + int getMinorVersion() const { return MESSAGEMNGR_VERSION_MINOR; } + + /** + * @brief Returns the blocking behavior for the given message type + * @param msgType The message type + * @return The blocking behavior for the given message type + */ + IMessage::BlockType getMessageBlock(int msgType) const; + + /** + * @brief Sets the blocking behavior for the given message type + * @param msgType The message type + * @param blockType The blocking behavior to set + */ + void setMessageBlock(int msgType, IMessage::BlockType blockType); + + /** + * @brief Registers a hook function for the given message type + * @param msgType The message type to register the hook for + * @param handler The hook function to register + * @param priority The priority of the hook function (see enum HookChainPriority) + */ + void registerHook(int msgType, hookfunc_t handler, int priority = HC_PRIORITY_DEFAULT); + + /** + * @brief Unregisters a hook function for the given message type + * @param msgType The message type to unregister the hook for + * @param handler The hook function to unregister + */ + void unregisterHook(int msgType, hookfunc_t handler); + +private: + friend void PF_MessageBegin_Intercept(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); + friend void PF_MessageEnd_Intercept(); + friend void PF_WriteByte_Intercept(int iValue); + friend void PF_WriteChar_Intercept(int iValue); + friend void PF_WriteShort_Intercept(int iValue); + friend void PF_WriteLong_Intercept(int iValue); + friend void PF_WriteAngle_Intercept(float flValue); + friend void PF_WriteCoord_Intercept(float flValue); + friend void PF_WriteString_Intercept(const char *sz); + friend void PF_WriteEntity_Intercept(int iValue); + + bool MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); + bool MessageEnd(); + +private: + bool WriteParam(IMessage::ParamType type, size_t length = -1); + + bool m_inblock; // Flag indicating whether a message block is currently active + bool m_inhook; // Flag indicating whether a message hook is currently active + + /** + * @brief Helper a templated Stack class to manage a stack of Message objects + * @tparam T The type of objects stored in the stack + * @tparam MAX The maximum size of the stack + */ + template + class Stack + { + public: + void push() { _size++; } + void pop () { _size--; } + + size_t size() const { return _size; } + size_t max_size() const { return MAX; } + + const T &back() const { return _data[_size - 1]; } + T &back() { return _data[_size - 1]; } + private: + size_t _size = 0u; + T _data[MAX]{}; + }; + + static const size_t MAX_MSGSTACK = 16; // The maximum size of the message stack, 16 it should be enough + Stack m_stack; + + IVoidHookChainRegistryImpl m_hooks [MAX_USERMESSAGES]{}; // The array of hook chain registries for each message type + IMessage::BlockType m_blocks[MAX_USERMESSAGES]{}; // The array of blocking behaviors for each message type +}; + +/** + * @brief The singleton instance of the MessageManager + */ +extern MessageManagerImpl &MessageManager(); From 0f45ec09fa36534f55035703a2727db546af67b0 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Mon, 27 May 2024 05:01:37 +0700 Subject: [PATCH 08/10] Enhanced API interface game message manager Bump major API version Minor refactoring --- rehlds/public/rehlds/IMessageManager.h | 200 +++++++--- rehlds/rehlds/rehlds_messagemngr_impl.cpp | 440 ++++++++++++++++++---- rehlds/rehlds/rehlds_messagemngr_impl.h | 268 ++++++++++--- 3 files changed, 743 insertions(+), 165 deletions(-) diff --git a/rehlds/public/rehlds/IMessageManager.h b/rehlds/public/rehlds/IMessageManager.h index cf818dbc2..d0cabb360 100644 --- a/rehlds/public/rehlds/IMessageManager.h +++ b/rehlds/public/rehlds/IMessageManager.h @@ -44,9 +44,9 @@ class IMessage */ enum class BlockType : uint8 { - Not, // Not a block - Once, // Block once - Set // Set block + Not, // Not a block + Once, // Block once + Set // Set block }; /** @@ -66,99 +66,213 @@ class IMessage SPEC, // Sends to all spectator proxies }; - virtual ~IMessage() {}; + /** + * @brief Data types for message data + */ + enum class DataType : uint8_t + { + Any, // Any part of the message + Dest, // Destination of the message + Index, // Index of the message + Origin, // Origin of the message + Edict, // Pointer to the edict of the recipient client + Param, // Parameter of the message + Max + }; + + virtual ~IMessage() = default; /** * @brief Returns the number of parameters in the message * @return The number of parameters */ - virtual int getParamCount() const = 0; + virtual int getParamCount() const = 0; /** * @brief Returns the type of the parameter at the given index * @param index The index of the parameter * @return The type of the parameter */ - virtual ParamType getParamType(size_t index) const = 0; + virtual ParamType getParamType(size_t index) const = 0; /** * @brief Returns the integer value of the parameter at the given index * @param index The index of the parameter * @return The integer value of the parameter */ - virtual int getParamInt(size_t index) const = 0; + virtual int getParamInt(size_t index) const = 0; /** * @brief Returns the float value of the parameter at the given index * @param index The index of the parameter * @return The float value of the parameter */ - virtual float getParamFloat(size_t index) const = 0; + virtual float getParamFloat(size_t index) const = 0; /** * @brief Returns the string value of the parameter at the given index * @param index The index of the parameter * @return The string value of the parameter */ - virtual const char* getParamString(size_t index) const = 0; + virtual const char* getParamString(size_t index) const = 0; /** * @brief Sets the integer value of the parameter at the given index * @param index The index of the parameter * @param value The integer value to set */ - virtual void setParamInt(size_t index, int value) = 0; + virtual void setParamInt(size_t index, int value) = 0; /** * @brief Sets the float value of the parameter at the given index * @param index The index of the parameter * @param value The float value to set */ - virtual void setParamFloat(size_t index, float value) = 0; + virtual void setParamFloat(size_t index, float value) = 0; /** * @brief Sets the vector value of the parameter at the given index * @param index The index of the parameter * @param pos The vector value to set */ - virtual void setParamVec(size_t index, const float *pos) = 0; + virtual void setParamVec(size_t index, const float *pos) = 0; /** * @brief Sets the string value of the parameter at the given index * @param index The index of the parameter * @param string The string value to set */ - virtual void setParamString(size_t index, const char *string) = 0; + virtual void setParamString(size_t index, const char *string) = 0; /** * @brief Returns the destination of the message * @return The destination of the message */ - virtual Dest getDest() const = 0; + virtual Dest getDest() const = 0; - /** - * @brief Returns the type of the message - * @return The type of the message - */ - virtual int getType() const = 0; + /** + * @brief Returns the index of the message + * @return The index of the message + */ + virtual int getId() const = 0; - /** - * @brief Returns the origin of the message - * @return The origin of the message - */ - virtual const float* getOrigin() const = 0; + /** + * @brief Returns the origin of the message + * @return The origin of the message + */ + virtual const float* getOrigin() const = 0; - /** - * @brief Returns the edict associated with the message - * @return The edict associated with the message - */ + /** + * @brief Returns the edict associated with the message + * @return The edict associated with the message + */ virtual struct edict_s* getEdict() const = 0; - /** - * @brief Returns whether the message has been modified - * @return True if the message has been modified, false otherwise - */ - virtual bool isModified() const = 0; + /** + * @brief Checks if the specified type of message data has been modified + * + * This function allows you to check if any part of the message data, such as its + * destination, type, origin, edict, or any specific parameter, has been modified + * + * @param type The type of the data to check for modification + * This can be one of the following: + * - DataType::Any: Check if any part of the message has been modified + * - DataType::Dest: Check if the destination has been modified + * - DataType::Index: Check if the message ID has been modified + * - DataType::Origin: Check if the origin has been modified + * - DataType::Edict: Check if the edict pointer has been modified + * - DataType::Param: Check if a specific parameter has been modified + * + * @param index The index of the parameter to check for modification (used only when type is DataType::Param) + * Default value is -1, which means the parameter index is not applicable + * + * @return True if the specified data type has been modified, false otherwise + */ + virtual bool isDataModified(DataType type = DataType::Any, size_t index = -1) const = 0; + + /** + * @brief Resets a specific type of message data to its original value + * + * @param type The type of data to reset to its original value + * This can be one of the following: + * - DataType::Any: Reset all modified message data to its original values + * - DataType::Dest: Reset the destination to its original value + * - DataType::Index: Reset the message ID to its original value + * - DataType::Origin: Reset the origin to its original value + * - DataType::Edict: Reset the edict pointer of the recipient client to its original value + * - DataType::Param: Reset a specific parameter to its original value + * + * @param index The index of the parameter to reset (used only when type is DataType::Param) + * Default value is -1, which means the parameter index is not applicable + * + * @return True if the modified data type was reset, false otherwise + */ + virtual bool resetModifiedData(DataType type = DataType::Any, size_t index = -1) = 0; + + /** + * @brief Sets the destination of the message + */ + virtual void setDest(Dest dest) = 0; + + /** + * @brief Sets the index of the message + */ + virtual void setId(int msg_id) = 0; + + /** + * @brief Sets the origin of the message + */ + virtual void setOrigin(const float *origin) = 0; + + /** + * @brief Sets the edict associated with the message + */ + virtual void setEdict(struct edict_s *pEdict) = 0; + + /** + * @brief Returns the original destination of the message before any modifications + * @return The original destination of the message + */ + virtual Dest getOriginalDest() const = 0; + + /** + * @brief Returns the original type of the message before any modifications + * @return The original type of the message + */ + virtual int getOriginalId() const = 0; + + /** + * @brief Returns the original origin of the message before any modifications + * @return The original origin of the message + */ + virtual const float* getOriginalOrigin() const = 0; + + /** + * @brief Returns the original edict associated with the message before any modifications + * @return The original edict associated with the message + */ + virtual struct edict_s* getOriginalEdict() const = 0; + + /** + * @brief Returns the original integer value of the parameter at the given index before any modifications + * @param index The index of the parameter + * @return The original integer value of the parameter + */ + virtual int getOriginalParamInt(size_t index) const = 0; + + /** + * @brief Returns the original float value of the parameter at the given index before any modifications + * @param index The index of the parameter + * @return The original float value of the parameter + */ + virtual float getOriginalParamFloat(size_t index) const = 0; + + /** + * @brief Returns the original string value of the parameter at the given index before any modifications + * @param index The index of the parameter + * @return The original string value of the parameter + */ + virtual const char* getOriginalParamString(size_t index) const = 0; // This must be the last virtual function in class #ifdef REHLDS_SELF @@ -167,7 +281,7 @@ class IMessage #endif }; -#define MESSAGEMNGR_VERSION_MAJOR 1 +#define MESSAGEMNGR_VERSION_MAJOR 2 #define MESSAGEMNGR_VERSION_MINOR 0 /** @@ -178,7 +292,7 @@ class IMessageManager public: using hookfunc_t = void (*)(IVoidHookChain *chain, IMessage *msg); - virtual ~IMessageManager() {}; + virtual ~IMessageManager() = default; /** * @brief Returns the major version of the MessageManager @@ -194,30 +308,30 @@ class IMessageManager /** * @brief Returns the blocking behavior for the given message type - * @param msgType The message type + * @param msg_id The message type * @return The blocking behavior for the given message type */ - virtual IMessage::BlockType getMessageBlock(int msgType) const = 0; + virtual IMessage::BlockType getMessageBlock(int msg_id) const = 0; /** * @brief Sets the blocking behavior for the given message type - * @param msgType The message type + * @param msg_id The message type * @param blockType The blocking behavior to set */ - virtual void setMessageBlock(int msgType, IMessage::BlockType blockType) = 0; + virtual void setMessageBlock(int msg_id, IMessage::BlockType blockType) = 0; /** * @brief Registers a hook function for the given message type - * @param msgType The message type to register the hook for + * @param msg_id The message type to register the hook for * @param handler The hook function to register * @param priority The priority of the hook function (see enum HookChainPriority) */ - virtual void registerHook(int msgType, hookfunc_t handler, int priority = HC_PRIORITY_DEFAULT) = 0; + virtual void registerHook(int msg_id, hookfunc_t handler, int priority = HC_PRIORITY_DEFAULT) = 0; /** * @brief Unregisters a hook function for the given message type - * @param msgType The message type to unregister the hook for + * @param msg_id The message type to unregister the hook for * @param handler The hook function to unregister */ - virtual void unregisterHook(int msgType, hookfunc_t handler) = 0; + virtual void unregisterHook(int msg_id, hookfunc_t handler) = 0; }; diff --git a/rehlds/rehlds/rehlds_messagemngr_impl.cpp b/rehlds/rehlds/rehlds_messagemngr_impl.cpp index 617ceb1a7..dfe27806d 100644 --- a/rehlds/rehlds/rehlds_messagemngr_impl.cpp +++ b/rehlds/rehlds/rehlds_messagemngr_impl.cpp @@ -21,53 +21,60 @@ // Constructs a Message object MessageImpl::MessageImpl() { - m_buffer.buffername = "MessageManager/Begin/End"; - m_buffer.data = m_bufferData; - m_buffer.flags = SIZEBUF_ALLOW_OVERFLOW; - m_buffer.cursize = 0; - m_buffer.maxsize = sizeof(m_bufferData); - - m_paramCount = 0; + m_paramCount = 0; + m_modifiedDataBits = 0; } // Sets the active state of the message with the given parameters -void MessageImpl::setActive(int dest, int type, const float *origin, edict_t *edict) +void MessageImpl::setActive(int dest, int id, const float *origin, edict_t *edict) { - m_dest = static_cast(dest); - m_type = type; - m_edict = edict; - - // Reset buffer size - m_buffer.flags = SIZEBUF_ALLOW_OVERFLOW; - m_buffer.cursize = 0; + // Initialize storage buffers + for (int i = 0; i < MAX_STORAGE; i++) + { + Storage_t &storage = m_Storage[i]; + storage.buf.cursize = 0; + storage.dest = static_cast(dest); + storage.msgid = id; + storage.edict = edict; + + // Copy origin vector if provided + if (origin) + VectorCopy(origin, storage.origin); + else + VectorClear(storage.origin); + } - // Copy origin vector if provided - if (origin) - VectorCopy(origin, m_origin); - else - VectorClear(m_origin); + m_paramCount = 0; + m_modifiedDataBits = 0; } // Sets the buffer for the message void MessageImpl::setBuffer(sizebuf_t *pbuf) { // Copy data from the provided buffer to the message buffer - memcpy(m_buffer.data, pbuf->data, pbuf->cursize); - m_buffer.cursize = pbuf->cursize; + for (int i = 0; i < MAX_STORAGE; i++) + { + Storage_t &storage = m_Storage[i]; + Q_memcpy(storage.buf.data, pbuf->data, pbuf->cursize); + storage.buf.cursize = pbuf->cursize; + } } // Sets the copyback buffer for the message void MessageImpl::setCopybackBuffer(sizebuf_t *pbuf) { + const Storage_t &storage = m_Storage[BACK]; + // Copy data from the message buffer back to the provided buffer - memcpy(pbuf->data, m_buffer.data, m_buffer.cursize); - pbuf->cursize = m_buffer.cursize; + Q_memcpy(pbuf->data, storage.buf.data, storage.buf.cursize); + pbuf->cursize = storage.buf.cursize; } // Clears the message parameters void MessageImpl::clear() { m_paramCount = 0; + m_modifiedDataBits = 0; } // An array containing fixed sizes for various types of parameters @@ -87,9 +94,9 @@ static size_t SIZEOF_PARAMTYPE[] = void MessageImpl::addParam(IMessage::ParamType type, size_t length) { Param_t ¶m = m_params[m_paramCount++]; - param.type = type; - param.len = (length == -1) ? SIZEOF_PARAMTYPE[static_cast(type)] : length; - param.pos = gMsgBuffer.cursize; + param.type = type; + param.newlen = param.oldlen = (length == -1) ? SIZEOF_PARAMTYPE[static_cast(type)] : length; + param.posBack = param.posFront = gMsgBuffer.cursize; } // Sets the value of a primitive parameter at the given index @@ -97,12 +104,11 @@ template void MessageImpl::setParamPrimitive(size_t index, T value) { // Ensure index is within bounds - if (index < 0 || index >= m_paramCount) + if (index >= m_paramCount) return; - const Param_t ¶m = m_params[index]; - - void *pbuf = m_buffer.data + param.pos; + Param_t ¶m = m_params[index]; + void *pbuf = m_Storage[BACK].buf.data + param.posBack; // Set value based on parameter type switch (param.type) @@ -118,7 +124,7 @@ void MessageImpl::setParamPrimitive(size_t index, T value) *(int16 *)pbuf = value; break; case IMessage::ParamType::Long: - *(uint16 *)pbuf = value; + *(uint32 *)pbuf = value; break; case IMessage::ParamType::Angle: // Convert angle value to byte representation with loss of precision @@ -133,7 +139,10 @@ void MessageImpl::setParamPrimitive(size_t index, T value) } // Mark message as modified - m_modified = true; + param.modified = true; + + // Mark the overall status as changed + setModifiedDataBit(DataType::Param); } // Transforms the buffer after setting a string parameter at the given index @@ -143,8 +152,10 @@ void MessageImpl::setTxformBuffer(size_t index, size_t startPos, size_t oldLengt int32_t diffLength = newLength - oldLength; if (diffLength != 0) { + sizebuf_t &buf = m_Storage[BACK].buf; + // Check if the buffer size limit will be exceeded - if (m_buffer.cursize + diffLength > m_buffer.maxsize) + if (buf.cursize + diffLength > buf.maxsize) { Sys_Error( "%s: Refusing to transform string with %i param of user message of %i bytes, " @@ -152,13 +163,18 @@ void MessageImpl::setTxformBuffer(size_t index, size_t startPos, size_t oldLengt } // Move the data in the buffer - size_t moveLength = m_buffer.cursize - (startPos + oldLength); - Q_memmove(m_buffer.data + startPos + newLength, m_buffer.data + startPos + oldLength, moveLength); - m_buffer.cursize += diffLength; + size_t moveLength = buf.cursize - (startPos + oldLength); + if (moveLength > 0) + Q_memmove(buf.data + startPos + newLength, buf.data + startPos + oldLength, moveLength); + + buf.cursize += diffLength; + + if (newLength < oldLength) + Q_memset(buf.data + startPos + newLength + moveLength, 0, oldLength - newLength); // Update the position of all subsequent parameters for (size_t i = index + 1; i < m_paramCount; i++) - m_params[i].pos += diffLength; + m_params[i].posBack += diffLength; } } @@ -166,12 +182,13 @@ void MessageImpl::setTxformBuffer(size_t index, size_t startPos, size_t oldLengt int MessageImpl::getParamInt(size_t index) const { // Ensure index is within bounds - if (index < 0 || index >= m_paramCount) + if (index >= m_paramCount) return 0; // Get the parameter value based on its type - void *buf = m_buffer.data + m_params[index].pos; - switch (m_params[index].type) + const Param_t ¶m = m_params[index]; + const void *buf = m_Storage[BACK].buf.data + param.posBack; + switch (param.type) { case IMessage::ParamType::Byte: return *(uint8 *)buf; @@ -181,7 +198,7 @@ int MessageImpl::getParamInt(size_t index) const case IMessage::ParamType::Entity: return *(int16 *)buf; case IMessage::ParamType::Long: - return *(uint16 *)buf; + return *(uint32 *)buf; default: return 0; // bad type } @@ -191,12 +208,12 @@ int MessageImpl::getParamInt(size_t index) const float MessageImpl::getParamFloat(size_t index) const { // Ensure index is within bounds - if (index < 0 || index >= m_paramCount) + if (index >= m_paramCount) return 0; // Get the parameter value based on its type const Param_t ¶m = m_params[index]; - void *buf = m_buffer.data + param.pos; + const void *buf = m_Storage[BACK].buf.data + param.posBack; switch (param.type) { case IMessage::ParamType::Angle: @@ -214,13 +231,74 @@ float MessageImpl::getParamFloat(size_t index) const const char *MessageImpl::getParamString(size_t index) const { // Ensure index is within bounds - if (index < 0 || index >= m_paramCount) + if (index >= m_paramCount) return nullptr; // Get the parameter value if it is a string const Param_t ¶m = m_params[index]; if (param.type == IMessage::ParamType::String) - return (const char *)m_buffer.data + param.pos; + return (const char *)m_Storage[BACK].buf.data + param.posBack; + + return nullptr; +} + +int MessageImpl::getOriginalParamInt(size_t index) const +{ + // Ensure index is within bounds + if (index >= m_paramCount) + return 0; + + // Get the parameter value based on its type + const Param_t ¶m = m_params[index]; + const void *buf = m_Storage[FRONT].buf.data + param.posFront; + switch (param.type) + { + case IMessage::ParamType::Byte: + return *(uint8 *)buf; + case IMessage::ParamType::Char: + return *(int8 *)buf; + case IMessage::ParamType::Short: + case IMessage::ParamType::Entity: + return *(int16 *)buf; + case IMessage::ParamType::Long: + return *(uint32 *)buf; + default: + return 0; // bad type + } +} + +float MessageImpl::getOriginalParamFloat(size_t index) const +{ + // Ensure index is within bounds + if (index >= m_paramCount) + return 0; + + // Get the parameter value based on its type + const Param_t ¶m = m_params[index]; + const void *buf = m_Storage[FRONT].buf.data + param.posFront; + switch (param.type) + { + case IMessage::ParamType::Angle: + return (float)(*(uint8 *)buf * (360.0 / 256.0)); + case IMessage::ParamType::Coord: + return (float)(*(int16 *)buf * (1.0 / 8)); + default: + break; // bad type + } + + return 0; +} + +const char *MessageImpl::getOriginalParamString(size_t index) const +{ + // Ensure index is within bounds + if (index >= m_paramCount) + return nullptr; + + // Get the parameter value if it is a string + const Param_t ¶m = m_params[index]; + if (param.type == IMessage::ParamType::String) + return (const char *)m_Storage[FRONT].buf.data + param.posFront; return nullptr; } @@ -244,13 +322,13 @@ void MessageImpl::setParamVec(size_t index, const float *pos) return; // Ensure index is within bounds - if (index < 0 || (index + 3) >= m_paramCount) + if ((index + 3) >= m_paramCount) return; // Get the parameter position in the buffer - const Param_t ¶m = m_params[index]; + Param_t ¶m = m_params[index]; - int16 *pbuf = (int16 *)m_buffer.data + param.pos; + int16 *pbuf = (int16 *)m_Storage[BACK].buf.data + param.posBack; // Set each component of the vector parameter *(int16 *)pbuf++ = (int16)(pos[0] * 8.0); @@ -258,7 +336,10 @@ void MessageImpl::setParamVec(size_t index, const float *pos) *(int16 *)pbuf++ = (int16)(pos[2] * 8.0); // Mark message as modified - m_modified = true; + param.modified = true; + + // Mark the overall status as modified + setModifiedDataBit(DataType::Param); } // Sets the string value of the parameter at the given index @@ -268,77 +349,276 @@ void MessageImpl::setParamString(size_t index, const char *value) return; // Ensure index is within bounds - if (index < 0 || index >= m_paramCount) + if (index >= m_paramCount) return; // Calculate the length of the string - size_t length = Q_strlen(value) + 1; - const Param_t ¶m = m_params[index]; + Param_t ¶m = m_params[index]; + + param.newlen = Q_strlen(value) + 1; // Transform buffer to accommodate the new string length - setTxformBuffer(index, param.pos, param.len, length); + setTxformBuffer(index, param.posBack, param.oldlen, param.newlen); // Copy the string value to the buffer - memcpy(m_buffer.data + param.pos, value, length); + Q_memcpy(m_Storage[BACK].buf.data + param.posBack, value, param.newlen); // Mark message as modified - m_modified = true; + param.modified = true; + + // Mark the overall status as modified + setModifiedDataBit(DataType::Param); } -MessageManagerImpl::MessageManagerImpl() +// Sets the destination of the message +void MessageImpl::setDest(Dest dest) +{ + m_Storage[BACK].dest = dest; + setModifiedDataBit(DataType::Dest); +} + +// Sets the type of the message +void MessageImpl::setId(int msg_id) +{ + m_Storage[BACK].msgid = msg_id; + setModifiedDataBit(DataType::Index); +} + +// Sets the origin of the message +void MessageImpl::setOrigin(const float *origin) +{ + // Copy origin vector if provided + if (origin) + VectorCopy(origin, m_Storage[BACK].origin); + else + VectorClear(m_Storage[BACK].origin); + + setModifiedDataBit(DataType::Origin); +} + +//Sets the edict associated with the message +void MessageImpl::setEdict(edict_t *pEdict) +{ + m_Storage[BACK].edict = pEdict; + setModifiedDataBit(DataType::Edict); +} + +bool MessageImpl::isDataModified(DataType type, size_t index) const +{ + if (!isDataTypeModified(type)) + return false; + + if (type == DataType::Param && index != -1) + { + // Ensure index is within bounds + if (index >= m_paramCount) + return false; + + const Param_t ¶m = m_params[index]; + return param.modified; + } + + return true; +} + +void MessageImpl::resetParam(size_t index) +{ + Param_t ¶m = m_params[index]; + + void *pbackbuf = m_Storage[BACK].buf.data + param.posBack; + const void *pfrontbuf = m_Storage[FRONT].buf.data + param.posFront; + + // Set value based on parameter type + switch (param.type) + { + case IMessage::ParamType::Byte: + *(uint8 *)pbackbuf = *(uint8 *)pfrontbuf; + break; + case IMessage::ParamType::Char: + *(int8 *)pbackbuf = *(int8 *)pfrontbuf; + break; + case IMessage::ParamType::Short: + case IMessage::ParamType::Entity: + *(int16 *)pbackbuf = *(int16 *)pfrontbuf; + break; + case IMessage::ParamType::Long: + *(uint32 *)pbackbuf = *(uint32 *)pfrontbuf; + break; + case IMessage::ParamType::Angle: + *(uint8 *)pbackbuf = *(uint8 *)pfrontbuf; + break; + case IMessage::ParamType::Coord: + *(int16 *)pbackbuf = *(int16 *)pfrontbuf; + break; + case IMessage::ParamType::String: + // Return the original string value from the front buffer + setTxformBuffer(index, param.posBack, param.newlen, param.oldlen); + Q_memcpy(pbackbuf, pfrontbuf, param.oldlen); + param.newlen = param.oldlen; + break; + default: + return; // bad type + } + + // Unmark message as modified + param.modified = false; +} + +// Resets a specific message parameter to its original value +bool MessageImpl::resetModifiedData(DataType type, size_t index) +{ + Storage_t &storageBack = m_Storage[BACK]; + const Storage_t &storageFront = m_Storage[FRONT]; + + unsetModifiedDataBit(type); + + switch (type) + { + // Resets all message parameters and storage data to their original values + case DataType::Any: + { + // Update the position of all subsequent parameters + for (size_t i = 0; i < m_paramCount; i++) + { + Param_t ¶m = m_params[i]; + param.posBack = param.posFront; + param.newlen = param.oldlen; + param.modified = false; // Unmark message as modified + } + + // Copy front storage data to back buffer data + Q_memcpy(storageBack.buf.data, storageFront.buf.data, storageFront.buf.maxsize); + + storageBack.dest = storageFront.dest; + storageBack.msgid = storageFront.msgid; + storageBack.edict = storageFront.edict; + + VectorCopy(storageFront.origin, storageBack.origin); + + m_modifiedDataBits = 0; + + break; + } + case DataType::Dest: + storageBack.dest = storageFront.dest; + break; + case DataType::Index: + storageBack.msgid = storageFront.msgid; + break; + case DataType::Origin: + VectorCopy(storageFront.origin, storageBack.origin); + break; + case DataType::Edict: + storageBack.edict = storageFront.edict; + break; + case DataType::Param: + { + // Reset a specific parameter + if (index != -1) + { + // Ensure index is within bounds + if (index < m_paramCount) + resetParam(index); + } + else + { + for (size_t i = 0; i < m_paramCount; i++) + resetParam(i); + } + + // Recalc modified data bits + for (size_t i = 0; i < m_paramCount; i++) + { + const Param_t ¶m = m_params[i]; + if (param.modified) + { + setModifiedDataBit(DataType::Param); + break; + } + } + + break; + } + default: + return false; + } + + // If there was any other modified data, mark Any as overall modified data + if (m_modifiedDataBits != 0) + setModifiedDataBit(DataType::Any); + + return true; +} + +MessageManagerImpl::MessageManagerImpl() : m_stack(m_pool) { m_inblock = false; m_inhook = false; } // Register hook function for the game message type -void MessageManagerImpl::registerHook(int msgType, hookfunc_t handler, int priority) +void MessageManagerImpl::registerHook(int msg_id, hookfunc_t handler, int priority) { - m_hooks[msgType].registerHook(handler, priority); + if (!m_hooks[msg_id]) + m_hooks[msg_id] = new HookRegistry_t; + + if (m_hooks[msg_id]->findHook(handler)) + return; // already registered + + m_hooks[msg_id]->registerHook(handler, priority); } // Unregister hook function for the game message type -void MessageManagerImpl::unregisterHook(int msgType, hookfunc_t handler) +void MessageManagerImpl::unregisterHook(int msg_id, hookfunc_t handler) { - m_hooks[msgType].unregisterHook(handler); + if (!m_hooks[msg_id]) + return; + + m_hooks[msg_id]->unregisterHook(handler); + + if (m_hooks[msg_id]->getCount() == 0) + { + delete m_hooks[msg_id]; + m_hooks[msg_id] = nullptr; + m_pool.clear(); + } } // Get the block type for the game message type -IMessage::BlockType MessageManagerImpl::getMessageBlock(int msgType) const +IMessage::BlockType MessageManagerImpl::getMessageBlock(int msg_id) const { - return m_blocks[msgType]; + return m_blocks[msg_id]; } // Set the block type for the game message type -void MessageManagerImpl::setMessageBlock(int msgType, IMessage::BlockType blockType) +void MessageManagerImpl::setMessageBlock(int msg_id, IMessage::BlockType blockType) { - m_blocks[msgType] = blockType; + m_blocks[msg_id] = blockType; } -bool MessageManagerImpl::MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) +bool MessageManagerImpl::MessageBegin(int msg_dest, int msg_id, const float *pOrigin, edict_t *ed) { // Check if the message type is blocked - if (m_blocks[msg_type] != IMessage::BlockType::Not) + if (m_blocks[msg_id] != IMessage::BlockType::Not) { m_inblock = true; return false; } // Check if there are hooks registered for the message type - m_inhook = m_hooks[msg_type].getCount() > 0; + m_inhook = (m_hooks[msg_id] && m_hooks[msg_id]->getCount() > 0); if (m_inhook) { // Check for stack overflow if (m_stack.size() >= m_stack.max_size() - 1) - Sys_Error("%s: stack overflow in #%i user message.\nIndicate potential recursive calls...\n", __func__, msg_type); + Sys_Error("%s: stack overflow in #%i user message.\nIndicate potential recursive calls...\n", __func__, msg_id); // Push a new game message onto the stack - m_stack.push(); + MessageImpl &msg = m_stack.push(); // Initialize the message - MessageImpl &msg = m_stack.back(); - msg.setActive(msg_dest, msg_type, pOrigin, ed); + msg.setActive(msg_dest, msg_id, pOrigin, ed); } return true; @@ -347,7 +627,7 @@ bool MessageManagerImpl::MessageBegin(int msg_dest, int msg_type, const float *p static void EXT_FUNC SendUserMessageData(IMessage *msg) { // Set global variables with message data - gMsgType = msg->getType(); + gMsgType = msg->getId(); gMsgEntity = msg->getEdict(); gMsgDest = static_cast(msg->getDest()); @@ -383,11 +663,11 @@ bool MessageManagerImpl::MessageEnd() gMsgStarted = FALSE; // Get the message from the top of the stack - MessageImpl &msg = m_stack.back(); + MessageImpl &msg = m_stack.top(); // Set buffer from global buffer and call hookchain msg.setBuffer(&gMsgBuffer); - m_hooks[msg.getType()].callChain(SendUserMessageData, &msg); + m_hooks[msg.getId()]->callChain(SendUserMessageData, &msg); m_inhook = false; // Clear the message and pop from the stack @@ -407,7 +687,7 @@ bool MessageManagerImpl::WriteParam(IMessage::ParamType type, size_t length) if (m_inhook) { // Add parameter to top stack message - MessageImpl &msg = m_stack.back(); + MessageImpl &msg = m_stack.top(); msg.addParam(type, length); } @@ -418,14 +698,14 @@ bool MessageManagerImpl::WriteParam(IMessage::ParamType type, size_t length) // Functions intercept to handle messages // -void EXT_FUNC PF_MessageBegin_Intercept(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) +void EXT_FUNC PF_MessageBegin_Intercept(int msg_dest, int msg_id, const float *pOrigin, edict_t *ed) { // Set global message type - gMsgType = msg_type; + gMsgType = msg_id; // Begin message manager - if (MessageManager().MessageBegin(msg_dest, msg_type, pOrigin, ed)) - PF_MessageBegin_I(msg_dest, msg_type, pOrigin, ed); + if (MessageManager().MessageBegin(msg_dest, msg_id, pOrigin, ed)) + PF_MessageBegin_I(msg_dest, msg_id, pOrigin, ed); } void EXT_FUNC PF_MessageEnd_Intercept(void) diff --git a/rehlds/rehlds/rehlds_messagemngr_impl.h b/rehlds/rehlds/rehlds_messagemngr_impl.h index b0ad18cb8..549d1bb6b 100644 --- a/rehlds/rehlds/rehlds_messagemngr_impl.h +++ b/rehlds/rehlds/rehlds_messagemngr_impl.h @@ -21,6 +21,9 @@ #include "IMessageManager.h" #include "hookchains.h" +#include // std::unique_ptr +#include // std::move + /** * @brief Implementation interface for defining message parameters and behavior for a game message object */ @@ -71,6 +74,27 @@ class MessageImpl: public IMessage */ void setParamInt(size_t index, int value); + /** + * @brief Returns the original integer value of the parameter at the given index before any modifications + * @param index The index of the parameter + * @return The original integer value of the parameter + */ + int getOriginalParamInt(size_t index) const; + + /** + * @brief Returns the original float value of the parameter at the given index before any modifications + * @param index The index of the parameter + * @return The original float value of the parameter + */ + float getOriginalParamFloat(size_t index) const; + + /** + * @brief Returns the original string value of the parameter at the given index before any modifications + * @param index The index of the parameter + * @return The original string value of the parameter + */ + const char* getOriginalParamString(size_t index) const; + /** * @brief Sets the float value of the parameter at the given index * @param index The index of the parameter @@ -92,42 +116,101 @@ class MessageImpl: public IMessage */ void setParamString(size_t index, const char *string); + /** + * @brief Sets the destination of the message + */ + void setDest(Dest dest); + /** * @brief Returns the destination of the message * @return The destination of the message */ - Dest getDest() const { return m_dest; } + Dest getDest() const { return m_Storage[BACK].dest; } + Dest getOriginalDest() const { return m_Storage[FRONT].dest; } /** - * @brief Returns the type of the message - * @return The type of the message + * @brief Sets the index of the message */ - int getType() const { return m_type; } + void setId(int msg_id); + + /** + * @brief Returns the index of the message + * @return The index of the message + */ + int getId() const { return m_Storage[BACK].msgid; } + int getOriginalId() const { return m_Storage[FRONT].msgid; } + + /** + * @brief Sets the origin of the message + */ + void setOrigin(const float *origin); /** * @brief Returns the origin of the message * @return The origin of the message */ - const float *getOrigin() const { return m_origin; } + const float *getOrigin() const { return m_Storage[BACK].origin; } + const float *getOriginalOrigin() const { return m_Storage[FRONT].origin; } + + /** + * @brief Sets the edict associated with the message + */ + void setEdict(edict_t *pEdict); /** * @brief Returns the edict associated with the message * @return The edict associated with the message */ - edict_t *getEdict() const { return m_edict; } + edict_t *getEdict() const { return m_Storage[BACK].edict; } + edict_t *getOriginalEdict() const { return m_Storage[FRONT].edict; } + + /** + * @brief Checks if the specified type of message data has been modified + * + * This function allows you to check if any part of the message data, such as its + * destination, type, origin, edict, or any specific parameter, has been modified + * + * @param type The type of the data to check for modification + * This can be one of the following: + * - DataType::Any: Check if any part of the message has been modified + * - DataType::Dest: Check if the destination has been modified + * - DataType::Index: Check if the message ID has been modified + * - DataType::Origin: Check if the origin has been modified + * - DataType::Edict: Check if the edict pointer has been modified + * - DataType::Param: Check if a specific parameter has been modified + * + * @param index The index of the parameter to check for modification (used only when type is DataType::Param) + * Default value is -1, which means the parameter index is not applicable + * + * @return True if the specified data type has been modified, false otherwise + */ + bool isDataModified(DataType type, size_t index) const; /** - * @brief Returns whether the message has been modified - * @return True if the message has been modified, false otherwise + * @brief Resets a specific type of message data to its original value + * + * @param type The type of data to reset to its original value + * This can be one of the following: + * - DataType::Any: Reset all modified message data to its original values + * - DataType::Dest: Reset the destination to its original value + * - DataType::Index: Reset the message ID to its original value + * - DataType::Origin: Reset the origin to its original value + * - DataType::Edict: Reset the edict pointer of the recipient client to its original value + * - DataType::Param: Reset a specific parameter to its original value + * + * @param index The index of the parameter to reset (used only when type is DataType::Param) + * Default value is -1, which means the parameter index is not applicable + * + * @return True if the modified data type was reset, false otherwise */ - bool isModified() const { return m_modified; } + bool resetModifiedData(DataType type, size_t index = -1); private: friend class MessageManagerImpl; // Sets the active state of the message with the given parameters - void setActive(int dest, int type, const float *origin, edict_t *edict); + void setActive(int dest, int id, const float *origin, edict_t *edict); // Sets the buffer for the message void setBuffer(sizebuf_t *pbuf); @@ -147,27 +230,78 @@ class MessageImpl: public IMessage // Transforms buffer after sets string for a parameter at the given index void setTxformBuffer(size_t index, size_t startPos, size_t oldLength, size_t newLength); - bool m_modified; // Flag indicating whether the message has been modified - Dest m_dest; // The destination of the message - int m_type; // The type of the message - float m_origin[3]; // The origin of the message - edict_t* m_edict; // The edict associated with the message + enum + { + FRONT, // Original buffer storage data + BACK, // Current modifiable buffer storage data + MAX_STORAGE + }; + + struct Storage_t + { + // The buffer storage data for the message 'm_buffer' (variable-length message limited to one byte is 256) + uint8_t bufData[256]{}; - uint8 m_bufferData[512]; // The buffer data for the message 'm_buffer' - sizebuf_t m_buffer; // The buffer for the message + // The buffer for the message + sizebuf_t buf = { "MsgMngr/Begin/End", SIZEBUF_ALLOW_OVERFLOW, bufData, sizeof(bufData), 0 }; + // The destination of the message + Dest dest{}; + + // The index of the message + int msgid{0}; + + // The origin of the message + float origin[3]{0,0,0}; + + // The edict associated with the message + edict_t *edict{nullptr}; + }; + + Storage_t m_Storage[MAX_STORAGE]; + +#pragma pack(push, 1) struct Param_t { - ParamType type; // The type of the parameter - size_t pos; // The position of the parameter in the buffer - size_t len; // The length of the parameter in the buffer + bool modified : 1; // Flag indicating whether the message param has been modified + ParamType type : 3; // The type of the parameter + size_t posBack : 9; // The current position of the parameter in the buffer + size_t posFront : 9; // The stock position of the parameter in the buffer + size_t oldlen : 9; // The length of the parameter in the buffer + size_t newlen : 9; // The length of the parameter in the buffer }; +#pragma pack(pop) static const size_t MAX_PARAMS = 16; // The maximum number of parameters allowed in the message - Param_t m_params[MAX_PARAMS]; // The array of parameters in the message - size_t m_paramCount; // The number of parameters in the message + Param_t m_params[MAX_PARAMS]{}; // The array of parameters in the message + size_t m_paramCount : 4; // The number of parameters in the message + + void resetParam(size_t index); + + void setModifiedDataBit(DataType type); + void unsetModifiedDataBit(DataType type); + bool isDataTypeModified(DataType type) const; + uint8 m_modifiedDataBits : DataType::Max; }; +/** +* Inline methods +*/ +inline void MessageImpl::setModifiedDataBit(DataType type) +{ + m_modifiedDataBits |= ((1 << static_cast(DataType::Any)) | (1 << static_cast(type))); +} + +inline void MessageImpl::unsetModifiedDataBit(DataType type) +{ + m_modifiedDataBits &= ~((1 << static_cast(DataType::Any)) | (1 << static_cast(type))); +} + +inline bool MessageImpl::isDataTypeModified(DataType type) const +{ + return (m_modifiedDataBits & (1 << static_cast(type))) != 0; +} + /** * @brief Implementation interface manages hooks and blocking behavior game messages */ @@ -194,35 +328,35 @@ class MessageManagerImpl: public IMessageManager /** * @brief Returns the blocking behavior for the given message type - * @param msgType The message type + * @param msg_id The message type * @return The blocking behavior for the given message type */ - IMessage::BlockType getMessageBlock(int msgType) const; + IMessage::BlockType getMessageBlock(int msg_id) const; /** * @brief Sets the blocking behavior for the given message type - * @param msgType The message type + * @param msg_id The message type * @param blockType The blocking behavior to set */ - void setMessageBlock(int msgType, IMessage::BlockType blockType); + void setMessageBlock(int msg_id, IMessage::BlockType blockType); /** * @brief Registers a hook function for the given message type - * @param msgType The message type to register the hook for + * @param msg_id The message type to register the hook for * @param handler The hook function to register * @param priority The priority of the hook function (see enum HookChainPriority) */ - void registerHook(int msgType, hookfunc_t handler, int priority = HC_PRIORITY_DEFAULT); + void registerHook(int msg_id, hookfunc_t handler, int priority = HC_PRIORITY_DEFAULT); /** * @brief Unregisters a hook function for the given message type - * @param msgType The message type to unregister the hook for + * @param msg_id The message type to unregister the hook for * @param handler The hook function to unregister */ - void unregisterHook(int msgType, hookfunc_t handler); + void unregisterHook(int msg_id, hookfunc_t handler); private: - friend void PF_MessageBegin_Intercept(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); + friend void PF_MessageBegin_Intercept(int msg_dest, int msg_id, const float *pOrigin, edict_t *ed); friend void PF_MessageEnd_Intercept(); friend void PF_WriteByte_Intercept(int iValue); friend void PF_WriteChar_Intercept(int iValue); @@ -233,7 +367,7 @@ class MessageManagerImpl: public IMessageManager friend void PF_WriteString_Intercept(const char *sz); friend void PF_WriteEntity_Intercept(int iValue); - bool MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); + bool MessageBegin(int msg_dest, int msg_id, const float *pOrigin, edict_t *ed); bool MessageEnd(); private: @@ -243,31 +377,81 @@ class MessageManagerImpl: public IMessageManager bool m_inhook; // Flag indicating whether a message hook is currently active /** - * @brief Helper a templated Stack class to manage a stack of Message objects + * @brief The fixed-size memory pool holds a list of free objects * @tparam T The type of objects stored in the stack * @tparam MAX The maximum size of the stack */ template - class Stack + class MessagePool { public: - void push() { _size++; } - void pop () { _size--; } + std::unique_ptr acquire() + { + if (_size > 0) + return std::move(_freeObjects[--_size]); // reusing + return std::make_unique(); // initialize constructor for new element + } + + void release(std::unique_ptr obj) + { + if (_size < MAX) + _freeObjects[_size++] = std::move(obj); + } + + void clear() + { + while (_size > 0) + _freeObjects[--_size].reset(); + } + + private: + size_t _size{0u}; + std::unique_ptr _freeObjects[MAX]{}; + }; + + /** + * @brief Helper a templated MessageStack class to manage a stack of Message objects with fixed size + * @tparam T The type of objects stored in the stack + * @tparam MAX The maximum size of the stack + */ + template + class MessageStack + { + public: + MessageStack(MessagePool &pool) : _pool(pool) {} + + T &push() + { + std::unique_ptr msg = _pool.acquire(); + _activeObjects[_size++] = std::move(msg); + return *_activeObjects[_size - 1]; + } + + void pop() + { + if (_size > 0) + _pool.release(std::move(_activeObjects[--_size])); + } size_t size() const { return _size; } size_t max_size() const { return MAX; } - const T &back() const { return _data[_size - 1]; } - T &back() { return _data[_size - 1]; } + const T &top() const { return *_activeObjects[_size - 1]; } + T &top() { return *_activeObjects[_size - 1]; } + private: - size_t _size = 0u; - T _data[MAX]{}; + size_t _size{0u}; + std::unique_ptr _activeObjects[MAX]{}; + MessagePool &_pool; }; static const size_t MAX_MSGSTACK = 16; // The maximum size of the message stack, 16 it should be enough - Stack m_stack; + MessagePool m_pool; // A fixed-size memory pool stack for reusable + MessageStack m_stack; + + using HookRegistry_t = IVoidHookChainRegistryImpl; + HookRegistry_t *m_hooks[MAX_USERMESSAGES]{}; - IVoidHookChainRegistryImpl m_hooks [MAX_USERMESSAGES]{}; // The array of hook chain registries for each message type IMessage::BlockType m_blocks[MAX_USERMESSAGES]{}; // The array of blocking behaviors for each message type }; From c1ccc5009a0a6395760e4f4eb5cfddb7353552d2 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Mon, 27 May 2024 05:08:02 +0700 Subject: [PATCH 09/10] Fix warning compiler in linux build --- rehlds/rehlds/rehlds_messagemngr_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rehlds/rehlds/rehlds_messagemngr_impl.cpp b/rehlds/rehlds/rehlds_messagemngr_impl.cpp index dfe27806d..4b381deb0 100644 --- a/rehlds/rehlds/rehlds_messagemngr_impl.cpp +++ b/rehlds/rehlds/rehlds_messagemngr_impl.cpp @@ -562,7 +562,7 @@ void MessageManagerImpl::registerHook(int msg_id, hookfunc_t handler, int priori if (!m_hooks[msg_id]) m_hooks[msg_id] = new HookRegistry_t; - if (m_hooks[msg_id]->findHook(handler)) + if (m_hooks[msg_id]->findHook((void *)handler)) return; // already registered m_hooks[msg_id]->registerHook(handler, priority); From 9c1e84328ebcdb47ea83c157dd8c7e493dda28a6 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Thu, 30 May 2024 19:15:39 +0700 Subject: [PATCH 10/10] Fixed GCC compilation warnings/errors Fixes #1032 --- rehlds/engine/host.cpp | 3 +- rehlds/public/rehlds/IMessageManager.h | 2 +- rehlds/rehlds/rehlds_messagemngr_impl.cpp | 278 +++++++++++++++++++++ rehlds/rehlds/rehlds_messagemngr_impl.h | 282 +--------------------- 4 files changed, 283 insertions(+), 282 deletions(-) diff --git a/rehlds/engine/host.cpp b/rehlds/engine/host.cpp index 673b3297f..9cd73e672 100644 --- a/rehlds/engine/host.cpp +++ b/rehlds/engine/host.cpp @@ -375,7 +375,8 @@ void EXT_FUNC SV_ClientPrintf_internal(const char *Dest) { char string[1024]; - Q_strlcpy(string, Dest, min(strlen(Dest) + 1, sizeof(string))); + Q_strlcpy(string, Dest); + MSG_WriteByte(&host_client->netchan.message, svc_print); MSG_WriteString(&host_client->netchan.message, string); } diff --git a/rehlds/public/rehlds/IMessageManager.h b/rehlds/public/rehlds/IMessageManager.h index d0cabb360..c93a2ec7b 100644 --- a/rehlds/public/rehlds/IMessageManager.h +++ b/rehlds/public/rehlds/IMessageManager.h @@ -69,7 +69,7 @@ class IMessage /** * @brief Data types for message data */ - enum class DataType : uint8_t + enum class DataType : uint8 { Any, // Any part of the message Dest, // Destination of the message diff --git a/rehlds/rehlds/rehlds_messagemngr_impl.cpp b/rehlds/rehlds/rehlds_messagemngr_impl.cpp index 4b381deb0..534051932 100644 --- a/rehlds/rehlds/rehlds_messagemngr_impl.cpp +++ b/rehlds/rehlds/rehlds_messagemngr_impl.cpp @@ -18,6 +18,284 @@ #include "precompiled.h" +/** + * @brief Implementation interface for defining message parameters and behavior for a game message object + */ +class MessageImpl: public IMessage +{ +public: + MessageImpl(); + ~MessageImpl() = default; + + /** + * @brief Returns the number of parameters in the message + * @return The number of parameters + */ + int getParamCount() const { return m_paramCount; } + + /** + * @brief Returns the type of the parameter at the given index + * @param index The index of the parameter + * @return The type of the parameter + */ + ParamType getParamType(size_t index) const { return m_params[index].type; } + + /** + * @brief Returns the integer value of the parameter at the given index + * @param index The index of the parameter + * @return The integer value of the parameter + */ + int getParamInt(size_t index) const; + + /** + * @brief Returns the float value of the parameter at the given index + * @param index The index of the parameter + * @return The float value of the parameter + */ + float getParamFloat(size_t index) const; + + /** + * @brief Returns the string value of the parameter at the given index + * @param index The index of the parameter + * @return The string value of the parameter + */ + const char *getParamString(size_t index) const; + + /** + * @brief Sets the integer value of the parameter at the given index + * @param index The index of the parameter + * @param value The integer value to set + */ + void setParamInt(size_t index, int value); + + /** + * @brief Returns the original integer value of the parameter at the given index before any modifications + * @param index The index of the parameter + * @return The original integer value of the parameter + */ + int getOriginalParamInt(size_t index) const; + + /** + * @brief Returns the original float value of the parameter at the given index before any modifications + * @param index The index of the parameter + * @return The original float value of the parameter + */ + float getOriginalParamFloat(size_t index) const; + + /** + * @brief Returns the original string value of the parameter at the given index before any modifications + * @param index The index of the parameter + * @return The original string value of the parameter + */ + const char* getOriginalParamString(size_t index) const; + + /** + * @brief Sets the float value of the parameter at the given index + * @param index The index of the parameter + * @param value The float value to set + */ + void setParamFloat(size_t index, float value); + + /** + * @brief Sets the vector value of the parameter at the given index + * @param index The index of the parameter + * @param pos The vector value to set + */ + void setParamVec(size_t index, const float *pos); + + /** + * @brief Sets the string value of the parameter at the given index + * @param index The index of the parameter + * @param string The string value to set + */ + void setParamString(size_t index, const char *string); + + /** + * @brief Sets the destination of the message + */ + void setDest(Dest dest); + + /** + * @brief Returns the destination of the message + * @return The destination of the message + */ + Dest getDest() const { return m_Storage[BACK].dest; } + Dest getOriginalDest() const { return m_Storage[FRONT].dest; } + + /** + * @brief Sets the index of the message + */ + void setId(int msg_id); + + /** + * @brief Returns the index of the message + * @return The index of the message + */ + int getId() const { return m_Storage[BACK].msgid; } + int getOriginalId() const { return m_Storage[FRONT].msgid; } + + /** + * @brief Sets the origin of the message + */ + void setOrigin(const float *origin); + + /** + * @brief Returns the origin of the message + * @return The origin of the message + */ + const float *getOrigin() const { return m_Storage[BACK].origin; } + const float *getOriginalOrigin() const { return m_Storage[FRONT].origin; } + + /** + * @brief Sets the edict associated with the message + */ + void setEdict(edict_t *pEdict); + + /** + * @brief Returns the edict associated with the message + * @return The edict associated with the message + */ + edict_t *getEdict() const { return m_Storage[BACK].edict; } + edict_t *getOriginalEdict() const { return m_Storage[FRONT].edict; } + + /** + * @brief Checks if the specified type of message data has been modified + * + * This function allows you to check if any part of the message data, such as its + * destination, type, origin, edict, or any specific parameter, has been modified + * + * @param type The type of the data to check for modification + * This can be one of the following: + * - DataType::Any: Check if any part of the message has been modified + * - DataType::Dest: Check if the destination has been modified + * - DataType::Index: Check if the message ID has been modified + * - DataType::Origin: Check if the origin has been modified + * - DataType::Edict: Check if the edict pointer has been modified + * - DataType::Param: Check if a specific parameter has been modified + * + * @param index The index of the parameter to check for modification (used only when type is DataType::Param) + * Default value is -1, which means the parameter index is not applicable + * + * @return True if the specified data type has been modified, false otherwise + */ + bool isDataModified(DataType type, size_t index) const; + + /** + * @brief Resets a specific type of message data to its original value + * + * @param type The type of data to reset to its original value + * This can be one of the following: + * - DataType::Any: Reset all modified message data to its original values + * - DataType::Dest: Reset the destination to its original value + * - DataType::Index: Reset the message ID to its original value + * - DataType::Origin: Reset the origin to its original value + * - DataType::Edict: Reset the edict pointer of the recipient client to its original value + * - DataType::Param: Reset a specific parameter to its original value + * + * @param index The index of the parameter to reset (used only when type is DataType::Param) + * Default value is -1, which means the parameter index is not applicable + * + * @return True if the modified data type was reset, false otherwise + */ + bool resetModifiedData(DataType type, size_t index = -1); + +private: + + friend class MessageManagerImpl; + + // Sets the active state of the message with the given parameters + void setActive(int dest, int id, const float *origin, edict_t *edict); + + // Sets the buffer for the message + void setBuffer(sizebuf_t *pbuf); + + // Set the copyback buffer for the message + void setCopybackBuffer(sizebuf_t *pbuf); + + // Adds a parameter to the message + void addParam(IMessage::ParamType type, size_t length); + + // Clears the message after execution + void clear(); + + template + void setParamPrimitive(size_t index, T value); + + // Transforms buffer after sets string for a parameter at the given index + void setTxformBuffer(size_t index, size_t startPos, size_t oldLength, size_t newLength); + + enum + { + FRONT, // Original buffer storage data + BACK, // Current modifiable buffer storage data + MAX_STORAGE + }; + + struct Storage_t + { + // The buffer storage data for the message 'm_buffer' (variable-length message limited to one byte is 256) + uint8 bufData[256]{}; + + // The buffer for the message + sizebuf_t buf = { "MsgMngr/Begin/End", SIZEBUF_ALLOW_OVERFLOW, bufData, sizeof(bufData), 0 }; + + // The destination of the message + Dest dest{}; + + // The index of the message + int msgid{0}; + + // The origin of the message + float origin[3]{0,0,0}; + + // The edict associated with the message + edict_t *edict{nullptr}; + }; + + Storage_t m_Storage[MAX_STORAGE]; + +#pragma pack(push, 1) + struct Param_t + { + bool modified : 1; // Flag indicating whether the message param has been modified + ParamType type : 3; // The type of the parameter + size_t posBack : 9; // The current position of the parameter in the buffer + size_t posFront : 9; // The stock position of the parameter in the buffer + size_t oldlen : 9; // The length of the parameter in the buffer + size_t newlen : 9; // The length of the parameter in the buffer + }; +#pragma pack(pop) + + static const size_t MAX_PARAMS = 16; // The maximum number of parameters allowed in the message + Param_t m_params[MAX_PARAMS]{}; // The array of parameters in the message + size_t m_paramCount : 4; // The number of parameters in the message + + void resetParam(size_t index); + + void setModifiedDataBit(DataType type); + void unsetModifiedDataBit(DataType type); + bool isDataTypeModified(DataType type) const; + uint8 m_modifiedDataBits : static_cast(DataType::Max); +}; + +/** +* Inline methods +*/ +inline void MessageImpl::setModifiedDataBit(DataType type) +{ + m_modifiedDataBits |= ((1 << static_cast(DataType::Any)) | (1 << static_cast(type))); +} + +inline void MessageImpl::unsetModifiedDataBit(DataType type) +{ + m_modifiedDataBits &= ~((1 << static_cast(DataType::Any)) | (1 << static_cast(type))); +} + +inline bool MessageImpl::isDataTypeModified(DataType type) const +{ + return (m_modifiedDataBits & (1 << static_cast(type))) != 0; +} + // Constructs a Message object MessageImpl::MessageImpl() { diff --git a/rehlds/rehlds/rehlds_messagemngr_impl.h b/rehlds/rehlds/rehlds_messagemngr_impl.h index 549d1bb6b..f016b193e 100644 --- a/rehlds/rehlds/rehlds_messagemngr_impl.h +++ b/rehlds/rehlds/rehlds_messagemngr_impl.h @@ -24,284 +24,6 @@ #include // std::unique_ptr #include // std::move -/** - * @brief Implementation interface for defining message parameters and behavior for a game message object - */ -class MessageImpl: public IMessage -{ -public: - MessageImpl(); - ~MessageImpl() = default; - - /** - * @brief Returns the number of parameters in the message - * @return The number of parameters - */ - int getParamCount() const { return m_paramCount; } - - /** - * @brief Returns the type of the parameter at the given index - * @param index The index of the parameter - * @return The type of the parameter - */ - ParamType getParamType(size_t index) const { return m_params[index].type; } - - /** - * @brief Returns the integer value of the parameter at the given index - * @param index The index of the parameter - * @return The integer value of the parameter - */ - int getParamInt(size_t index) const; - - /** - * @brief Returns the float value of the parameter at the given index - * @param index The index of the parameter - * @return The float value of the parameter - */ - float getParamFloat(size_t index) const; - - /** - * @brief Returns the string value of the parameter at the given index - * @param index The index of the parameter - * @return The string value of the parameter - */ - const char *getParamString(size_t index) const; - - /** - * @brief Sets the integer value of the parameter at the given index - * @param index The index of the parameter - * @param value The integer value to set - */ - void setParamInt(size_t index, int value); - - /** - * @brief Returns the original integer value of the parameter at the given index before any modifications - * @param index The index of the parameter - * @return The original integer value of the parameter - */ - int getOriginalParamInt(size_t index) const; - - /** - * @brief Returns the original float value of the parameter at the given index before any modifications - * @param index The index of the parameter - * @return The original float value of the parameter - */ - float getOriginalParamFloat(size_t index) const; - - /** - * @brief Returns the original string value of the parameter at the given index before any modifications - * @param index The index of the parameter - * @return The original string value of the parameter - */ - const char* getOriginalParamString(size_t index) const; - - /** - * @brief Sets the float value of the parameter at the given index - * @param index The index of the parameter - * @param value The float value to set - */ - void setParamFloat(size_t index, float value); - - /** - * @brief Sets the vector value of the parameter at the given index - * @param index The index of the parameter - * @param pos The vector value to set - */ - void setParamVec(size_t index, const float *pos); - - /** - * @brief Sets the string value of the parameter at the given index - * @param index The index of the parameter - * @param string The string value to set - */ - void setParamString(size_t index, const char *string); - - /** - * @brief Sets the destination of the message - */ - void setDest(Dest dest); - - /** - * @brief Returns the destination of the message - * @return The destination of the message - */ - Dest getDest() const { return m_Storage[BACK].dest; } - Dest getOriginalDest() const { return m_Storage[FRONT].dest; } - - /** - * @brief Sets the index of the message - */ - void setId(int msg_id); - - /** - * @brief Returns the index of the message - * @return The index of the message - */ - int getId() const { return m_Storage[BACK].msgid; } - int getOriginalId() const { return m_Storage[FRONT].msgid; } - - /** - * @brief Sets the origin of the message - */ - void setOrigin(const float *origin); - - /** - * @brief Returns the origin of the message - * @return The origin of the message - */ - const float *getOrigin() const { return m_Storage[BACK].origin; } - const float *getOriginalOrigin() const { return m_Storage[FRONT].origin; } - - /** - * @brief Sets the edict associated with the message - */ - void setEdict(edict_t *pEdict); - - /** - * @brief Returns the edict associated with the message - * @return The edict associated with the message - */ - edict_t *getEdict() const { return m_Storage[BACK].edict; } - edict_t *getOriginalEdict() const { return m_Storage[FRONT].edict; } - - /** - * @brief Checks if the specified type of message data has been modified - * - * This function allows you to check if any part of the message data, such as its - * destination, type, origin, edict, or any specific parameter, has been modified - * - * @param type The type of the data to check for modification - * This can be one of the following: - * - DataType::Any: Check if any part of the message has been modified - * - DataType::Dest: Check if the destination has been modified - * - DataType::Index: Check if the message ID has been modified - * - DataType::Origin: Check if the origin has been modified - * - DataType::Edict: Check if the edict pointer has been modified - * - DataType::Param: Check if a specific parameter has been modified - * - * @param index The index of the parameter to check for modification (used only when type is DataType::Param) - * Default value is -1, which means the parameter index is not applicable - * - * @return True if the specified data type has been modified, false otherwise - */ - bool isDataModified(DataType type, size_t index) const; - - /** - * @brief Resets a specific type of message data to its original value - * - * @param type The type of data to reset to its original value - * This can be one of the following: - * - DataType::Any: Reset all modified message data to its original values - * - DataType::Dest: Reset the destination to its original value - * - DataType::Index: Reset the message ID to its original value - * - DataType::Origin: Reset the origin to its original value - * - DataType::Edict: Reset the edict pointer of the recipient client to its original value - * - DataType::Param: Reset a specific parameter to its original value - * - * @param index The index of the parameter to reset (used only when type is DataType::Param) - * Default value is -1, which means the parameter index is not applicable - * - * @return True if the modified data type was reset, false otherwise - */ - bool resetModifiedData(DataType type, size_t index = -1); - -private: - - friend class MessageManagerImpl; - - // Sets the active state of the message with the given parameters - void setActive(int dest, int id, const float *origin, edict_t *edict); - - // Sets the buffer for the message - void setBuffer(sizebuf_t *pbuf); - - // Set the copyback buffer for the message - void setCopybackBuffer(sizebuf_t *pbuf); - - // Adds a parameter to the message - void addParam(IMessage::ParamType type, size_t length); - - // Clears the message after execution - void clear(); - - template - void setParamPrimitive(size_t index, T value); - - // Transforms buffer after sets string for a parameter at the given index - void setTxformBuffer(size_t index, size_t startPos, size_t oldLength, size_t newLength); - - enum - { - FRONT, // Original buffer storage data - BACK, // Current modifiable buffer storage data - MAX_STORAGE - }; - - struct Storage_t - { - // The buffer storage data for the message 'm_buffer' (variable-length message limited to one byte is 256) - uint8_t bufData[256]{}; - - // The buffer for the message - sizebuf_t buf = { "MsgMngr/Begin/End", SIZEBUF_ALLOW_OVERFLOW, bufData, sizeof(bufData), 0 }; - - // The destination of the message - Dest dest{}; - - // The index of the message - int msgid{0}; - - // The origin of the message - float origin[3]{0,0,0}; - - // The edict associated with the message - edict_t *edict{nullptr}; - }; - - Storage_t m_Storage[MAX_STORAGE]; - -#pragma pack(push, 1) - struct Param_t - { - bool modified : 1; // Flag indicating whether the message param has been modified - ParamType type : 3; // The type of the parameter - size_t posBack : 9; // The current position of the parameter in the buffer - size_t posFront : 9; // The stock position of the parameter in the buffer - size_t oldlen : 9; // The length of the parameter in the buffer - size_t newlen : 9; // The length of the parameter in the buffer - }; -#pragma pack(pop) - - static const size_t MAX_PARAMS = 16; // The maximum number of parameters allowed in the message - Param_t m_params[MAX_PARAMS]{}; // The array of parameters in the message - size_t m_paramCount : 4; // The number of parameters in the message - - void resetParam(size_t index); - - void setModifiedDataBit(DataType type); - void unsetModifiedDataBit(DataType type); - bool isDataTypeModified(DataType type) const; - uint8 m_modifiedDataBits : DataType::Max; -}; - -/** -* Inline methods -*/ -inline void MessageImpl::setModifiedDataBit(DataType type) -{ - m_modifiedDataBits |= ((1 << static_cast(DataType::Any)) | (1 << static_cast(type))); -} - -inline void MessageImpl::unsetModifiedDataBit(DataType type) -{ - m_modifiedDataBits &= ~((1 << static_cast(DataType::Any)) | (1 << static_cast(type))); -} - -inline bool MessageImpl::isDataTypeModified(DataType type) const -{ - return (m_modifiedDataBits & (1 << static_cast(type))) != 0; -} - /** * @brief Implementation interface manages hooks and blocking behavior game messages */ @@ -446,8 +168,8 @@ class MessageManagerImpl: public IMessageManager }; static const size_t MAX_MSGSTACK = 16; // The maximum size of the message stack, 16 it should be enough - MessagePool m_pool; // A fixed-size memory pool stack for reusable - MessageStack m_stack; + MessagePool m_pool; // A fixed-size memory pool stack for reusable + MessageStack m_stack; using HookRegistry_t = IVoidHookChainRegistryImpl; HookRegistry_t *m_hooks[MAX_USERMESSAGES]{};