mirror of
https://github.com/rehlds/reapi.git
synced 2024-12-29 08:05:36 +03:00
Implement message hook using ReHLDS API
This commit is contained in:
parent
92c13f99e6
commit
b757be53f5
@ -115,6 +115,7 @@ set(REAPI_SRCS
|
|||||||
"src/hook_callback.cpp"
|
"src/hook_callback.cpp"
|
||||||
"src/hook_list.cpp"
|
"src/hook_list.cpp"
|
||||||
"src/hook_manager.cpp"
|
"src/hook_manager.cpp"
|
||||||
|
"src/hook_message_manager.cpp"
|
||||||
"src/api_config.cpp"
|
"src/api_config.cpp"
|
||||||
"src/member_list.cpp"
|
"src/member_list.cpp"
|
||||||
"src/meta_api.cpp"
|
"src/meta_api.cpp"
|
||||||
@ -122,6 +123,7 @@ set(REAPI_SRCS
|
|||||||
"src/sdk_util.cpp"
|
"src/sdk_util.cpp"
|
||||||
"src/natives/natives_common.cpp"
|
"src/natives/natives_common.cpp"
|
||||||
"src/natives/natives_hookchains.cpp"
|
"src/natives/natives_hookchains.cpp"
|
||||||
|
"src/natives/natives_message.cpp"
|
||||||
"src/natives/natives_members.cpp"
|
"src/natives/natives_members.cpp"
|
||||||
"src/natives/natives_misc.cpp"
|
"src/natives/natives_misc.cpp"
|
||||||
"src/natives/natives_rechecker.cpp"
|
"src/natives/natives_rechecker.cpp"
|
||||||
|
@ -266,3 +266,124 @@ native rh_get_net_from(output[], len);
|
|||||||
* @return Netchan connection time in seconds or 0 if client index is invalid or client is not connected
|
* @return Netchan connection time in seconds or 0 if client index is invalid or client is not connected
|
||||||
*/
|
*/
|
||||||
native rh_get_client_connect_time(const index);
|
native rh_get_client_connect_time(const index);
|
||||||
|
|
||||||
|
|
||||||
|
enum MessageHook
|
||||||
|
{
|
||||||
|
INVALID_MESSAGEHOOK = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a callback function to be called when a game message with the specified ID is received.
|
||||||
|
*
|
||||||
|
* @param msg_id The ID of the message to register the callback for.
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @return Returns a handle to the registered message hook.
|
||||||
|
*/
|
||||||
|
native MessageHook:RegisterMessage(const msg_id, const callback[], post = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a game message hook identified by the specified handle.
|
||||||
|
*
|
||||||
|
* @param handle The handle of the message hook to unregister.
|
||||||
|
*
|
||||||
|
* @return Returns true if the message hook is successfully unregistered, otherwise false.
|
||||||
|
*/
|
||||||
|
native bool:UnregisterMessage(const MessageHook:handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables a game message hook identified by the specified handle.
|
||||||
|
*
|
||||||
|
* @param handle The handle of the message hook to enable.
|
||||||
|
*
|
||||||
|
* @return Returns true if the message hook is successfully enabled, otherwise false.
|
||||||
|
*/
|
||||||
|
native bool:EnableHookMessage(const MessageHook:handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables a game message hook identified by the specified handle.
|
||||||
|
*
|
||||||
|
* @param handle The handle of the message hook to disable.
|
||||||
|
*
|
||||||
|
* @return Returns true if the message hook is successfully disabled, otherwise false.
|
||||||
|
*/
|
||||||
|
native bool:DisableHookMessage(const MessageHook:handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the parameter value for the specified index in the current game message.
|
||||||
|
*
|
||||||
|
* @param index The index of the parameter to set.
|
||||||
|
* @param value The value to set for the parameter.
|
||||||
|
*
|
||||||
|
* @return Returns true if the parameter value is successfully set, otherwise false.
|
||||||
|
*/
|
||||||
|
native bool:SetMessageParam(const number, any:...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the parameter value for the specified index 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.
|
||||||
|
*
|
||||||
|
* @return Returns the retrieved parameter value.
|
||||||
|
*/
|
||||||
|
native any:GetMessageParam(const number, 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.
|
||||||
|
*
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* @return Returns the number of parameters in the current game message.
|
||||||
|
*/
|
||||||
|
native GetMessageParamCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param msgid The ID of the message to set the block type for.
|
||||||
|
* @param type The type of block to set for the message, look at the enum MsgBlockType
|
||||||
|
*
|
||||||
|
* @return Returns true if the block type is successfully set, otherwise false.
|
||||||
|
*/
|
||||||
|
native bool:SetMessageBlock(const msgid, MsgBlockType:type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the block type for the specified message ID.
|
||||||
|
*
|
||||||
|
* @param msgid The ID of the message to retrieve the block type for.
|
||||||
|
*
|
||||||
|
* @return Returns the block type of the specified message, look at the enum MsgBlockType
|
||||||
|
*/
|
||||||
|
native MsgBlockType:GetMessageBlock(const msgid);
|
||||||
|
@ -22,7 +22,7 @@ enum CheckVisibilityType
|
|||||||
VisibilityInPAS // Check in Potentially Audible Set (PAS)
|
VisibilityInPAS // Check in Potentially Audible Set (PAS)
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* For RH_SV_AddResource hook
|
* For RH_SV_AddResource hook
|
||||||
*/
|
*/
|
||||||
enum ResourceType_t
|
enum ResourceType_t
|
||||||
@ -1321,3 +1321,29 @@ enum NetAdrVars
|
|||||||
*/
|
*/
|
||||||
netadr_port
|
netadr_port
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message param types used with GetMessageParamType()
|
||||||
|
*/
|
||||||
|
enum MsgParamType
|
||||||
|
{
|
||||||
|
ParamByte,
|
||||||
|
ParamChar,
|
||||||
|
ParamShort,
|
||||||
|
ParamLong,
|
||||||
|
ParamAngle,
|
||||||
|
ParamCoord,
|
||||||
|
ParamString,
|
||||||
|
ParamEntity,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocking behavior types for messages
|
||||||
|
* Flags for natives SetMessageBlock()/GetMessageBlock()
|
||||||
|
*/
|
||||||
|
enum MsgBlockType
|
||||||
|
{
|
||||||
|
MSG_BLOCK_NOT, // Not a block
|
||||||
|
MSG_BLOCK_ONCE, // Block once
|
||||||
|
MSG_BLOCK_SET // Set block
|
||||||
|
};
|
||||||
|
@ -146,6 +146,7 @@
|
|||||||
<ClInclude Include="..\include\cssdk\engine\hookchains.h">
|
<ClInclude Include="..\include\cssdk\engine\hookchains.h">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\cssdk\engine\IMessageManager.h" />
|
||||||
<ClInclude Include="..\include\cssdk\engine\keydefs.h" />
|
<ClInclude Include="..\include\cssdk\engine\keydefs.h" />
|
||||||
<ClInclude Include="..\include\cssdk\engine\maintypes.h" />
|
<ClInclude Include="..\include\cssdk\engine\maintypes.h" />
|
||||||
<ClInclude Include="..\include\cssdk\engine\model.h" />
|
<ClInclude Include="..\include\cssdk\engine\model.h" />
|
||||||
@ -217,6 +218,7 @@
|
|||||||
<ClInclude Include="..\src\hook_list.h" />
|
<ClInclude Include="..\src\hook_list.h" />
|
||||||
<ClInclude Include="..\src\main.h" />
|
<ClInclude Include="..\src\main.h" />
|
||||||
<ClInclude Include="..\src\member_list.h" />
|
<ClInclude Include="..\src\member_list.h" />
|
||||||
|
<ClInclude Include="..\src\hook_message_manager.h" />
|
||||||
<ClInclude Include="..\src\mods\mod_rechecker_api.h" />
|
<ClInclude Include="..\src\mods\mod_rechecker_api.h" />
|
||||||
<ClInclude Include="..\src\mods\mod_regamedll_api.h" />
|
<ClInclude Include="..\src\mods\mod_regamedll_api.h" />
|
||||||
<ClInclude Include="..\src\mods\mod_rehlds_api.h" />
|
<ClInclude Include="..\src\mods\mod_rehlds_api.h" />
|
||||||
@ -227,6 +229,7 @@
|
|||||||
<ClInclude Include="..\src\natives\natives_helper.h" />
|
<ClInclude Include="..\src\natives\natives_helper.h" />
|
||||||
<ClInclude Include="..\src\natives\natives_hookchains.h" />
|
<ClInclude Include="..\src\natives\natives_hookchains.h" />
|
||||||
<ClInclude Include="..\src\natives\natives_members.h" />
|
<ClInclude Include="..\src\natives\natives_members.h" />
|
||||||
|
<ClInclude Include="..\src\natives\natives_hookmessage.h" />
|
||||||
<ClInclude Include="..\src\natives\natives_misc.h" />
|
<ClInclude Include="..\src\natives\natives_misc.h" />
|
||||||
<ClInclude Include="..\src\natives\natives_rechecker.h" />
|
<ClInclude Include="..\src\natives\natives_rechecker.h" />
|
||||||
<ClInclude Include="..\src\natives\natives_reunion.h" />
|
<ClInclude Include="..\src\natives\natives_reunion.h" />
|
||||||
@ -266,6 +269,7 @@
|
|||||||
</ExcludedFromBuild>
|
</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\src\main.cpp" />
|
<ClCompile Include="..\src\main.cpp" />
|
||||||
|
<ClCompile Include="..\src\hook_message_manager.cpp" />
|
||||||
<ClCompile Include="..\src\meta_api.cpp" />
|
<ClCompile Include="..\src\meta_api.cpp" />
|
||||||
<ClCompile Include="..\src\mods\mod_rechecker_api.cpp" />
|
<ClCompile Include="..\src\mods\mod_rechecker_api.cpp" />
|
||||||
<ClCompile Include="..\src\mods\mod_regamedll_api.cpp" />
|
<ClCompile Include="..\src\mods\mod_regamedll_api.cpp" />
|
||||||
@ -276,6 +280,7 @@
|
|||||||
<ClCompile Include="..\src\natives\natives_common.cpp" />
|
<ClCompile Include="..\src\natives\natives_common.cpp" />
|
||||||
<ClCompile Include="..\src\natives\natives_hookchains.cpp" />
|
<ClCompile Include="..\src\natives\natives_hookchains.cpp" />
|
||||||
<ClCompile Include="..\src\natives\natives_members.cpp" />
|
<ClCompile Include="..\src\natives\natives_members.cpp" />
|
||||||
|
<ClCompile Include="..\src\natives\natives_hookmessage.cpp" />
|
||||||
<ClCompile Include="..\src\natives\natives_misc.cpp" />
|
<ClCompile Include="..\src\natives\natives_misc.cpp" />
|
||||||
<ClCompile Include="..\src\natives\natives_rechecker.cpp" />
|
<ClCompile Include="..\src\natives\natives_rechecker.cpp" />
|
||||||
<ClCompile Include="..\src\natives\natives_reunion.cpp" />
|
<ClCompile Include="..\src\natives\natives_reunion.cpp" />
|
||||||
|
@ -726,6 +726,15 @@
|
|||||||
<ClInclude Include="..\include\cssdk\dlls\gib.h">
|
<ClInclude Include="..\include\cssdk\dlls\gib.h">
|
||||||
<Filter>include\cssdk\dlls</Filter>
|
<Filter>include\cssdk\dlls</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\cssdk\engine\IMessageManager.h">
|
||||||
|
<Filter>include\cssdk\engine</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\hook_message_manager.h">
|
||||||
|
<Filter>src</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\natives\natives_hookmessage.h">
|
||||||
|
<Filter>src\natives</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\include\cssdk\common\parsemsg.cpp">
|
<ClCompile Include="..\include\cssdk\common\parsemsg.cpp">
|
||||||
@ -830,6 +839,12 @@
|
|||||||
<ClCompile Include="..\src\amx_hook.cpp">
|
<ClCompile Include="..\src\amx_hook.cpp">
|
||||||
<Filter>src</Filter>
|
<Filter>src</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\hook_message_manager.cpp">
|
||||||
|
<Filter>src</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\natives\natives_hookmessage.cpp">
|
||||||
|
<Filter>src\natives</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\extra\amxmodx\scripting\include\reapi.inc">
|
<None Include="..\extra\amxmodx\scripting\include\reapi.inc">
|
||||||
|
@ -162,6 +162,7 @@ C_DLLEXPORT int AMXX_Attach(PFN_REQ_FNPTR reqFnptrFunc)
|
|||||||
OnAmxxAttach();
|
OnAmxxAttach();
|
||||||
|
|
||||||
RegisterNatives_HookChains();
|
RegisterNatives_HookChains();
|
||||||
|
RegisterNatives_HookMessage();
|
||||||
RegisterNatives_Members();
|
RegisterNatives_Members();
|
||||||
RegisterNatives_Misc();
|
RegisterNatives_Misc();
|
||||||
RegisterNatives_VTC();
|
RegisterNatives_VTC();
|
||||||
|
230
reapi/src/hook_message_manager.cpp
Normal file
230
reapi/src/hook_message_manager.cpp
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
#include "precompiled.h"
|
||||||
|
|
||||||
|
// Global instance of the message hook manager
|
||||||
|
MessageHookManager g_messageHookManager;
|
||||||
|
|
||||||
|
// Pointer to the message context within an active hook
|
||||||
|
IMessage *g_activeMessageContext = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dispatches the callbacks associated with the given message
|
||||||
|
*
|
||||||
|
* This function executes the hooks associated with the given message type,
|
||||||
|
* allowing modifications or interception of the message's behavior
|
||||||
|
*
|
||||||
|
* @param chain Pointer to the hook chain for the message
|
||||||
|
* @param message Pointer to the message parameters
|
||||||
|
*/
|
||||||
|
void MessageHookManager::DispatchCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *params)
|
||||||
|
{
|
||||||
|
// Get the hook associated with the given message type
|
||||||
|
MessageHook *msg = getHook(params->getType());
|
||||||
|
|
||||||
|
// If somehow no hook is found, just continue hookchain
|
||||||
|
if (!msg) {
|
||||||
|
chain->callNext(params);
|
||||||
|
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;
|
||||||
|
|
||||||
|
int hookState = HC_CONTINUE;
|
||||||
|
|
||||||
|
// Execute pre-hooks
|
||||||
|
for (const CAmxxHookBase *fwd : msg->pre)
|
||||||
|
{
|
||||||
|
if (likely(fwd->GetState() == FSTATE_ENABLED))
|
||||||
|
{
|
||||||
|
int ret = g_amxxapi.ExecuteForward(fwd->GetFwdIndex(), entityIndex, (cell)params);
|
||||||
|
if (unlikely(ret == HC_BREAK)) {
|
||||||
|
g_activeMessageContext = savedContext;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(ret > hookState))
|
||||||
|
hookState = ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the hook state is not superseded, continue hookchain
|
||||||
|
if (hookState != HC_SUPERCEDE) {
|
||||||
|
g_activeMessageContext = nullptr;
|
||||||
|
chain->callNext(params);
|
||||||
|
g_activeMessageContext = savedContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute post-hooks
|
||||||
|
for (const CAmxxHookBase *fwd : msg->post)
|
||||||
|
{
|
||||||
|
if (likely(fwd->GetState() == FSTATE_ENABLED))
|
||||||
|
{
|
||||||
|
int ret = g_amxxapi.ExecuteForward(fwd->GetFwdIndex(), entityIndex, (cell)params);
|
||||||
|
if (unlikely(ret == HC_BREAK))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the original message context
|
||||||
|
g_activeMessageContext = savedContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a hook for the specified message ID
|
||||||
|
*
|
||||||
|
* This function registers a new hook for the specified message ID and associates it with the provided function
|
||||||
|
*
|
||||||
|
* @param msg_id ID of the message to hook
|
||||||
|
* @param funcname Name of the function to call when the hook is triggered
|
||||||
|
* @param post Indicates whether the hook should be executed after the default behavior (true) or before (false)
|
||||||
|
*
|
||||||
|
* @return Returns a handle to the registered hook, or 0 if the registration fails
|
||||||
|
*/
|
||||||
|
cell MessageHookManager::addHook(AMX *amx, int msg_id, const char *funcname, bool post)
|
||||||
|
{
|
||||||
|
int fwid = g_amxxapi.RegisterSPForwardByName(amx, funcname, FP_CELL, FP_DONE);
|
||||||
|
if (unlikely(fwid == -1)) {
|
||||||
|
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: register forward failed.", __FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the message hook associated with the ID
|
||||||
|
MessageHook &msg = hooks[msg_id];
|
||||||
|
|
||||||
|
// If it's the first hook for this message, register it with message manager
|
||||||
|
if (!msg.post.size() && !msg.pre.size())
|
||||||
|
{
|
||||||
|
msg.id = msg_id;
|
||||||
|
g_RehldsMessageManager->registerHook(msg_id, RoutineMessageCallbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine whether to add the hook to the pre or post vector
|
||||||
|
std::vector<CAmxxHookBase *> &dest = post ? msg.post : msg.pre;
|
||||||
|
|
||||||
|
// Pack msg_id and forward ID into the handle value
|
||||||
|
cell handle = (msg_id * MAX_USERMESSAGES) + dest.size() + 1;
|
||||||
|
|
||||||
|
dest.emplace_back(new CAmxxHookBase(amx, funcname, fwid, -1));
|
||||||
|
|
||||||
|
return post ? -handle : handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a hook associated with the specified handle
|
||||||
|
*
|
||||||
|
* This function removes the hook associated with the given handle from the hook manager
|
||||||
|
*
|
||||||
|
* @param handle Handle to the hook to be removed
|
||||||
|
*
|
||||||
|
* @return Returns true if the hook is successfully removed, false otherwise
|
||||||
|
*/
|
||||||
|
bool MessageHookManager::removeHook(AMX *amx, cell handle)
|
||||||
|
{
|
||||||
|
// Determine whether the hook is a post-hook
|
||||||
|
bool post = handle < 0;
|
||||||
|
if (post)
|
||||||
|
handle = ~handle;
|
||||||
|
else
|
||||||
|
handle--;
|
||||||
|
|
||||||
|
// Unpack the message ID and forward ID from the handle
|
||||||
|
const size_t id = handle / MAX_USERMESSAGES;
|
||||||
|
const size_t fwid = handle & (MAX_USERMESSAGES - 1);
|
||||||
|
|
||||||
|
// Get the message hook by ID, returns nullptr if the ID is invalid
|
||||||
|
MessageHook *msg = getHook(id);
|
||||||
|
if (msg)
|
||||||
|
{
|
||||||
|
// Get the appropriate vector of hooks (pre or post)
|
||||||
|
std::vector<CAmxxHookBase *> &forwards = post ? msg->post : msg->pre;
|
||||||
|
|
||||||
|
// Check if the forward ID is within the vector bounds
|
||||||
|
if (fwid < forwards.size())
|
||||||
|
{
|
||||||
|
// Delete the hook and erase it from the vector
|
||||||
|
delete forwards[fwid];
|
||||||
|
forwards.erase(forwards.begin() + fwid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the AMXX hook associated with the specified handle
|
||||||
|
*
|
||||||
|
* This function returns the AMXX hook associated with the provided handle
|
||||||
|
*
|
||||||
|
* @param handle Handle of the hook to retrieve
|
||||||
|
*
|
||||||
|
* @return Pointer to the AMXX hook if found, nullptr otherwise
|
||||||
|
*/
|
||||||
|
CAmxxHookBase *MessageHookManager::getAmxxHook(cell handle)
|
||||||
|
{
|
||||||
|
// Determine whether the hook is a post-hook
|
||||||
|
bool post = handle < 0;
|
||||||
|
if (post)
|
||||||
|
handle = ~handle;
|
||||||
|
else
|
||||||
|
handle--;
|
||||||
|
|
||||||
|
// Unpack the message ID and forward ID from the handle
|
||||||
|
const size_t id = handle / MAX_USERMESSAGES;
|
||||||
|
const size_t fwid = handle & (MAX_USERMESSAGES - 1);
|
||||||
|
|
||||||
|
// Get the message hook by ID, returns nullptr if the ID is invalid
|
||||||
|
MessageHook *msg = getHook(id);
|
||||||
|
if (msg)
|
||||||
|
{
|
||||||
|
// Get the appropriate vector of hooks (pre or post)
|
||||||
|
std::vector<CAmxxHookBase *> &forwards = post ? msg->post : msg->pre;
|
||||||
|
|
||||||
|
// Check if the forward ID is within the vector bounds
|
||||||
|
if (fwid < forwards.size())
|
||||||
|
return forwards[fwid];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the message hook by ID.
|
||||||
|
*
|
||||||
|
* This function safely retrieves the message hook associated with the provided ID.
|
||||||
|
*
|
||||||
|
* @param id ID of the message hook to retrieve.
|
||||||
|
*
|
||||||
|
* @return Pointer to the message hook if found, nullptr otherwise.
|
||||||
|
*/
|
||||||
|
MessageHookManager::MessageHook *MessageHookManager::getHook(size_t id)
|
||||||
|
{
|
||||||
|
if (id <= 0 || id >= MAX_USERMESSAGES)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return &hooks[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears all registered message hooks
|
||||||
|
*
|
||||||
|
* This function clears all registered message hooks from the hook manager
|
||||||
|
*/
|
||||||
|
void MessageHookManager::Clear()
|
||||||
|
{
|
||||||
|
for (auto &h : hooks)
|
||||||
|
h.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dispatches the message callbacks as a routine
|
||||||
|
*/
|
||||||
|
void MessageHookManager::RoutineMessageCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *params)
|
||||||
|
{
|
||||||
|
g_messageHookManager.DispatchCallbacks(chain, params);
|
||||||
|
}
|
64
reapi/src/hook_message_manager.h
Normal file
64
reapi/src/hook_message_manager.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
// Class managing hooks for game messages
|
||||||
|
class MessageHookManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Adds a hook for a game message
|
||||||
|
cell addHook(AMX *amx, int msg_id, const char *funcname, bool post);
|
||||||
|
|
||||||
|
// Removes a hook with the given handle
|
||||||
|
bool removeHook(AMX *amx, cell handle);
|
||||||
|
|
||||||
|
// Clears all hooks
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
// Get the AMXX hook with the given handle
|
||||||
|
CAmxxHookBase *getAmxxHook(cell handle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class MessageHook
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Clears all hooks associated with this message
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if (post.size() || pre.size()) {
|
||||||
|
for (CAmxxHookBase *h : post)
|
||||||
|
delete h;
|
||||||
|
post.clear();
|
||||||
|
|
||||||
|
for (CAmxxHookBase *h : pre)
|
||||||
|
delete h;
|
||||||
|
pre.clear();
|
||||||
|
|
||||||
|
// Unregister the message hook
|
||||||
|
if (g_RehldsMessageManager)
|
||||||
|
g_RehldsMessageManager->unregisterHook(id, RoutineMessageCallbacks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int id;
|
||||||
|
std::vector<CAmxxHookBase *> pre, post;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Dispatches the callbacks for the message hooks
|
||||||
|
void DispatchCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *params);
|
||||||
|
|
||||||
|
// Routine function for dispatching message callbacks
|
||||||
|
static void RoutineMessageCallbacks(IVoidHookChain<IMessage *> *chain, IMessage *params);
|
||||||
|
|
||||||
|
// Getter the message hook by ID
|
||||||
|
MessageHook *getHook(size_t id);
|
||||||
|
|
||||||
|
// Array of message hooks
|
||||||
|
std::array<MessageHook, MAX_USERMESSAGES> hooks;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Global instance of the message hook manager
|
||||||
|
extern MessageHookManager g_messageHookManager;
|
||||||
|
|
||||||
|
// Pointer to the message context within an active hook
|
||||||
|
extern IMessage *g_activeMessageContext;
|
@ -42,6 +42,7 @@ void OnMetaDetach()
|
|||||||
{
|
{
|
||||||
// clear all hooks?
|
// clear all hooks?
|
||||||
g_hookManager.Clear();
|
g_hookManager.Clear();
|
||||||
|
g_messageHookManager.Clear();
|
||||||
g_queryFileManager.Clear();
|
g_queryFileManager.Clear();
|
||||||
|
|
||||||
if (api_cfg.hasVTC()) {
|
if (api_cfg.hasVTC()) {
|
||||||
@ -68,6 +69,7 @@ void ServerDeactivate_Post()
|
|||||||
g_pEdicts = nullptr;
|
g_pEdicts = nullptr;
|
||||||
api_cfg.ServerDeactivate();
|
api_cfg.ServerDeactivate();
|
||||||
g_hookManager.Clear();
|
g_hookManager.Clear();
|
||||||
|
g_messageHookManager.Clear();
|
||||||
g_queryFileManager.Clear();
|
g_queryFileManager.Clear();
|
||||||
EntityCallbackDispatcher().DeleteAllCallbacks();
|
EntityCallbackDispatcher().DeleteAllCallbacks();
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ const RehldsFuncs_t* g_RehldsFuncs;
|
|||||||
IRehldsServerData* g_RehldsData;
|
IRehldsServerData* g_RehldsData;
|
||||||
IRehldsHookchains* g_RehldsHookchains;
|
IRehldsHookchains* g_RehldsHookchains;
|
||||||
IRehldsServerStatic* g_RehldsSvs;
|
IRehldsServerStatic* g_RehldsSvs;
|
||||||
|
IMessageManager* g_RehldsMessageManager;
|
||||||
|
|
||||||
bool RehldsApi_Init()
|
bool RehldsApi_Init()
|
||||||
{
|
{
|
||||||
@ -74,6 +75,14 @@ bool RehldsApi_Init()
|
|||||||
g_RehldsData = g_RehldsApi->GetServerData();
|
g_RehldsData = g_RehldsApi->GetServerData();
|
||||||
g_RehldsHookchains = g_RehldsApi->GetHookchains();
|
g_RehldsHookchains = g_RehldsApi->GetHookchains();
|
||||||
g_RehldsSvs = g_RehldsApi->GetServerStatic();
|
g_RehldsSvs = g_RehldsApi->GetServerStatic();
|
||||||
|
g_RehldsMessageManager = nullptr;
|
||||||
|
|
||||||
|
IMessageManager *messageManager = g_RehldsApi->GetMessageManager();
|
||||||
|
if (messageManager->getMajorVersion() == MESSAGEMNGR_VERSION_MAJOR &&
|
||||||
|
messageManager->getMinorVersion() >= MESSAGEMNGR_VERSION_MINOR)
|
||||||
|
{
|
||||||
|
g_RehldsMessageManager = messageManager;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,6 @@ extern const RehldsFuncs_t* g_RehldsFuncs;
|
|||||||
extern IRehldsServerData* g_RehldsData;
|
extern IRehldsServerData* g_RehldsData;
|
||||||
extern IRehldsHookchains* g_RehldsHookchains;
|
extern IRehldsHookchains* g_RehldsHookchains;
|
||||||
extern IRehldsServerStatic* g_RehldsSvs;
|
extern IRehldsServerStatic* g_RehldsSvs;
|
||||||
|
extern IMessageManager* g_RehldsMessageManager;
|
||||||
|
|
||||||
extern bool RehldsApi_Init();
|
extern bool RehldsApi_Init();
|
@ -7,6 +7,7 @@
|
|||||||
#define CHECK_GAMERULES() if (unlikely(!g_pGameRules)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: gamerules not initialized", __FUNCTION__); return FALSE; }
|
#define CHECK_GAMERULES() if (unlikely(!g_pGameRules)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: gamerules not initialized", __FUNCTION__); return FALSE; }
|
||||||
#define CHECK_CONNECTED(x, y) if (unlikely(x == nullptr || x->has_disconnected)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %i is not connected", __FUNCTION__, params[y]); return FALSE; }
|
#define CHECK_CONNECTED(x, y) if (unlikely(x == nullptr || x->has_disconnected)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %i is not connected", __FUNCTION__, params[y]); return FALSE; }
|
||||||
#define CHECK_INSTANCE_OF(x, y) if (unlikely(dynamic_cast<x *>((x::BaseClass *)y) == nullptr)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid entity %d ('%s'), is not an instance of the base class '%s'", __FUNCTION__, indexOfEdict(y->pev), STRING(y->pev->classname), #x); return FALSE; }
|
#define CHECK_INSTANCE_OF(x, y) if (unlikely(dynamic_cast<x *>((x::BaseClass *)y) == nullptr)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid entity %d ('%s'), is not an instance of the base class '%s'", __FUNCTION__, indexOfEdict(y->pev), STRING(y->pev->classname), #x); return FALSE; }
|
||||||
|
#define CHECK_REQUIREMENTS(x) if (unlikely(!api_cfg.has##x())) { AMXX_LogError(amx, AMX_ERR_NATIVE, "Native '%s' is not available, %s required.", __FUNCTION__, #x); return FALSE; } if (!g_RehldsMessageManager) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: %s message manager not initialized.", __FUNCTION__, #x); return FALSE; }
|
||||||
|
|
||||||
class CAmxArg
|
class CAmxArg
|
||||||
{
|
{
|
||||||
|
414
reapi/src/natives/natives_hookmessage.cpp
Normal file
414
reapi/src/natives/natives_hookmessage.cpp
Normal file
@ -0,0 +1,414 @@
|
|||||||
|
#include "precompiled.h"
|
||||||
|
|
||||||
|
enum MessageHook
|
||||||
|
{
|
||||||
|
INVALID_MESSAGEHOOK = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a callback function to be called when a game message with the specified ID is received.
|
||||||
|
*
|
||||||
|
* @param msg_id The ID of the message to register the callback for.
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @return Returns a handle to the registered message hook.
|
||||||
|
*
|
||||||
|
* native MessageHook:RegisterMessage(const msg_id, const callback[], post = 0);
|
||||||
|
*/
|
||||||
|
cell AMX_NATIVE_CALL RegisterMessage(AMX *amx, cell *params)
|
||||||
|
{
|
||||||
|
enum args_e { arg_count, arg_id, arg_handler, arg_post };
|
||||||
|
|
||||||
|
CHECK_REQUIREMENTS(ReHLDS);
|
||||||
|
|
||||||
|
int msg_id = params[arg_id];
|
||||||
|
|
||||||
|
// svc_bad (0) is not allowed for hook
|
||||||
|
if (msg_id <= 0 || msg_id >= MAX_USERMESSAGES)
|
||||||
|
return INVALID_MESSAGEHOOK;
|
||||||
|
|
||||||
|
char namebuf[256];
|
||||||
|
const char *funcname = getAmxString(amx, params[arg_handler], namebuf);
|
||||||
|
|
||||||
|
int funcid;
|
||||||
|
if (unlikely(g_amxxapi.amx_FindPublic(amx, funcname, &funcid) != AMX_ERR_NONE))
|
||||||
|
{
|
||||||
|
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: public function \"%s\" not found.", __FUNCTION__, funcname);
|
||||||
|
return INVALID_MESSAGEHOOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int post = params[arg_post];
|
||||||
|
return g_messageHookManager.addHook(amx, msg_id, funcname, post != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a game message hook identified by the specified handle.
|
||||||
|
*
|
||||||
|
* @param handle The handle of the message hook to unregister.
|
||||||
|
*
|
||||||
|
* @return Returns true if the message hook is successfully unregistered, otherwise false.
|
||||||
|
*
|
||||||
|
* native bool:UnregisterMessage(const MessageHook:handle);
|
||||||
|
*/
|
||||||
|
cell AMX_NATIVE_CALL UnregisterMessage(AMX *amx, cell *params)
|
||||||
|
{
|
||||||
|
enum args_e { arg_count, arg_handle };
|
||||||
|
|
||||||
|
CHECK_REQUIREMENTS(ReHLDS);
|
||||||
|
|
||||||
|
if (!g_messageHookManager.removeHook(amx, params[arg_handle]))
|
||||||
|
{
|
||||||
|
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: Failed to remove message hook with handle %d.", __FUNCTION__, params[arg_handle]);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables a game message hook identified by the specified handle.
|
||||||
|
*
|
||||||
|
* @param handle The handle of the message hook to enable.
|
||||||
|
*
|
||||||
|
* @return Returns true if the message hook is successfully enabled, otherwise false.
|
||||||
|
*
|
||||||
|
* native bool:EnableHookMessage(const MessageHook:handle);
|
||||||
|
*/
|
||||||
|
cell AMX_NATIVE_CALL EnableHookMessage(AMX *amx, cell *params)
|
||||||
|
{
|
||||||
|
enum args_e { arg_count, arg_handle };
|
||||||
|
|
||||||
|
CHECK_REQUIREMENTS(ReHLDS);
|
||||||
|
|
||||||
|
cell handle = params[arg_handle];
|
||||||
|
auto hook = g_messageHookManager.getAmxxHook(handle);
|
||||||
|
if (!hook)
|
||||||
|
{
|
||||||
|
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: Message hook with handle %d not found.", __FUNCTION__, handle);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook->SetState(FSTATE_ENABLED);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables a game message hook identified by the specified handle.
|
||||||
|
*
|
||||||
|
* @param handle The handle of the message hook to disable.
|
||||||
|
*
|
||||||
|
* @return Returns true if the message hook is successfully disabled, otherwise false.
|
||||||
|
*
|
||||||
|
* native bool:DisableHookMessage(const MessageHook:handle);
|
||||||
|
*/
|
||||||
|
cell AMX_NATIVE_CALL DisableHookMessage(AMX *amx, cell *params)
|
||||||
|
{
|
||||||
|
enum args_e { arg_count, arg_handle };
|
||||||
|
|
||||||
|
CHECK_REQUIREMENTS(ReHLDS);
|
||||||
|
|
||||||
|
cell handle = params[arg_handle];
|
||||||
|
auto hook = g_messageHookManager.getAmxxHook(handle);
|
||||||
|
if (!hook)
|
||||||
|
{
|
||||||
|
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: Message hook with handle %d not found.", __FUNCTION__, handle);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook->SetState(FSTATE_STOPPED);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the parameter value for the specified index in the current game message.
|
||||||
|
*
|
||||||
|
* @param index The index of the parameter to set.
|
||||||
|
* @param value The value to set for the parameter.
|
||||||
|
*
|
||||||
|
* @return Returns true if the parameter value is successfully set, otherwise false.
|
||||||
|
*
|
||||||
|
* native bool:SetMessageParam(const number, any:...);
|
||||||
|
*/
|
||||||
|
cell AMX_NATIVE_CALL SetMessageParam(AMX *amx, cell *params)
|
||||||
|
{
|
||||||
|
enum args_e { arg_count, arg_number, arg_value };
|
||||||
|
|
||||||
|
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 = params[arg_number] - 1;
|
||||||
|
|
||||||
|
cell *value = getAmxAddr(amx, params[arg_value]);
|
||||||
|
|
||||||
|
switch (g_activeMessageContext->getParamType(number))
|
||||||
|
{
|
||||||
|
case IMessage::ParamType::String:
|
||||||
|
char stringbuf[256];
|
||||||
|
g_activeMessageContext->setParamString(number, getAmxString(amx, params[arg_value], stringbuf));
|
||||||
|
break;
|
||||||
|
case IMessage::ParamType::Angle:
|
||||||
|
case IMessage::ParamType::Coord:
|
||||||
|
g_activeMessageContext->setParamFloat(number, *(float *)value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_activeMessageContext->setParamInt(number, *value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the parameter value for the specified index 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.
|
||||||
|
*
|
||||||
|
* @return Returns the retrieved parameter value.
|
||||||
|
*
|
||||||
|
* native any:GetMessageParam(const number, any:...);
|
||||||
|
*/
|
||||||
|
cell AMX_NATIVE_CALL GetMessageParam(AMX *amx, cell *params)
|
||||||
|
{
|
||||||
|
enum args_e { arg_count, arg_number, arg_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t number = params[arg_number] - 1;
|
||||||
|
|
||||||
|
cell *dstAddr = getAmxAddr(amx, params[arg_value]);
|
||||||
|
|
||||||
|
switch (g_activeMessageContext->getParamType(number))
|
||||||
|
{
|
||||||
|
case IMessage::ParamType::String:
|
||||||
|
{
|
||||||
|
if (PARAMS_COUNT != 3)
|
||||||
|
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 > 1)
|
||||||
|
*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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @return Returns the type of the parameter, look at the enum MsgParamType
|
||||||
|
*
|
||||||
|
* native MsgParamType:GetMessageParamType(const number);
|
||||||
|
*/
|
||||||
|
cell AMX_NATIVE_CALL GetMessageParamType(AMX *amx, cell *params)
|
||||||
|
{
|
||||||
|
enum args_e { arg_count, 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 = params[arg_number] - 1;
|
||||||
|
|
||||||
|
size_t paramCount = 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: trying to get argument without active hook.", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param msgid The ID of the message to set the block type for.
|
||||||
|
* @param type The type of block to set for the message, look at the enum MsgBlockType
|
||||||
|
*
|
||||||
|
* @return Returns true if the block type is successfully set, otherwise false.
|
||||||
|
*
|
||||||
|
* native bool:SetMessageBlock(const msgid, MsgBlockType:type);
|
||||||
|
*/
|
||||||
|
cell AMX_NATIVE_CALL SetMessageBlock(AMX *amx, cell *params)
|
||||||
|
{
|
||||||
|
enum args_e { arg_count, arg_id, arg_type };
|
||||||
|
|
||||||
|
CHECK_REQUIREMENTS(ReHLDS);
|
||||||
|
|
||||||
|
int msg_id = params[arg_id];
|
||||||
|
|
||||||
|
// svc_bad (0) is not allowed for hook
|
||||||
|
if (msg_id <= 0 || msg_id >= MAX_USERMESSAGES)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
g_RehldsMessageManager->setMessageBlock(msg_id, static_cast<IMessage::BlockType>(params[arg_type]));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the block type for the specified message ID.
|
||||||
|
*
|
||||||
|
* @param msgid The ID of the message to retrieve the block type for.
|
||||||
|
*
|
||||||
|
* @return Returns the block type of the specified message, look at the enum MsgBlockType
|
||||||
|
*
|
||||||
|
* native MsgBlockType:GetMessageBlock(const msgid);
|
||||||
|
*/
|
||||||
|
cell AMX_NATIVE_CALL GetMessageBlock(AMX *amx, cell *params)
|
||||||
|
{
|
||||||
|
enum args_e { arg_count, arg_id };
|
||||||
|
|
||||||
|
CHECK_REQUIREMENTS(ReHLDS);
|
||||||
|
|
||||||
|
int msg_id = params[arg_id];
|
||||||
|
|
||||||
|
// svc_bad (0) is not allowed for hook
|
||||||
|
if (msg_id <= 0 || msg_id >= MAX_USERMESSAGES)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return static_cast<cell>(g_RehldsMessageManager->getMessageBlock(params[arg_id]));
|
||||||
|
}
|
||||||
|
|
||||||
|
AMX_NATIVE_INFO HookMessage_Natives[] =
|
||||||
|
{
|
||||||
|
{ "RegisterMessage", RegisterMessage },
|
||||||
|
{ "UnregisterMessage", UnregisterMessage },
|
||||||
|
|
||||||
|
{ "EnableHookMessage", EnableHookMessage },
|
||||||
|
{ "DisableHookMessage", DisableHookMessage },
|
||||||
|
|
||||||
|
{ "GetMessageParam", GetMessageParam },
|
||||||
|
{ "GetMessageParamType", GetMessageParamType },
|
||||||
|
{ "GetMessageParamCount", GetMessageParamCount },
|
||||||
|
|
||||||
|
{ "GetMessageOrigin", GetMessageOrigin },
|
||||||
|
{ "GetMessageDest", GetMessageDest },
|
||||||
|
|
||||||
|
{ "SetMessageParam", SetMessageParam },
|
||||||
|
|
||||||
|
{ "SetMessageBlock", SetMessageBlock },
|
||||||
|
{ "GetMessageBlock", GetMessageBlock },
|
||||||
|
|
||||||
|
{ nullptr, nullptr }
|
||||||
|
};
|
||||||
|
|
||||||
|
void RegisterNatives_HookMessage()
|
||||||
|
{
|
||||||
|
g_amxxapi.AddNatives(HookMessage_Natives);
|
||||||
|
}
|
3
reapi/src/natives/natives_hookmessage.h
Normal file
3
reapi/src/natives/natives_hookmessage.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void RegisterNatives_HookMessage();
|
@ -60,12 +60,14 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "api_config.h"
|
#include "api_config.h"
|
||||||
#include "hook_manager.h"
|
#include "hook_manager.h"
|
||||||
|
#include "hook_message_manager.h"
|
||||||
#include "hook_callback.h"
|
#include "hook_callback.h"
|
||||||
#include "entity_callback_dispatcher.h"
|
#include "entity_callback_dispatcher.h"
|
||||||
#include "member_list.h"
|
#include "member_list.h"
|
||||||
|
|
||||||
// natives
|
// natives
|
||||||
#include "natives_hookchains.h"
|
#include "natives_hookchains.h"
|
||||||
|
#include "natives_hookmessage.h"
|
||||||
#include "natives_members.h"
|
#include "natives_members.h"
|
||||||
#include "natives_misc.h"
|
#include "natives_misc.h"
|
||||||
#include "natives_common.h"
|
#include "natives_common.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user