diff --git a/reapi/extra/amxmodx/scripting/include/reapi_engine.inc b/reapi/extra/amxmodx/scripting/include/reapi_engine.inc index 24dee320..b9bda123 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_engine.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_engine.inc @@ -280,8 +280,13 @@ enum MessageHook * @param callback The name of the callback function. * @param post Whether the callback should be invoked before or after processing the message. (optional) * -* @note You can modify the message content using SetMessageParam native before the original function is invoked. -* Also can reading the message content using GetMessageParam native. +* @note The callback arguments have: +* msg_id - Message id +* msg_dest - Destination type (see MSG_* constants in messages_const.inc) +* msg_entity - Entity receiving the message +* +* @note You can modify the message content using SetMessageData native before the original function is invoked. +* Also can reading the message content using GetMessageData native. * * In the callback function, use the return values from Hookchain return types, such as HC_CONTINUE, HC_SUPERCEDE, etc. * to control the flow of message processing. @@ -318,56 +323,50 @@ native bool:EnableHookMessage(const MessageHook:handle); native bool:DisableHookMessage(const MessageHook:handle); /** -* Sets the parameter value for the specified index in the current game message. +* Sets the message data in the current game message. * -* @param index The index of the parameter to set. -* @param value The value to set for the parameter. +* @param type The type of the message data that can be changed +* @param ... Additional args depending on the type of the message argument being retrieved (For more details, look at the enum MsgArgType) * -* @return Returns true if the parameter value is successfully set, otherwise false. +* @return Returns true if the message data is successfully set, otherwise false. */ -native bool:SetMessageParam(const number, any:...); +native bool:SetMessageData(const MsgDataType:type, any:...); /** -* Retrieves the parameter value for the specified index in the current game message. +* Gets the message data value in the current game message * -* @param index The index of the parameter to retrieve. -* @param ... Additional parameters depending on the type of the parameter being retrieved. +* @param type The type of message data that can be get +* @param ... Additional args depending on the type of the message argument being retrieved (For more details, look at the enum MsgArgType) * -* @return Returns the retrieved parameter value. +* @return Returns value of argument in the current message */ -native any:GetMessageParam(const number, any:...); +native any:GetMessageData(const MsgDataType:type, any:...); /** -* Retrieves the type of the parameter at the specified index in the current game message. -* -* @param index The index of the parameter to retrieve the type for. +* Gets the message data original value in the current game message. * -* @return Returns the type of the parameter, look at the enum MsgParamType -*/ -native MsgParamType:GetMessageParamType(const number); - -/** -* Retrieves the number of parameters in the current game message. +* @param type The type of message data that can be get +* @param ... Additional args depending on the type of the message argument being retrieved (For more details, look at the enum MsgArgType) * -* @return Returns the number of parameters in the current game message. +* @return Returns original value of argument in the current message */ -native GetMessageParamCount(); +native any:GetMessageOrigData(const MsgDataType:type, any:...); /** -* Retrieves the origin of the current game message. +* Retrieves the type of the argument at the specified number in the current game message. * -* @param origin An array to store the origin coordinates of the game message. +* @param number The number of the argument to retrieve the type for. * -* @return Returns true if the origin is successfully retrieved, otherwise false. +* @return Returns the type of the argument, look at the enum MsgArgType */ -native bool:GetMessageOrigin(Float:origin[3]); +native MsgArgType:GetMessageArgType(const number); /** -* Retrieves the destination of the current message. +* Retrieves the number of argument in the current game message. * -* @return Returns the destination of the current message. +* @return Returns the number of argument in the current game message. */ -native GetMessageDest(); +native GetMessageArgsNum(); /** * Sets the block type for the specified message ID. @@ -387,3 +386,44 @@ native bool:SetMessageBlock(const msgid, MsgBlockType:type); * @return Returns the block type of the specified message, look at the enum MsgBlockType */ native MsgBlockType:GetMessageBlock(const msgid); + +/** +* Checks if the specified type of message data has been modified +* +* This native allows you to check if any part of the message data, such as its +* destination, type, origin, receiver, or any the specific argument of the message, has been modified +* +* @param type The type of the data to check for modification +* This can be one of the following: +* - MsgAny: Check if any part of the message has been modified +* - MsgDest: Check if the destination has been modified +* - MsgIndex: Check if the message ID has been modified +* - MsgOrigin: Check if the origin has been modified +* - MsgTargetId: Check if the index of the recipient client has been modified +* - MsgArg: Check if a specific argument of the message has been modified +* +* @param number The number of the argument to check for modification (used only when type is MsgDataType:MsgArg) +* Default value is -1, which means the argument number is not applicable +* +* @return Returns true if the specified data type has been modified, false otherwise +*/ +native bool:IsMessageDataModified(MsgDataType:type = MsgAny, const number = -1); + +/** +* Resets a specific type of message data to its original value +* +* @param type The type of the data to check for modification +* This can be one of the following: +* - MsgAny: Reset all modified message data to its original values +* - MsgDest: Reset the destination to its original value +* - MsgIndex: Reset the message ID to its original value +* - MsgOrigin: Reset the origin to its original value +* - MsgTargetId: Reset the index of the recipient client to its original value +* - MsgArg: Reset a specific argument of the message to its original value +* +* @param number The number of the argument to reset (used only when type is MsgDataType:MsgArg) +* Default value is -1, which means all arguments will be reset. +* +* @return Returns true if the modified data type was reset, otherwise false. +*/ +native bool:ResetModifiedMessageData(MsgDataType:type = MsgAny, const number = -1); diff --git a/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc b/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc index d32b1cee..409029eb 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc @@ -1323,18 +1323,79 @@ enum NetAdrVars }; /** -* Message param types used with GetMessageParamType() +* Message argument types used with GetMessageArgType() */ -enum MsgParamType +enum MsgArgType { - ParamByte, - ParamChar, - ParamShort, - ParamLong, - ParamAngle, - ParamCoord, - ParamString, - ParamEntity, + ArgByte, + ArgChar, + ArgShort, + ArgLong, + ArgAngle, + ArgCoord, + ArgString, + ArgEntity, +}; + +/** +* Message data types used with SetMessageData()/GetMessageData() +* HasModifiedMessageData()/ResetModifiedMessageData() +*/ +enum MsgDataType +{ + /* + * Description: Any part of the message + */ + MsgAny, + + /* + * Description: The destination of the message + * Return type: integer + * Get params: new dest = GetMessageData(MsgDest); + * Set params: SetMessageData(MsgDest, MSG_ALL); + */ + MsgDest, + + /* + * Description: The index of the message + * Return type: integer + * Get params: new msg_id = GetMessageData(MsgMsgId); + * Set params: SetMessageData(MsgMsgId, const msg_id); + */ + MsgMsgId, + + /* + * Description: The origin of the message + * Return type: float [3] + * Get params: GetMessageData(MsgOrigin, Float:dstVector[3]); + * Set params: SetMessageData(MsgOrigin, Float:srcVector[3]); + */ + MsgOrigin, + + /* + * Description: The index of the recipient client + * Return type: integer + * Get params: new targetId = GetMessageData(MsgTargetId); + * Set params: SetMessageData(MsgTargetId, const targetId); (acceptable indexes 0-32, 0 index also as -1 means NULLENT) + */ + MsgTargetId, + + /* + * Description: The arguments of the message + * + * Arg type: string (MSG_ARG_String) + * Get params: bool:GetMessageData(MsgArg, const argnumber, value[], const maxlen); + * Set params: bool:SetMessageData(MsgArg, const argnumber, const value[]); + * + * Arg type: float (MSG_ARG_Angle, MSG_ARG_Coord) + * Get params: Float:GetMessageData(MsgArg, const argnumber, &Float:value = 0.0); + * Set params: bool:SetMessageData(MsgArg, const argnumber, const Float:value); + * + * Arg type: integer (MSG_ARG_Byte, MSG_ARG_Char, MSG_ARG_Short, MSG_ARG_Long, MSG_ARG_Entity) + * Get params: GetMessageData(MsgArg, const argnumber); + * Set params: bool:SetMessageData(MsgArg, const argnumber, const value); + */ + MsgArg }; /** diff --git a/reapi/extra/amxmodx/scripting/message_test.sma b/reapi/extra/amxmodx/scripting/message_test.sma new file mode 100644 index 00000000..47c6d594 --- /dev/null +++ b/reapi/extra/amxmodx/scripting/message_test.sma @@ -0,0 +1,210 @@ +#include +#include + +public plugin_init() +{ + register_plugin("ReAPI MessageHook Test", "1.0", "s1lent"); + RegisterMessage(get_user_msgid("SayText"), "MessageSayText_Pre", .post = false); + RegisterMessage(get_user_msgid("SayText"), "MessageSayText_Post", .post = true); +} + +/** +* Destination types for message hook +*/ +new const g_MsgDestination[][] = +{ + "MSG_BROADCAST", // Unreliable to all + "MSG_ONE", // Reliable to one (msg_entity) + "MSG_ALL", // Reliable to all + "MSG_INIT", // Write to the init string + "MSG_PVS", // Ents in PVS of org + "MSG_PAS", // Ents in PAS of org + "MSG_PVS_R", // Reliable to PVS + "MSG_PAS_R", // Reliable to PAS + "MSG_ONE_UNRELIABLE", // Send to one client, but don't put in reliable stream, put in unreliable datagram (could be dropped) + "MSG_SPEC" // Sends to all spectator proxies +}; + +/** +* Message argument types used with GetMessageArgType() +*/ +new const g_MsgArgType[][] = +{ + "Byte", + "Char", + "Short", + "Long", + "Angle", + "Coord", + "String", + "Entity", +}; + +/** +* Blocking behavior types for messages used with SetMessageBlock()/GetMessageBlock() +*/ +new const g_MsgBlockType[][] = +{ + "MSG_BLOCK_NOT", // Not a block + "MSG_BLOCK_ONCE", // Block once + "MSG_BLOCK_SET" // Set block +}; + +public MessageSayText_Pre(const msg_id, const msg_dest, const id) +{ + server_print("^nMessageSayText_Pre"); + + DumpMessageArgs(msg_id); + + static bool:recursive_guard = false; + if (!recursive_guard) + { + recursive_guard = true; // avoid deadlock + + // Modify original text message in chat + SetMessageData(MsgDest, MSG_ALL); // send text messages in the chat to everyone + SetMessageData(MsgTargetId, NULLENT); + SetMessageData(MsgArg, 2, "^4(Test) ^3%s1^1 @ ^4%s3^1 : %s2"); // change format + + if (is_user_connected(id)) + { + // Send another chat message, test deadlock + new szPlayerName[32]; + get_user_name(id, szPlayerName, charsmax(szPlayerName)); + + new szTextMsg[256]; + GetMessageData(MsgArg, 4, szTextMsg, charsmax(szTextMsg)); + + message_begin(MSG_ONE, msg_id, .player = id); + write_byte(id); + write_string("^3%s1^1 @ ^4%s3^1 : %s2"); + write_string(szPlayerName); + write_string(szTextMsg); + write_string("Courtyard"); + message_end(); + + // Send another text message, but on screen in center + message_begin(MSG_ONE, get_user_msgid("TextMsg"), .player = id); + write_byte(print_center); + + for (new i = 1; i <= GetMessageArgsNum(); i++) + { + new MsgArgType:type = GetMessageArgType(i); + if (type == ArgString) + { + new szBuffer[256]; + GetMessageOrigData(MsgArg, i, szBuffer, charsmax(szBuffer)); + write_string(szBuffer); + } + } + + message_end(); + } + + recursive_guard = false; + } +} + +public MessageSayText_Post(const msg_id, const msg_dest, const id) +{ + server_print("^nMessageSayText_Post"); + DumpMessageArgs(msg_id); +} + +stock Float:fabs(Float:x) +{ + return x > 0 ? x : -x; +} + +stock DumpMessageArgs(const msg_id) +{ + // indicates that the message data has been modified + new const symbolIndicateModified[] = "+"; + + if (IsMessageDataModified(MsgDest)) + server_print("Dest = %s (%d) > changed to > %s (%d)", g_MsgDestination[GetMessageOrigData(MsgDest)], GetMessageOrigData(MsgDest), g_MsgDestination[GetMessageData(MsgDest)], GetMessageData(MsgDest)); + else + server_print("Dest = %s (%d)", g_MsgDestination[GetMessageData(MsgDest)], GetMessageData(MsgDest)); + + new Float:vecOrigin[3]; + GetMessageData(MsgOrigin, vecOrigin); + + if (IsMessageDataModified(MsgOrigin)) + { + new Float:vecSourceOrigin[3]; + GetMessageOrigData(MsgOrigin, vecSourceOrigin); + server_print("Origin = (%0.2f, %0.2f, %0.2f) > changed to > (%0.2f, %0.2f, %0.2f)", vecSourceOrigin[0], vecSourceOrigin[1], vecSourceOrigin[2], vecOrigin[0], vecOrigin[1], vecOrigin[2]); + } + else + { + server_print("Origin = (%0.2f, %0.2f, %0.2f)", vecOrigin[0], vecOrigin[1], vecOrigin[2]); + } + + if (IsMessageDataModified(MsgTargetId)) + server_print("Receiver = %d > changed to > %d", GetMessageOrigData(MsgTargetId), GetMessageData(MsgTargetId)); + else + server_print("Receiver = %d", GetMessageData(MsgTargetId)); + + server_print("Block state = %s", g_MsgBlockType[any:GetMessageBlock(msg_id)]); + server_print("Args count = %d", GetMessageArgsNum()); + server_print("Message modified %s", IsMessageDataModified() ? symbolIndicateModified : "-"); + + // Iterate over all arguments of current message + for (new i = 1; i <= GetMessageArgsNum(); i++) + { + new MsgArgType:type = GetMessageArgType(i); + new bool:isModified = IsMessageDataModified(MsgArg, i); + + // Print string values of argument + if (type == ArgString) + { + new curString[256], origString[256]; + GetMessageData(MsgArg, i, curString, charsmax(curString)); + GetMessageOrigData(MsgArg, i, origString, charsmax(origString)); + + replace_all(curString, charsmax(curString), "^n", ""); + replace_all(origString, charsmax(origString), "^n", ""); + + if (!equal(origString, curString) || isModified) + { + server_print(" %-2d %-13s %s ^"%s^" > changed to > ^"%s^"", i, g_MsgArgType[any:type], isModified ? symbolIndicateModified : "-", origString, curString); + } + else + { + server_print(" %-2d %-13s %s ^"%s^"", i, g_MsgArgType[any:type], isModified ? symbolIndicateModified : "-", curString); + } + } + // Print float point values of argument + else if (type == ArgAngle || type == ArgCoord) + { + new Float:flCurValue = Float:GetMessageData(MsgArg, i); + new Float:flOrigValue = Float:GetMessageOrigData(MsgArg, i); + + if (fabs(flCurValue - flOrigValue) > 0.1 || isModified) + { + server_print(" %-2d %-13s %s ^"%f^" > changed to > ^"%f^"", i, g_MsgArgType[any:type], isModified ? symbolIndicateModified : "-", flOrigValue, flCurValue); + } + else + { + server_print(" %-2d %-13s %s ^"%f^"", i, g_MsgArgType[any:type], isModified ? symbolIndicateModified : "-", flCurValue); + } + } + // Print integer values of argument + else + { + new iCurValue = GetMessageData(MsgArg, i); + new iOrigValue = GetMessageOrigData(MsgArg, i); + + if (iCurValue != iOrigValue || isModified) + { + server_print(" %-2d %-13s %s ^"%i^" > changed to > ^"%i^"", i, g_MsgArgType[any:type], isModified ? symbolIndicateModified : "-", iOrigValue, iCurValue); + } + else + { + server_print(" %-2d %-13s %s ^"%i^"", i, g_MsgArgType[any:type], isModified ? symbolIndicateModified : "-", iCurValue); + } + } + } + + server_print("^n"); +} diff --git a/reapi/include/cssdk/engine/IMessageManager.h b/reapi/include/cssdk/engine/IMessageManager.h index cf818dbc..d0cabb36 100644 --- a/reapi/include/cssdk/engine/IMessageManager.h +++ b/reapi/include/cssdk/engine/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/reapi/src/hook_message_manager.cpp b/reapi/src/hook_message_manager.cpp index 9ecb35d7..6ef4815b 100644 --- a/reapi/src/hook_message_manager.cpp +++ b/reapi/src/hook_message_manager.cpp @@ -15,24 +15,20 @@ IMessage *g_activeMessageContext = nullptr; * @param chain Pointer to the hook chain for the message * @param message Pointer to the message parameters */ -void MessageHookManager::DispatchCallbacks(IVoidHookChain *chain, IMessage *params) +void MessageHookManager::DispatchCallbacks(IVoidHookChain *chain, IMessage *message) { // Get the hook associated with the given message type - MessageHook *msg = getHook(params->getType()); + MessageHook *msg = getHook(message->getId()); // If somehow no hook is found, just continue hookchain if (!msg) { - chain->callNext(params); + chain->callNext(message); return; } // Save the current message context and set the new one IMessage *savedContext = g_activeMessageContext; - g_activeMessageContext = params; - - // Get the entity index of the message (if applicable) - edict_t *entityEdict = params->getEdict(); - int entityIndex = entityEdict ? indexOfEdict(entityEdict) : 0; + g_activeMessageContext = message; int hookState = HC_CONTINUE; @@ -41,7 +37,7 @@ void MessageHookManager::DispatchCallbacks(IVoidHookChain *chain, IM { if (likely(fwd->GetState() == FSTATE_ENABLED)) { - int ret = g_amxxapi.ExecuteForward(fwd->GetFwdIndex(), entityIndex, (cell)params); + int ret = g_amxxapi.ExecuteForward(fwd->GetFwdIndex(), message->getId(), message->getDest(), indexOfEdictAmx(message->getEdict(), 0 /* most friendly to use 0 as invalid index for message */)); if (unlikely(ret == HC_BREAK)) { g_activeMessageContext = savedContext; return; @@ -55,8 +51,8 @@ void MessageHookManager::DispatchCallbacks(IVoidHookChain *chain, IM // If the hook state is not superseded, continue hookchain if (hookState != HC_SUPERCEDE) { g_activeMessageContext = nullptr; - chain->callNext(params); - g_activeMessageContext = savedContext; + chain->callNext(message); + g_activeMessageContext = message; } // Execute post-hooks @@ -64,7 +60,7 @@ void MessageHookManager::DispatchCallbacks(IVoidHookChain *chain, IM { if (likely(fwd->GetState() == FSTATE_ENABLED)) { - int ret = g_amxxapi.ExecuteForward(fwd->GetFwdIndex(), entityIndex, (cell)params); + int ret = g_amxxapi.ExecuteForward(fwd->GetFwdIndex(), message->getId(), message->getDest(), indexOfEdictAmx(message->getEdict(), 0 /* most friendly to use 0 as invalid index for message */)); if (unlikely(ret == HC_BREAK)) break; } @@ -87,7 +83,7 @@ void MessageHookManager::DispatchCallbacks(IVoidHookChain *chain, IM */ cell MessageHookManager::addHook(AMX *amx, int msg_id, const char *funcname, bool post) { - int fwid = g_amxxapi.RegisterSPForwardByName(amx, funcname, FP_CELL, FP_DONE); + int fwid = g_amxxapi.RegisterSPForwardByName(amx, funcname, FP_CELL, FP_CELL, FP_CELL, FP_DONE); if (unlikely(fwid == -1)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: register forward failed.", __FUNCTION__); return 0; @@ -224,7 +220,7 @@ void MessageHookManager::Clear() /** * @brief Dispatches the message callbacks as a routine */ -void MessageHookManager::RoutineMessageCallbacks(IVoidHookChain *chain, IMessage *params) +void MessageHookManager::RoutineMessageCallbacks(IVoidHookChain *chain, IMessage *message) { - g_messageHookManager.DispatchCallbacks(chain, params); + g_messageHookManager.DispatchCallbacks(chain, message); } diff --git a/reapi/src/hook_message_manager.h b/reapi/src/hook_message_manager.h index 0cef91c1..8f183139 100644 --- a/reapi/src/hook_message_manager.h +++ b/reapi/src/hook_message_manager.h @@ -45,10 +45,10 @@ class MessageHookManager }; // Dispatches the callbacks for the message hooks - void DispatchCallbacks(IVoidHookChain *chain, IMessage *params); + void DispatchCallbacks(IVoidHookChain *chain, IMessage *message); // Routine function for dispatching message callbacks - static void RoutineMessageCallbacks(IVoidHookChain *chain, IMessage *params); + static void RoutineMessageCallbacks(IVoidHookChain *chain, IMessage *message); // Getter the message hook by ID MessageHook *getHook(size_t id); diff --git a/reapi/src/mods/mod_rehlds_api.cpp b/reapi/src/mods/mod_rehlds_api.cpp index 7c44c38d..22e1669c 100644 --- a/reapi/src/mods/mod_rehlds_api.cpp +++ b/reapi/src/mods/mod_rehlds_api.cpp @@ -7,6 +7,8 @@ IRehldsHookchains* g_RehldsHookchains; IRehldsServerStatic* g_RehldsSvs; IMessageManager* g_RehldsMessageManager; +void RehldsMessageMngr_Init(); + bool RehldsApi_Init() { #ifdef WIN32 @@ -79,14 +81,43 @@ bool RehldsApi_Init() // message manager is available in "ReHLDS API" >= 3.14 if (majorVersion >= 3 && minorVersion >= 14) + RehldsMessageMngr_Init(); + + return true; +} + +void RehldsMessageMngr_Init() +{ + IMessageManager *messageManager = g_RehldsApi->GetMessageManager(); + + int majorMessageMngrVersion = messageManager->getMajorVersion(); + int minorMessageMngrVersion = messageManager->getMinorVersion(); + + if (majorMessageMngrVersion != MESSAGEMNGR_VERSION_MAJOR) { - IMessageManager *messageManager = g_RehldsApi->GetMessageManager(); - if (messageManager->getMajorVersion() == MESSAGEMNGR_VERSION_MAJOR && - messageManager->getMinorVersion() >= MESSAGEMNGR_VERSION_MINOR) + UTIL_ServerPrint("[%s]: ReHLDS MessageMngr API major version mismatch; expected %d.%d, real %d.%d\n", Plugin_info.logtag, MESSAGEMNGR_VERSION_MAJOR, MESSAGEMNGR_VERSION_MINOR, majorMessageMngrVersion, minorMessageMngrVersion); + + // need to notify that it is necessary to update the ReHLDS + if (majorMessageMngrVersion < MESSAGEMNGR_VERSION_MAJOR) { - g_RehldsMessageManager = messageManager; + UTIL_ServerPrint("[%s]: Please update ReHLDS to a newer version for the required MessageMngr API %d.%d\n", Plugin_info.logtag, MESSAGEMNGR_VERSION_MAJOR, MESSAGEMNGR_VERSION_MINOR); } + + // need to notify that it is necessary to update the module + else if (majorMessageMngrVersion > MESSAGEMNGR_VERSION_MAJOR) + { + UTIL_ServerPrint("[%s]: Please update the %s to a newer version for the required MessageMngr API %d.%d\n", Plugin_info.logtag, Plugin_info.logtag, MESSAGEMNGR_VERSION_MAJOR, MESSAGEMNGR_VERSION_MINOR); + } + + return; } - return true; + if (minorMessageMngrVersion < MESSAGEMNGR_VERSION_MINOR) + { + UTIL_ServerPrint("[%s]: ReHLDS MessageMngr API minor version mismatch; expected at least %d.%d, real %d.%d\n", Plugin_info.logtag, MESSAGEMNGR_VERSION_MAJOR, MESSAGEMNGR_VERSION_MINOR, majorMessageMngrVersion, minorMessageMngrVersion); + UTIL_ServerPrint("[%s]: Please update ReHLDS to a newer version for the required MessageMngr API %d.%d\n", Plugin_info.logtag, MESSAGEMNGR_VERSION_MAJOR, MESSAGEMNGR_VERSION_MINOR); + return; + } + + g_RehldsMessageManager = messageManager; } diff --git a/reapi/src/natives/natives_hookmessage.cpp b/reapi/src/natives/natives_hookmessage.cpp index 3c251829..b56657c1 100644 --- a/reapi/src/natives/natives_hookmessage.cpp +++ b/reapi/src/natives/natives_hookmessage.cpp @@ -1,5 +1,7 @@ #include "precompiled.h" +#define CHECK_PARAMBOUNDS(x, y) if (unlikely(x > (size_t)y)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid message argument %d/max:%d", __FUNCTION__, x, y); } + enum MessageHook { INVALID_MESSAGEHOOK = 0 @@ -12,8 +14,13 @@ enum MessageHook * @param callback The name of the callback function. * @param post Whether the callback should be invoked before or after processing the message. (optional) * -* @note You can modify the message content using SetMessageParam native before the original function is invoked. -* Also can reading the message content using GetMessageParam native. +* @note The callback arguments have: +* msg_id - Message id +* msg_dest - Destination type (see MSG_* constants in messages_const.inc) +* msg_entity - Entity receiving the message +* +* @note You can modify the message content using SetMessageData native before the original function is invoked. +* Also can reading the message content using GetMessageData native. * * In the callback function, use the return values from Hookchain return types, such as HC_CONTINUE, HC_SUPERCEDE, etc. * to control the flow of message processing. @@ -24,11 +31,11 @@ enum MessageHook */ cell AMX_NATIVE_CALL RegisterMessage(AMX *amx, cell *params) { - enum args_e { arg_count, arg_id, arg_handler, arg_post }; + enum args_e { arg_count, arg_msgid, arg_handler, arg_post }; CHECK_REQUIREMENTS(ReHLDS); - int msg_id = params[arg_id]; + int msg_id = params[arg_msgid]; // svc_bad (0) is not allowed for hook if (msg_id <= 0 || msg_id >= MAX_USERMESSAGES) @@ -127,18 +134,18 @@ cell AMX_NATIVE_CALL DisableHookMessage(AMX *amx, cell *params) } /** -* Sets the parameter value for the specified index in the current game message. +* Sets the message data in the current game message. * -* @param index The index of the parameter to set. -* @param value The value to set for the parameter. +* @param type The type of the message data that can be changed +* @param ... Additional args depending on the type of the message argument being retrieved (For more details, look at the enum MsgArgType) * -* @return Returns true if the parameter value is successfully set, otherwise false. +* @return Returns true if the message data is successfully set, otherwise false. * -* native bool:SetMessageParam(const number, any:...); +* native bool:SetMessageData(const MsgDataType:type, any:...); */ -cell AMX_NATIVE_CALL SetMessageParam(AMX *amx, cell *params) +cell AMX_NATIVE_CALL SetMessageData(AMX *amx, cell *params) { - enum args_e { arg_count, arg_number, arg_value }; + enum args_e { arg_count, arg_type, arg_value, arg_param_value }; CHECK_REQUIREMENTS(ReHLDS); @@ -148,41 +155,74 @@ cell AMX_NATIVE_CALL SetMessageParam(AMX *amx, cell *params) return FALSE; } - size_t number = params[arg_number] - 1; - + IMessage::DataType type = static_cast(params[arg_type]); cell *value = getAmxAddr(amx, params[arg_value]); - switch (g_activeMessageContext->getParamType(number)) + switch (type) { - case IMessage::ParamType::String: - char stringbuf[256]; - g_activeMessageContext->setParamString(number, getAmxString(amx, params[arg_value], stringbuf)); + case IMessage::DataType::Dest: + g_activeMessageContext->setDest(static_cast(*value)); break; - case IMessage::ParamType::Angle: - case IMessage::ParamType::Coord: - g_activeMessageContext->setParamFloat(number, *(float *)value); + case IMessage::DataType::Index: + g_activeMessageContext->setId(*value); break; - default: - g_activeMessageContext->setParamInt(number, *value); + case IMessage::DataType::Origin: + g_activeMessageContext->setOrigin(*(Vector *)value); + break; + case IMessage::DataType::Edict: + g_activeMessageContext->setEdict(edictByIndexAmx(*value, 0 /* most friendly to use 0 as invalid index for message */)); break; + case IMessage::DataType::Param: + { + // bool:SetMessageData(MsgDataType:type, const argnumber, const value[]); + cell *value = getAmxAddr(amx, params[arg_param_value]); + size_t number = *getAmxAddr(amx, params[arg_value]) - 1; + + CHECK_PARAMBOUNDS(number, g_activeMessageContext->getParamCount()); + + switch (g_activeMessageContext->getParamType(number)) + { + case IMessage::ParamType::String: + char stringbuf[256]; + g_activeMessageContext->setParamString(number, getAmxString(amx, params[arg_param_value], stringbuf)); + break; + case IMessage::ParamType::Angle: + case IMessage::ParamType::Coord: + g_activeMessageContext->setParamFloat(number, *(float *)value); + break; + case IMessage::ParamType::Byte: + case IMessage::ParamType::Char: + case IMessage::ParamType::Short: + case IMessage::ParamType::Long: + case IMessage::ParamType::Entity: + g_activeMessageContext->setParamInt(number, *value); + break; + default: + return FALSE; + } + + break; + } + default: + return FALSE; } return TRUE; } /** -* Retrieves the parameter value for the specified index in the current game message. +* Gets the message data value in the current game message * -* @param index The index of the parameter to retrieve. -* @param ... Additional parameters depending on the type of the parameter being retrieved. +* @param type The type of message data that can be get +* @param ... Additional args depending on the type of the message argument being retrieved (For more details, look at the enum MsgArgType) * -* @return Returns the retrieved parameter value. +* @return Returns value of argument in the current message * -* native any:GetMessageParam(const number, any:...); +* native any:GetMessageData(MsgDataType:type, any:...); */ -cell AMX_NATIVE_CALL GetMessageParam(AMX *amx, cell *params) +cell AMX_NATIVE_CALL GetMessageData(AMX *amx, cell *params) { - enum args_e { arg_count, arg_number, arg_value, arg_maxlen }; + enum args_e { arg_count, arg_type, arg_value, arg_param_value, arg_maxlen }; CHECK_REQUIREMENTS(ReHLDS); @@ -192,35 +232,57 @@ cell AMX_NATIVE_CALL GetMessageParam(AMX *amx, cell *params) return FALSE; } - size_t number = params[arg_number] - 1; - - cell *dstAddr = getAmxAddr(amx, params[arg_value]); - - switch (g_activeMessageContext->getParamType(number)) - { - case IMessage::ParamType::String: + IMessage::DataType type = static_cast(params[arg_type]); + switch (type) { - if (PARAMS_COUNT != 3) - return FALSE; - - const char *argString = g_activeMessageContext->getParamString(number); - setAmxString(dstAddr, argString ? argString : "", params[arg_maxlen]); + case IMessage::DataType::Dest: + return static_cast(g_activeMessageContext->getDest()); + case IMessage::DataType::Index: + return g_activeMessageContext->getId(); + case IMessage::DataType::Origin: + *(Vector *)getAmxAddr(amx, params[arg_value]) = g_activeMessageContext->getOrigin(); return TRUE; - } - case IMessage::ParamType::Angle: - case IMessage::ParamType::Coord: + case IMessage::DataType::Edict: + return indexOfEdictAmx(g_activeMessageContext->getEdict(), 0 /* most friendly to use 0 as invalid index for message */); + case IMessage::DataType::Param: { - float flValue = g_activeMessageContext->getParamFloat(number); - if (PARAMS_COUNT > 1) - *dstAddr = flValue; - return flValue; + size_t number = *getAmxAddr(amx, params[arg_value]) - 1; // arg_value as number + + CHECK_PARAMBOUNDS(number, g_activeMessageContext->getParamCount()); + + cell *dstAddr = getAmxAddr(amx, params[arg_param_value]); + + switch (g_activeMessageContext->getParamType(number)) + { + case IMessage::ParamType::String: + { + if (PARAMS_COUNT != 4) + return FALSE; + + const char *argString = g_activeMessageContext->getParamString(number); + setAmxString(dstAddr, argString ? argString : "", params[arg_maxlen]); + return TRUE; + } + case IMessage::ParamType::Angle: + case IMessage::ParamType::Coord: + { + float flValue = g_activeMessageContext->getParamFloat(number); + if (PARAMS_COUNT > 2) + *dstAddr = flValue; + return flValue; + } + case IMessage::ParamType::Entity: + case IMessage::ParamType::Byte: + case IMessage::ParamType::Char: + case IMessage::ParamType::Short: + case IMessage::ParamType::Long: + return g_activeMessageContext->getParamInt(number); + default: + break; + } + + break; } - case IMessage::ParamType::Entity: - case IMessage::ParamType::Byte: - case IMessage::ParamType::Char: - case IMessage::ParamType::Short: - case IMessage::ParamType::Long: - return g_activeMessageContext->getParamInt(number); default: break; } @@ -229,17 +291,18 @@ cell AMX_NATIVE_CALL GetMessageParam(AMX *amx, cell *params) } /** -* Retrieves the type of the parameter at the specified index in the current game message. +* Gets the message data original value in the current game message. * -* @param index The index of the parameter to retrieve the type for. +* @param type The type of message data that can be get +* @param ... Additional args depending on the type of the message argument being retrieved (For more details, look at the enum MsgArgType) * -* @return Returns the type of the parameter, look at the enum MsgParamType +* @return Returns original value of argument in the current message * -* native MsgParamType:GetMessageParamType(const number); +* native any:GetMessageOrigData(MsgDataType:type, any:...); */ -cell AMX_NATIVE_CALL GetMessageParamType(AMX *amx, cell *params) +cell AMX_NATIVE_CALL GetMessageOrigData(AMX *amx, cell *params) { - enum args_e { arg_count, arg_number }; + enum args_e { arg_count, arg_type, arg_value, arg_param_value, arg_maxlen }; CHECK_REQUIREMENTS(ReHLDS); @@ -249,52 +312,76 @@ cell AMX_NATIVE_CALL GetMessageParamType(AMX *amx, cell *params) return FALSE; } - size_t number = params[arg_number] - 1; - - size_t paramCount = g_activeMessageContext->getParamCount(); - if (number < 0 || number >= paramCount) + IMessage::DataType type = static_cast(params[arg_type]); + switch (type) { - AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid message argument %d.", __FUNCTION__, number); - return FALSE; - } - - return static_cast(g_activeMessageContext->getParamType(number)); -} - -/** -* Retrieves the number of parameters in the current game message. -* -* @return Returns the number of parameters in the current game message. -* -* native GetMessageParamCount(); -*/ -cell AMX_NATIVE_CALL GetMessageParamCount(AMX *amx, cell *params) -{ - enum args_e { arg_count, arg_number }; - - CHECK_REQUIREMENTS(ReHLDS); - - if (!g_activeMessageContext) + case IMessage::DataType::Dest: + return static_cast(g_activeMessageContext->getOriginalDest()); + case IMessage::DataType::Index: + return g_activeMessageContext->getId(); + case IMessage::DataType::Origin: + *(Vector *)getAmxAddr(amx, params[arg_value]) = g_activeMessageContext->getOriginalOrigin(); + return TRUE; + case IMessage::DataType::Edict: + return indexOfEdictAmx(g_activeMessageContext->getOriginalEdict()); + case IMessage::DataType::Param: { - AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: trying to get argument without active hook.", __FUNCTION__); - return FALSE; + size_t number = *getAmxAddr(amx, params[arg_value]) - 1; // arg_value as number + + CHECK_PARAMBOUNDS(number, g_activeMessageContext->getParamCount()); + + cell *dstAddr = getAmxAddr(amx, params[arg_param_value]); + + switch (g_activeMessageContext->getParamType(number)) + { + case IMessage::ParamType::String: + { + if (PARAMS_COUNT != 4) + return FALSE; + + const char *argString = g_activeMessageContext->getOriginalParamString(number); + setAmxString(dstAddr, argString ? argString : "", params[arg_maxlen]); + return TRUE; + } + case IMessage::ParamType::Angle: + case IMessage::ParamType::Coord: + { + float flValue = g_activeMessageContext->getOriginalParamFloat(number); + if (PARAMS_COUNT > 2) + *dstAddr = flValue; + return flValue; + } + case IMessage::ParamType::Entity: + case IMessage::ParamType::Byte: + case IMessage::ParamType::Char: + case IMessage::ParamType::Short: + case IMessage::ParamType::Long: + return g_activeMessageContext->getOriginalParamInt(number); + default: + break; + } + + break; + } + default: + break; } - return g_activeMessageContext->getParamCount(); + return FALSE; } /** -* Retrieves the origin of the current game message. +* Retrieves the type of the argument at the specified number in the current game message. * -* @param origin An array to store the origin coordinates of the game message. +* @param number The number of the argument to retrieve the type for. * -* @return Returns true if the origin is successfully retrieved, otherwise false. +* @return Returns the type of the argument, look at the enum MsgArgType * -* native bool:GetMessageOrigin(Float:origin[3]); +* native MsgArgType:GetMessageArgType(const number); */ -cell AMX_NATIVE_CALL GetMessageOrigin(AMX *amx, cell *params) +cell AMX_NATIVE_CALL GetMessageArgType(AMX *amx, cell *params) { - enum args_e { arg_count, arg_number, arg_origin }; + enum args_e { arg_count, arg_number }; CHECK_REQUIREMENTS(ReHLDS); @@ -304,35 +391,33 @@ cell AMX_NATIVE_CALL GetMessageOrigin(AMX *amx, cell *params) return FALSE; } - const float *messageOrigin = g_activeMessageContext->getOrigin(); - if (!messageOrigin) - return FALSE; + size_t number = params[arg_number] - 1; - Vector &outVec = *(Vector *)getAmxAddr(amx, params[arg_origin]); - outVec = messageOrigin; - return TRUE; + CHECK_PARAMBOUNDS(number, g_activeMessageContext->getParamCount()); + + return static_cast(g_activeMessageContext->getParamType(number)); } /** -* Retrieves the destination of the current message. +* Retrieves the number of argument in the current game message. * -* @return Returns the destination of the current message. +* @return Returns the number of argument in the current game message. * -* native GetMessageDest(); +* native GetMessageArgsNum(); */ -cell AMX_NATIVE_CALL GetMessageDest(AMX *amx, cell *params) +cell AMX_NATIVE_CALL GetMessageArgsNum(AMX *amx, cell *params) { - enum args_e { arg_count, arg_number, arg_origin }; + enum args_e { arg_count }; CHECK_REQUIREMENTS(ReHLDS); if (!g_activeMessageContext) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: trying to get argument without active hook.", __FUNCTION__); - return -1; + return FALSE; } - return static_cast(g_activeMessageContext->getDest()); + return g_activeMessageContext->getParamCount(); } /** @@ -385,25 +470,120 @@ cell AMX_NATIVE_CALL GetMessageBlock(AMX *amx, cell *params) return static_cast(g_RehldsMessageManager->getMessageBlock(params[arg_id])); } +/** +* Checks if the specified type of message data has been modified +* +* This native allows you to check if any part of the message data, such as its +* destination, type, origin, receiver, or any the specific argument of the message, has been modified +* +* @param type The type of the data to check for modification +* This can be one of the following: +* - MsgAny: Check if any part of the message has been modified +* - MsgDest: Check if the destination has been modified +* - MsgIndex: Check if the message ID has been modified +* - MsgOrigin: Check if the origin has been modified +* - MsgTargetId: Check if the index of the recipient client has been modified +* - MsgArg: Check if a specific argument of the message has been modified +* +* @param number The number of the argument to check for modification (used only when type is MsgDataType:MsgArg) +* Default value is -1, which means the argument number is not applicable +* +* @return Returns true if the specified data type has been modified, false otherwise +* +* native bool:IsMessageDataModified(MsgDataType:type = MsgAny, const number = -1); +*/ +cell AMX_NATIVE_CALL IsMessageDataModified(AMX *amx, cell *params) +{ + CHECK_REQUIREMENTS(ReHLDS); + + enum args_e { arg_count, arg_type, arg_number }; + + CHECK_REQUIREMENTS(ReHLDS); + + if (!g_activeMessageContext) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: trying to get argument without active hook.", __FUNCTION__); + return FALSE; + } + + size_t number = -1; + + IMessage::DataType type = static_cast(params[arg_type]); + if (type == IMessage::DataType::Param) + { + number = params[arg_number] - 1; + + CHECK_PARAMBOUNDS(number, g_activeMessageContext->getParamCount()); + } + + return g_activeMessageContext->isDataModified(type, number) ? TRUE : FALSE; +} + +/** +* Resets a specific type of message data to its original value +* +* @param type The type of the data to check for modification +* This can be one of the following: +* - MsgAny: Reset all modified message data to its original values +* - MsgDest: Reset the destination to its original value +* - MsgIndex: Reset the message ID to its original value +* - MsgOrigin: Reset the origin to its original value +* - MsgTargetId: Reset the index of the recipient client to its original value +* - MsgArg: Reset a specific argument of the message to its original value +* +* @param number The number of the argument to reset (used only when type is MsgDataType:MsgArg) +* Default value is -1, which means all arguments will be reset. +* +* @return Returns true if the modified data type was reset, otherwise false. +* +* native bool:ResetModifiedMessageData(MsgDataType:type = MsgAny, const number = -1); +*/ +cell AMX_NATIVE_CALL ResetModifiedMessageData(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_type, arg_number }; + + CHECK_REQUIREMENTS(ReHLDS); + + if (!g_activeMessageContext) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: trying to set argument without active hook.", __FUNCTION__); + return FALSE; + } + + size_t number = -1; + + IMessage::DataType type = static_cast(params[arg_type]); + if (type == IMessage::DataType::Param && params[arg_number] != -1) + { + number = params[arg_number] - 1; + + CHECK_PARAMBOUNDS(number, g_activeMessageContext->getParamCount()); + } + + return g_activeMessageContext->resetModifiedData(type, number) ? TRUE : FALSE; +} + AMX_NATIVE_INFO HookMessage_Natives[] = { - { "RegisterMessage", RegisterMessage }, - { "UnregisterMessage", UnregisterMessage }, + { "RegisterMessage", RegisterMessage }, + { "UnregisterMessage", UnregisterMessage }, + + { "EnableHookMessage", EnableHookMessage }, + { "DisableHookMessage", DisableHookMessage }, - { "EnableHookMessage", EnableHookMessage }, - { "DisableHookMessage", DisableHookMessage }, + { "SetMessageData", SetMessageData }, + { "GetMessageData", GetMessageData }, - { "GetMessageParam", GetMessageParam }, - { "GetMessageParamType", GetMessageParamType }, - { "GetMessageParamCount", GetMessageParamCount }, + { "GetMessageOrigData", GetMessageOrigData }, - { "GetMessageOrigin", GetMessageOrigin }, - { "GetMessageDest", GetMessageDest }, + { "GetMessageArgType", GetMessageArgType }, + { "GetMessageArgsNum", GetMessageArgsNum }, - { "SetMessageParam", SetMessageParam }, + { "SetMessageBlock", SetMessageBlock }, + { "GetMessageBlock", GetMessageBlock }, - { "SetMessageBlock", SetMessageBlock }, - { "GetMessageBlock", GetMessageBlock }, + { "IsMessageDataModified", IsMessageDataModified }, + { "ResetModifiedMessageData", ResetModifiedMessageData }, { nullptr, nullptr } }; diff --git a/reapi/src/type_conversion.h b/reapi/src/type_conversion.h index 41b9e0c8..456c9d9a 100644 --- a/reapi/src/type_conversion.h +++ b/reapi/src/type_conversion.h @@ -31,9 +31,9 @@ inline size_t indexOfEdictAmx(const entvars_t* pev) return index; } -inline size_t indexOfEdictAmx(const edict_t *pEdict) +inline size_t indexOfEdictAmx(const edict_t *pEdict, const int INVALID_INDEX = AMX_NULLENT) { - size_t index = AMX_NULLENT; + size_t index = INVALID_INDEX; if (likely(pEdict != nullptr)) index = indexOfEdict(pEdict); return index; @@ -54,10 +54,10 @@ inline IGameClient* clientByIndex(const int index) } // safe to index -1 -inline edict_t* edictByIndexAmx(const int index) +inline edict_t* edictByIndexAmx(const int index, const int INVALID_INDEX = AMX_NULLENT) { auto ed = g_pEdicts + index; - if (unlikely(index < 0)) // == AMX_NULLENT + if (unlikely(index <= INVALID_INDEX)) // == AMX_NULLENT ed = nullptr; return ed; }