Improved user message interception API (bug 3631, r=pred).

This commit is contained in:
David Anderson 2009-03-01 16:39:25 -05:00
parent 0c028ca9d0
commit 96a3671bb6
8 changed files with 128 additions and 20 deletions

View File

@ -273,13 +273,13 @@ bool CPlugin::UpdateInfo()
base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&info); base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&info);
m_FileVersion = info->version; m_FileVersion = info->version;
if (m_FileVersion >= 3) if (m_FileVersion >= 4)
{ {
base->LocalToString(info->date, (char **)&pDate); base->LocalToString(info->date, (char **)&pDate);
base->LocalToString(info->time, (char **)&pTime); base->LocalToString(info->time, (char **)&pTime);
UTIL_Format(m_DateTime, sizeof(m_DateTime), "%s %s", pDate, pTime); UTIL_Format(m_DateTime, sizeof(m_DateTime), "%s %s", pDate, pTime);
} }
if (m_FileVersion > 4) if (m_FileVersion > 5)
{ {
base->LocalToString(info->filevers, (char **)&pFileVers); base->LocalToString(info->filevers, (char **)&pFileVers);
SetErrorState(Plugin_Failed, "Newer SourceMod required (%s or higher)", pFileVers); SetErrorState(Plugin_Failed, "Newer SourceMod required (%s or higher)", pFileVers);

View File

@ -205,7 +205,31 @@ bool UserMessages::EndMessage()
return true; return true;
} }
bool UserMessages::HookUserMessage2(int msg_id,
IUserMessageListener *pListener,
bool intercept)
{
return InternalHook(msg_id, pListener, intercept, true);
}
bool UserMessages::UnhookUserMessage2(int msg_id,
IUserMessageListener *pListener,
bool intercept)
{
return InternalUnhook(msg_id, pListener, intercept, true);
}
bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept) bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
{
return InternalHook(msg_id, pListener, intercept, false);
}
bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
{
return InternalUnhook(msg_id, pListener, intercept, false);
}
bool UserMessages::InternalHook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew)
{ {
if (msg_id < 0 || msg_id >= 255) if (msg_id < 0 || msg_id >= 255)
{ {
@ -224,6 +248,7 @@ bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener,
pInfo->Callback = pListener; pInfo->Callback = pListener;
pInfo->IsHooked = false; pInfo->IsHooked = false;
pInfo->KillMe = false; pInfo->KillMe = false;
pInfo->IsNew = isNew;
if (!m_HookCount++) if (!m_HookCount++)
{ {
@ -243,8 +268,8 @@ bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener,
return true; return true;
} }
bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept) bool UserMessages::InternalUnhook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew)
{ {
MsgList *pList; MsgList *pList;
MsgIter iter; MsgIter iter;
ListenerInfo *pInfo; ListenerInfo *pInfo;
@ -259,7 +284,7 @@ bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener
for (iter=pList->begin(); iter!=pList->end(); iter++) for (iter=pList->begin(); iter!=pList->end(); iter++)
{ {
pInfo = (*iter); pInfo = (*iter);
if (pInfo->Callback == pListener) if (pInfo->Callback == pListener && pInfo->IsNew == isNew)
{ {
if (pInfo->IsHooked) if (pInfo->IsHooked)
{ {
@ -339,7 +364,7 @@ bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_ty
void UserMessages::OnMessageEnd_Post() void UserMessages::OnMessageEnd_Post()
{ {
if (!m_InHook || m_BlockEndPost) if (!m_InHook)
{ {
RETURN_META(MRES_IGNORED); RETURN_META(MRES_IGNORED);
} }
@ -354,8 +379,16 @@ void UserMessages::OnMessageEnd_Post()
for (iter=pList->begin(); iter!=pList->end(); ) for (iter=pList->begin(); iter!=pList->end(); )
{ {
pInfo = (*iter); pInfo = (*iter);
if (m_BlockEndPost && !pInfo->IsNew)
{
continue;
}
pInfo->IsHooked = true; pInfo->IsHooked = true;
pInfo->Callback->OnUserMessageSent(m_CurId); pInfo->Callback->OnUserMessageSent(m_CurId);
if (pInfo->IsNew)
{
pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
}
if (pInfo->KillMe) if (pInfo->KillMe)
{ {
@ -373,8 +406,16 @@ void UserMessages::OnMessageEnd_Post()
for (iter=pList->begin(); iter!=pList->end(); ) for (iter=pList->begin(); iter!=pList->end(); )
{ {
pInfo = (*iter); pInfo = (*iter);
if (m_BlockEndPost && !pInfo->IsNew)
{
continue;
}
pInfo->IsHooked = true; pInfo->IsHooked = true;
pInfo->Callback->OnUserMessageSent(m_CurId); pInfo->Callback->OnUserMessageSent(m_CurId);
if (pInfo->IsNew)
{
pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
}
if (pInfo->KillMe) if (pInfo->KillMe)
{ {
@ -495,7 +536,6 @@ void UserMessages::OnMessageEnd_Pre()
RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED); RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
supercede: supercede:
m_InHook = false;
m_BlockEndPost = true; m_BlockEndPost = true;
RETURN_META(MRES_SUPERCEDE); RETURN_META(MRES_SUPERCEDE);
} }

View File

@ -48,6 +48,7 @@ struct ListenerInfo
IUserMessageListener *Callback; IUserMessageListener *Callback;
bool IsHooked; bool IsHooked;
bool KillMe; bool KillMe;
bool IsNew;
}; };
typedef List<ListenerInfo *> MsgList; typedef List<ListenerInfo *> MsgList;
@ -71,6 +72,12 @@ public: //IUserMessages
bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false); bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
bf_write *StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags); bf_write *StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags);
bool EndMessage(); bool EndMessage();
bool HookUserMessage2(int msg_id,
IUserMessageListener *pListener,
bool intercept=false);
bool UnhookUserMessage2(int msg_id,
IUserMessageListener *pListener,
bool intercept=false);
public: public:
#if SOURCE_ENGINE == SE_LEFT4DEAD #if SOURCE_ENGINE == SE_LEFT4DEAD
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name); bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
@ -82,6 +89,8 @@ public:
void OnMessageEnd_Pre(); void OnMessageEnd_Pre();
void OnMessageEnd_Post(); void OnMessageEnd_Post();
private: private:
bool InternalHook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew);
bool InternalUnhook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew);
void _DecRefCounter(); void _DecRefCounter();
private: private:
List<ListenerInfo *> m_msgHooks[255]; List<ListenerInfo *> m_msgHooks[255];

View File

@ -309,7 +309,7 @@ ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IR
return static_cast<ResultType>(res); return static_cast<ResultType>(res);
} }
void MsgListenerWrapper::OnUserMessageSent(int msg_id) void MsgListenerWrapper::OnPostUserMessage(int msg_id, bool sent)
{ {
if (!m_Notify) if (!m_Notify)
{ {
@ -318,6 +318,7 @@ void MsgListenerWrapper::OnUserMessageSent(int msg_id)
cell_t res; cell_t res;
m_Notify->PushCell(msg_id); m_Notify->PushCell(msg_id);
m_Notify->PushCell(sent ? 1 : 0);
m_Notify->Execute(&res); m_Notify->Execute(&res);
} }
@ -490,7 +491,7 @@ static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
pListener = s_UsrMessageNatives.CreateListener(pCtx); pListener = s_UsrMessageNatives.CreateListener(pCtx);
pListener->Initialize(msgid, pHook, pNotify, intercept); pListener->Initialize(msgid, pHook, pNotify, intercept);
g_UserMsgs.HookUserMessage(msgid, pListener, intercept); g_UserMsgs.HookUserMessage2(msgid, pListener, intercept);
return 1; return 1;
} }
@ -521,7 +522,7 @@ static cell_t smn_UnhookUserMessage(IPluginContext *pCtx, const cell_t *params)
} }
pListener = (*iter); pListener = (*iter);
if (!g_UserMsgs.UnhookUserMessage(msgid, pListener, intercept)) if (!g_UserMsgs.UnhookUserMessage2(msgid, pListener, intercept))
{ {
return pCtx->ThrowNativeError("Unable to unhook the current user message"); return pCtx->ThrowNativeError("Unable to unhook the current user message");
} }

View File

@ -45,7 +45,7 @@ public:
public: //IUserMessageListener public: //IUserMessageListener
void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
void OnUserMessageSent(int msg_id); void OnPostUserMessage(int msg_id, bool sent);
private: private:
size_t _FillInPlayers(int *pl_array, IRecipientFilter *pFilter); size_t _FillInPlayers(int *pl_array, IRecipientFilter *pFilter);
private: private:

View File

@ -38,7 +38,7 @@
#include <version> #include <version>
/** If this gets changed, you need to update Core's check. */ /** If this gets changed, you need to update Core's check. */
#define SOURCEMOD_PLUGINAPI_VERSION 4 #define SOURCEMOD_PLUGINAPI_VERSION 5
struct PlVers struct PlVers
{ {

View File

@ -127,11 +127,12 @@ native EndMessage();
functag public Action:MsgHook(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init); functag public Action:MsgHook(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init);
/** /**
* Called when a message is finished sending. * Called when a message hook has completed.
* *
* @param msg_id Message index. * @param msg_id Message index.
* @param sent True if message was sent, false if blocked.
*/ */
functag public MsgSentNotify(UserMsg:msg_id); functag public MsgPostHook(UserMsg:msg_id, bool:sent);
/** /**
* Hooks a user message. * Hooks a user message.
@ -145,7 +146,7 @@ functag public MsgSentNotify(UserMsg:msg_id);
* @noreturn * @noreturn
* @error Invalid message index. * @error Invalid message index.
*/ */
native HookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false, MsgSentNotify:notify=MsgSentNotify:-1); native HookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false, MsgPostHook:post=MsgPostHook:-1);
/** /**
* Removes one usermessage hook. * Removes one usermessage hook.

View File

@ -44,7 +44,7 @@
*/ */
#define SMINTERFACE_USERMSGS_NAME "IUserMessages" #define SMINTERFACE_USERMSGS_NAME "IUserMessages"
#define SMINTERFACE_USERMSGS_VERSION 1 #define SMINTERFACE_USERMSGS_VERSION 2
namespace SourceMod namespace SourceMod
{ {
@ -81,11 +81,35 @@ namespace SourceMod
/** /**
* @brief Called when a hooked user message is sent, regardless of the hook type. * @brief Called when a hooked user message is sent, regardless of the hook type.
*
* Note: This is called regardless of the API version, though it only happens if the
* message is successfully sent.
*
* @param msg_id Message Id. * @param msg_id Message Id.
*/ */
virtual void OnUserMessageSent(int msg_id) virtual void OnUserMessageSent(int msg_id)
{ {
} }
/**
* @brief Returns the user message API version.
*/
virtual unsigned int GetUserMessageAPIVersion()
{
return SMINTERFACE_USERMSGS_VERSION;
}
/**
* @brief Called when a hooked user message hook is finished, regardless of the hook type.
*
* Note: this is only called if hooked using the new API (version 2 or greater).
*
* @param msg_id Message Id.
* @param sent True if message was sent, false if blocked.
*/
virtual void OnPostUserMessage(int msg_id, bool sent)
{
}
}; };
#define USERMSG_RELIABLE (1<<2) /**< Message will be set to reliable */ #define USERMSG_RELIABLE (1<<2) /**< Message will be set to reliable */
@ -123,17 +147,22 @@ namespace SourceMod
* @param intercept If true, message will be intercepted rather than merely hooked. * @param intercept If true, message will be intercepted rather than merely hooked.
* @return True on success, false otherwise. * @return True on success, false otherwise.
*/ */
virtual bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false) =0; virtual bool HookUserMessage(int msg_id,
IUserMessageListener *pListener,
bool intercept=false) =0;
/** /**
* @brief Unhooks a user message. * @brief Unhooks a user message.
* *
* @param msg_id Message Id. * @param msg_id Message Id.
* @param pListener Pointer to an IUserMessageListener. * @param pListener Pointer to an IUserMessageListener.
* @param intercept If true, removed message will from interception pool rather than normal hook pool. * @param intercept If true, message is removed from interception pool rather than the
* normal hook pool.
* @return True on success, false otherwise. * @return True on success, false otherwise.
*/ */
virtual bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false) =0; virtual bool UnhookUserMessage(int msg_id,
IUserMessageListener *pListener,
bool intercept=false) =0;
/** /**
* @brief Wrapper around UserMessageBegin for more options. * @brief Wrapper around UserMessageBegin for more options.
@ -144,13 +173,41 @@ namespace SourceMod
* @param flags Flags to use for sending the message. * @param flags Flags to use for sending the message.
* @return bf_write structure to write message with, or NULL on failure. * @return bf_write structure to write message with, or NULL on failure.
*/ */
virtual bf_write *StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags) =0; virtual bf_write *StartMessage(int msg_id,
const cell_t players[],
unsigned int playersNum,
int flags) =0;
/** /**
* @brief Wrapper around UserMessageEnd for use with StartMessage(). * @brief Wrapper around UserMessageEnd for use with StartMessage().
* @return True on success, false otherwise. * @return True on success, false otherwise.
*/ */
virtual bool EndMessage() =0; virtual bool EndMessage() =0;
/**
* @brief Sets a hook on a user message using the newer API (OnPostUserMessage).
*
* @param msg_id Message Id.
* @param pListener Pointer to an IUserMessageListener.
* @param intercept If true, message will be intercepted rather than merely hooked.
* @return True on success, false otherwise.
*/
virtual bool HookUserMessage2(int msg_id,
IUserMessageListener *pListener,
bool intercept=false) =0;
/**
* @brief Unhooks a user message using the newer API (OnPostUserMessage).
*
* @param msg_id Message Id.
* @param pListener Pointer to an IUserMessageListener.
* @param intercept If true, message is removed from interception pool rather than the
* normal hook pool.
* @return True on success, false otherwise.
*/
virtual bool UnhookUserMessage2(int msg_id,
IUserMessageListener *pListener,
bool intercept=false) =0;
}; };
} }