2
0
mirror of https://github.com/rehlds/reapi.git synced 2024-12-29 08:05:36 +03:00

Rework message hook/natives

This commit is contained in:
s1lentq 2024-05-27 05:08:52 +07:00
parent 06743d6eb9
commit ab14d37b0a
9 changed files with 879 additions and 247 deletions

View File

@ -280,8 +280,13 @@ enum MessageHook
* @param callback The name of the callback function. * @param callback The name of the callback function.
* @param post Whether the callback should be invoked before or after processing the message. (optional) * @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. * @note The callback arguments have:
* Also can reading the message content using GetMessageParam native. * 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. * 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. * to control the flow of message processing.
@ -318,56 +323,50 @@ native bool:EnableHookMessage(const MessageHook:handle);
native bool:DisableHookMessage(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 type The type of the message data that can be changed
* @param value The value to set for the parameter. * @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 type The type of message data that can be get
* @param ... Additional parameters depending on the type of the parameter being retrieved. * @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. * 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(const MsgDataType:type, any:...);
/** /**
* Retrieves the number of parameters in the current game message. * Retrieves the type of the argument at the specified number in the current game message.
* *
* @return Returns the number of parameters in the current game message. * @param number The number of the argument to retrieve the type for.
*
* @return Returns the type of the argument, look at the enum MsgArgType
*/ */
native GetMessageParamCount(); native MsgArgType:GetMessageArgType(const number);
/** /**
* Retrieves the origin of the current game message. * Retrieves the number of argument in the current game message.
* *
* @param origin An array to store the origin coordinates of the game message. * @return Returns the number of argument in the current game message.
*
* @return Returns true if the origin is successfully retrieved, otherwise false.
*/ */
native bool:GetMessageOrigin(Float:origin[3]); native GetMessageArgsNum();
/**
* Retrieves the destination of the current message.
*
* @return Returns the destination of the current message.
*/
native GetMessageDest();
/** /**
* Sets the block type for the specified message ID. * 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 * @return Returns the block type of the specified message, look at the enum MsgBlockType
*/ */
native MsgBlockType:GetMessageBlock(const msgid); 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);

View File

@ -1323,18 +1323,79 @@ enum NetAdrVars
}; };
/** /**
* Message param types used with GetMessageParamType() * Message argument types used with GetMessageArgType()
*/ */
enum MsgParamType enum MsgArgType
{ {
ParamByte, ArgByte,
ParamChar, ArgChar,
ParamShort, ArgShort,
ParamLong, ArgLong,
ParamAngle, ArgAngle,
ParamCoord, ArgCoord,
ParamString, ArgString,
ParamEntity, 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
}; };
/** /**

View File

@ -0,0 +1,210 @@
#include <amxmodx>
#include <reapi>
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");
}

View File

@ -66,7 +66,21 @@ public:
SPEC, // Sends to all spectator proxies 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 * @brief Returns the number of parameters in the message
@ -137,10 +151,10 @@ public:
virtual Dest getDest() const = 0; virtual Dest getDest() const = 0;
/** /**
* @brief Returns the type of the message * @brief Returns the index of the message
* @return The type of the message * @return The index of the message
*/ */
virtual int getType() const = 0; virtual int getId() const = 0;
/** /**
* @brief Returns the origin of the message * @brief Returns the origin of the message
@ -155,10 +169,110 @@ public:
virtual struct edict_s* getEdict() const = 0; virtual struct edict_s* getEdict() const = 0;
/** /**
* @brief Returns whether the message has been modified * @brief Checks if the specified type of message data has been modified
* @return True if the message has been modified, false otherwise *
* 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 isModified() const = 0; 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 // This must be the last virtual function in class
#ifdef REHLDS_SELF #ifdef REHLDS_SELF
@ -167,7 +281,7 @@ public:
#endif #endif
}; };
#define MESSAGEMNGR_VERSION_MAJOR 1 #define MESSAGEMNGR_VERSION_MAJOR 2
#define MESSAGEMNGR_VERSION_MINOR 0 #define MESSAGEMNGR_VERSION_MINOR 0
/** /**
@ -178,7 +292,7 @@ class IMessageManager
public: public:
using hookfunc_t = void (*)(IVoidHookChain<IMessage *> *chain, IMessage *msg); using hookfunc_t = void (*)(IVoidHookChain<IMessage *> *chain, IMessage *msg);
virtual ~IMessageManager() {}; virtual ~IMessageManager() = default;
/** /**
* @brief Returns the major version of the MessageManager * @brief Returns the major version of the MessageManager
@ -194,30 +308,30 @@ public:
/** /**
* @brief Returns the blocking behavior for the given message type * @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 * @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 * @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 * @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 * @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 handler The hook function to register
* @param priority The priority of the hook function (see enum HookChainPriority) * @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 * @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 * @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;
}; };

View File

@ -15,24 +15,20 @@ IMessage *g_activeMessageContext = nullptr;
* @param chain Pointer to the hook chain for the message * @param chain Pointer to the hook chain for the message
* @param message Pointer to the message parameters * @param message Pointer to the message parameters
*/ */
void MessageHookManager::DispatchCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *params) void MessageHookManager::DispatchCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *message)
{ {
// Get the hook associated with the given message type // 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 somehow no hook is found, just continue hookchain
if (!msg) { if (!msg) {
chain->callNext(params); chain->callNext(message);
return; return;
} }
// Save the current message context and set the new one // Save the current message context and set the new one
IMessage *savedContext = g_activeMessageContext; IMessage *savedContext = g_activeMessageContext;
g_activeMessageContext = params; g_activeMessageContext = message;
// Get the entity index of the message (if applicable)
edict_t *entityEdict = params->getEdict();
int entityIndex = entityEdict ? indexOfEdict(entityEdict) : 0;
int hookState = HC_CONTINUE; int hookState = HC_CONTINUE;
@ -41,7 +37,7 @@ void MessageHookManager::DispatchCallbacks(IVoidHookChain<IMessage *> *chain, IM
{ {
if (likely(fwd->GetState() == FSTATE_ENABLED)) 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)) { if (unlikely(ret == HC_BREAK)) {
g_activeMessageContext = savedContext; g_activeMessageContext = savedContext;
return; return;
@ -55,8 +51,8 @@ void MessageHookManager::DispatchCallbacks(IVoidHookChain<IMessage *> *chain, IM
// If the hook state is not superseded, continue hookchain // If the hook state is not superseded, continue hookchain
if (hookState != HC_SUPERCEDE) { if (hookState != HC_SUPERCEDE) {
g_activeMessageContext = nullptr; g_activeMessageContext = nullptr;
chain->callNext(params); chain->callNext(message);
g_activeMessageContext = savedContext; g_activeMessageContext = message;
} }
// Execute post-hooks // Execute post-hooks
@ -64,7 +60,7 @@ void MessageHookManager::DispatchCallbacks(IVoidHookChain<IMessage *> *chain, IM
{ {
if (likely(fwd->GetState() == FSTATE_ENABLED)) 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)) if (unlikely(ret == HC_BREAK))
break; break;
} }
@ -87,7 +83,7 @@ void MessageHookManager::DispatchCallbacks(IVoidHookChain<IMessage *> *chain, IM
*/ */
cell MessageHookManager::addHook(AMX *amx, int msg_id, const char *funcname, bool post) 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)) { if (unlikely(fwid == -1)) {
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: register forward failed.", __FUNCTION__); AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: register forward failed.", __FUNCTION__);
return 0; return 0;
@ -224,7 +220,7 @@ void MessageHookManager::Clear()
/** /**
* @brief Dispatches the message callbacks as a routine * @brief Dispatches the message callbacks as a routine
*/ */
void MessageHookManager::RoutineMessageCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *params) void MessageHookManager::RoutineMessageCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *message)
{ {
g_messageHookManager.DispatchCallbacks(chain, params); g_messageHookManager.DispatchCallbacks(chain, message);
} }

View File

@ -45,10 +45,10 @@ private:
}; };
// Dispatches the callbacks for the message hooks // Dispatches the callbacks for the message hooks
void DispatchCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *params); void DispatchCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *message);
// Routine function for dispatching message callbacks // Routine function for dispatching message callbacks
static void RoutineMessageCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *params); static void RoutineMessageCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *message);
// Getter the message hook by ID // Getter the message hook by ID
MessageHook *getHook(size_t id); MessageHook *getHook(size_t id);

View File

@ -7,6 +7,8 @@ IRehldsHookchains* g_RehldsHookchains;
IRehldsServerStatic* g_RehldsSvs; IRehldsServerStatic* g_RehldsSvs;
IMessageManager* g_RehldsMessageManager; IMessageManager* g_RehldsMessageManager;
void RehldsMessageMngr_Init();
bool RehldsApi_Init() bool RehldsApi_Init()
{ {
#ifdef WIN32 #ifdef WIN32
@ -79,14 +81,43 @@ bool RehldsApi_Init()
// message manager is available in "ReHLDS API" >= 3.14 // message manager is available in "ReHLDS API" >= 3.14
if (majorVersion >= 3 && minorVersion >= 14) if (majorVersion >= 3 && minorVersion >= 14)
{ RehldsMessageMngr_Init();
IMessageManager *messageManager = g_RehldsApi->GetMessageManager();
if (messageManager->getMajorVersion() == MESSAGEMNGR_VERSION_MAJOR &&
messageManager->getMinorVersion() >= MESSAGEMNGR_VERSION_MINOR)
{
g_RehldsMessageManager = messageManager;
}
}
return true; return true;
} }
void RehldsMessageMngr_Init()
{
IMessageManager *messageManager = g_RehldsApi->GetMessageManager();
int majorMessageMngrVersion = messageManager->getMajorVersion();
int minorMessageMngrVersion = messageManager->getMinorVersion();
if (majorMessageMngrVersion != MESSAGEMNGR_VERSION_MAJOR)
{
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)
{
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;
}
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;
}

View File

@ -1,5 +1,7 @@
#include "precompiled.h" #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 enum MessageHook
{ {
INVALID_MESSAGEHOOK = 0 INVALID_MESSAGEHOOK = 0
@ -12,8 +14,13 @@ enum MessageHook
* @param callback The name of the callback function. * @param callback The name of the callback function.
* @param post Whether the callback should be invoked before or after processing the message. (optional) * @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. * @note The callback arguments have:
* Also can reading the message content using GetMessageParam native. * 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. * 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. * to control the flow of message processing.
@ -24,11 +31,11 @@ enum MessageHook
*/ */
cell AMX_NATIVE_CALL RegisterMessage(AMX *amx, cell *params) 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); CHECK_REQUIREMENTS(ReHLDS);
int msg_id = params[arg_id]; int msg_id = params[arg_msgid];
// svc_bad (0) is not allowed for hook // svc_bad (0) is not allowed for hook
if (msg_id <= 0 || msg_id >= MAX_USERMESSAGES) 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 type The type of the message data that can be changed
* @param value The value to set for the parameter. * @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); CHECK_REQUIREMENTS(ReHLDS);
@ -148,41 +155,74 @@ cell AMX_NATIVE_CALL SetMessageParam(AMX *amx, cell *params)
return FALSE; return FALSE;
} }
size_t number = params[arg_number] - 1; IMessage::DataType type = static_cast<IMessage::DataType>(params[arg_type]);
cell *value = getAmxAddr(amx, params[arg_value]); cell *value = getAmxAddr(amx, params[arg_value]);
switch (type)
{
case IMessage::DataType::Dest:
g_activeMessageContext->setDest(static_cast<IMessage::Dest>(*value));
break;
case IMessage::DataType::Index:
g_activeMessageContext->setId(*value);
break;
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)) switch (g_activeMessageContext->getParamType(number))
{ {
case IMessage::ParamType::String: case IMessage::ParamType::String:
char stringbuf[256]; char stringbuf[256];
g_activeMessageContext->setParamString(number, getAmxString(amx, params[arg_value], stringbuf)); g_activeMessageContext->setParamString(number, getAmxString(amx, params[arg_param_value], stringbuf));
break; break;
case IMessage::ParamType::Angle: case IMessage::ParamType::Angle:
case IMessage::ParamType::Coord: case IMessage::ParamType::Coord:
g_activeMessageContext->setParamFloat(number, *(float *)value); g_activeMessageContext->setParamFloat(number, *(float *)value);
break; break;
default: 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); g_activeMessageContext->setParamInt(number, *value);
break; break;
default:
return FALSE;
}
break;
}
default:
return FALSE;
} }
return TRUE; 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 type The type of message data that can be get
* @param ... Additional parameters depending on the type of the parameter being retrieved. * @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); CHECK_REQUIREMENTS(ReHLDS);
@ -192,15 +232,31 @@ cell AMX_NATIVE_CALL GetMessageParam(AMX *amx, cell *params)
return FALSE; return FALSE;
} }
size_t number = params[arg_number] - 1; IMessage::DataType type = static_cast<IMessage::DataType>(params[arg_type]);
switch (type)
{
case IMessage::DataType::Dest:
return static_cast<cell>(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::DataType::Edict:
return indexOfEdictAmx(g_activeMessageContext->getEdict(), 0 /* most friendly to use 0 as invalid index for message */);
case IMessage::DataType::Param:
{
size_t number = *getAmxAddr(amx, params[arg_value]) - 1; // arg_value as number
cell *dstAddr = getAmxAddr(amx, params[arg_value]); CHECK_PARAMBOUNDS(number, g_activeMessageContext->getParamCount());
cell *dstAddr = getAmxAddr(amx, params[arg_param_value]);
switch (g_activeMessageContext->getParamType(number)) switch (g_activeMessageContext->getParamType(number))
{ {
case IMessage::ParamType::String: case IMessage::ParamType::String:
{ {
if (PARAMS_COUNT != 3) if (PARAMS_COUNT != 4)
return FALSE; return FALSE;
const char *argString = g_activeMessageContext->getParamString(number); const char *argString = g_activeMessageContext->getParamString(number);
@ -211,7 +267,7 @@ cell AMX_NATIVE_CALL GetMessageParam(AMX *amx, cell *params)
case IMessage::ParamType::Coord: case IMessage::ParamType::Coord:
{ {
float flValue = g_activeMessageContext->getParamFloat(number); float flValue = g_activeMessageContext->getParamFloat(number);
if (PARAMS_COUNT > 1) if (PARAMS_COUNT > 2)
*dstAddr = flValue; *dstAddr = flValue;
return flValue; return flValue;
} }
@ -225,19 +281,105 @@ cell AMX_NATIVE_CALL GetMessageParam(AMX *amx, cell *params)
break; break;
} }
break;
}
default:
break;
}
return FALSE; return FALSE;
} }
/** /**
* 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_type, arg_value, arg_param_value, arg_maxlen };
CHECK_REQUIREMENTS(ReHLDS);
if (!g_activeMessageContext)
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: trying to get argument without active hook.", __FUNCTION__);
return FALSE;
}
IMessage::DataType type = static_cast<IMessage::DataType>(params[arg_type]);
switch (type)
{
case IMessage::DataType::Dest:
return static_cast<cell>(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:
{
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 FALSE;
}
/**
* Retrieves the type of the argument at the specified number in the current game message.
*
* @param number The number of the argument to retrieve the type for.
*
* @return Returns the type of the argument, look at the enum MsgArgType
*
* native MsgArgType:GetMessageArgType(const number);
*/
cell AMX_NATIVE_CALL GetMessageArgType(AMX *amx, cell *params)
{ {
enum args_e { arg_count, arg_number }; enum args_e { arg_count, arg_number };
@ -251,26 +393,21 @@ cell AMX_NATIVE_CALL GetMessageParamType(AMX *amx, cell *params)
size_t number = params[arg_number] - 1; size_t number = params[arg_number] - 1;
size_t paramCount = g_activeMessageContext->getParamCount(); CHECK_PARAMBOUNDS(number, g_activeMessageContext->getParamCount());
if (number < 0 || number >= paramCount)
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid message argument %d.", __FUNCTION__, number);
return FALSE;
}
return static_cast<cell>(g_activeMessageContext->getParamType(number)); return static_cast<cell>(g_activeMessageContext->getParamType(number));
} }
/** /**
* Retrieves the number of parameters in the current game message. * Retrieves the number of argument in the current game message.
* *
* @return Returns the number of parameters in the current game message. * @return Returns the number of argument in the current game message.
* *
* native GetMessageParamCount(); * native GetMessageArgsNum();
*/ */
cell AMX_NATIVE_CALL GetMessageParamCount(AMX *amx, cell *params) cell AMX_NATIVE_CALL GetMessageArgsNum(AMX *amx, cell *params)
{ {
enum args_e { arg_count, arg_number }; enum args_e { arg_count };
CHECK_REQUIREMENTS(ReHLDS); CHECK_REQUIREMENTS(ReHLDS);
@ -283,58 +420,6 @@ cell AMX_NATIVE_CALL GetMessageParamCount(AMX *amx, cell *params)
return g_activeMessageContext->getParamCount(); return g_activeMessageContext->getParamCount();
} }
/**
* Retrieves the origin of the current game message.
*
* @param origin An array to store the origin coordinates of the game message.
*
* @return Returns true if the origin is successfully retrieved, otherwise false.
*
* native bool:GetMessageOrigin(Float:origin[3]);
*/
cell AMX_NATIVE_CALL GetMessageOrigin(AMX *amx, cell *params)
{
enum args_e { arg_count, arg_number, arg_origin };
CHECK_REQUIREMENTS(ReHLDS);
if (!g_activeMessageContext)
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: trying to get argument without active hook.", __FUNCTION__);
return FALSE;
}
const float *messageOrigin = g_activeMessageContext->getOrigin();
if (!messageOrigin)
return FALSE;
Vector &outVec = *(Vector *)getAmxAddr(amx, params[arg_origin]);
outVec = messageOrigin;
return TRUE;
}
/**
* Retrieves the destination of the current message.
*
* @return Returns the destination of the current message.
*
* native GetMessageDest();
*/
cell AMX_NATIVE_CALL GetMessageDest(AMX *amx, cell *params)
{
enum args_e { arg_count, arg_number, arg_origin };
CHECK_REQUIREMENTS(ReHLDS);
if (!g_activeMessageContext)
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: trying to get argument without active hook.", __FUNCTION__);
return -1;
}
return static_cast<cell>(g_activeMessageContext->getDest());
}
/** /**
* Sets the block type for the specified message ID. * Sets the block type for the specified message ID.
* *
@ -385,6 +470,99 @@ cell AMX_NATIVE_CALL GetMessageBlock(AMX *amx, cell *params)
return static_cast<cell>(g_RehldsMessageManager->getMessageBlock(params[arg_id])); return static_cast<cell>(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<IMessage::DataType>(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<IMessage::DataType>(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[] = AMX_NATIVE_INFO HookMessage_Natives[] =
{ {
{ "RegisterMessage", RegisterMessage }, { "RegisterMessage", RegisterMessage },
@ -393,18 +571,20 @@ AMX_NATIVE_INFO HookMessage_Natives[] =
{ "EnableHookMessage", EnableHookMessage }, { "EnableHookMessage", EnableHookMessage },
{ "DisableHookMessage", DisableHookMessage }, { "DisableHookMessage", DisableHookMessage },
{ "GetMessageParam", GetMessageParam }, { "SetMessageData", SetMessageData },
{ "GetMessageParamType", GetMessageParamType }, { "GetMessageData", GetMessageData },
{ "GetMessageParamCount", GetMessageParamCount },
{ "GetMessageOrigin", GetMessageOrigin }, { "GetMessageOrigData", GetMessageOrigData },
{ "GetMessageDest", GetMessageDest },
{ "SetMessageParam", SetMessageParam }, { "GetMessageArgType", GetMessageArgType },
{ "GetMessageArgsNum", GetMessageArgsNum },
{ "SetMessageBlock", SetMessageBlock }, { "SetMessageBlock", SetMessageBlock },
{ "GetMessageBlock", GetMessageBlock }, { "GetMessageBlock", GetMessageBlock },
{ "IsMessageDataModified", IsMessageDataModified },
{ "ResetModifiedMessageData", ResetModifiedMessageData },
{ nullptr, nullptr } { nullptr, nullptr }
}; };

View File

@ -31,9 +31,9 @@ inline size_t indexOfEdictAmx(const entvars_t* pev)
return index; 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)) if (likely(pEdict != nullptr))
index = indexOfEdict(pEdict); index = indexOfEdict(pEdict);
return index; return index;
@ -54,10 +54,10 @@ inline IGameClient* clientByIndex(const int index)
} }
// safe to index -1 // 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; auto ed = g_pEdicts + index;
if (unlikely(index < 0)) // == AMX_NULLENT if (unlikely(index <= INVALID_INDEX)) // == AMX_NULLENT
ed = nullptr; ed = nullptr;
return ed; return ed;
} }