From 96a3671bb68f6763008bf3a9271aeb429cdce899 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 1 Mar 2009 16:39:25 -0500 Subject: [PATCH] Improved user message interception API (bug 3631, r=pred). --- core/PluginSys.cpp | 4 +- core/UserMessages.cpp | 50 +++++++++++++++++++++--- core/UserMessages.h | 9 +++++ core/smn_usermsgs.cpp | 7 ++-- core/smn_usermsgs.h | 2 +- plugins/include/core.inc | 2 +- plugins/include/usermessages.inc | 7 ++-- public/IUserMessages.h | 67 +++++++++++++++++++++++++++++--- 8 files changed, 128 insertions(+), 20 deletions(-) diff --git a/core/PluginSys.cpp b/core/PluginSys.cpp index 86f6774e..c7eb95db 100644 --- a/core/PluginSys.cpp +++ b/core/PluginSys.cpp @@ -273,13 +273,13 @@ bool CPlugin::UpdateInfo() base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&info); m_FileVersion = info->version; - if (m_FileVersion >= 3) + if (m_FileVersion >= 4) { base->LocalToString(info->date, (char **)&pDate); base->LocalToString(info->time, (char **)&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); SetErrorState(Plugin_Failed, "Newer SourceMod required (%s or higher)", pFileVers); diff --git a/core/UserMessages.cpp b/core/UserMessages.cpp index 8b37dd33..3288c4e3 100644 --- a/core/UserMessages.cpp +++ b/core/UserMessages.cpp @@ -205,7 +205,31 @@ bool UserMessages::EndMessage() 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) +{ + 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) { @@ -224,6 +248,7 @@ bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, pInfo->Callback = pListener; pInfo->IsHooked = false; pInfo->KillMe = false; + pInfo->IsNew = isNew; if (!m_HookCount++) { @@ -243,8 +268,8 @@ bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, 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; MsgIter iter; ListenerInfo *pInfo; @@ -259,7 +284,7 @@ bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener for (iter=pList->begin(); iter!=pList->end(); iter++) { pInfo = (*iter); - if (pInfo->Callback == pListener) + if (pInfo->Callback == pListener && pInfo->IsNew == isNew) { if (pInfo->IsHooked) { @@ -339,7 +364,7 @@ bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_ty void UserMessages::OnMessageEnd_Post() { - if (!m_InHook || m_BlockEndPost) + if (!m_InHook) { RETURN_META(MRES_IGNORED); } @@ -354,8 +379,16 @@ void UserMessages::OnMessageEnd_Post() for (iter=pList->begin(); iter!=pList->end(); ) { pInfo = (*iter); + if (m_BlockEndPost && !pInfo->IsNew) + { + continue; + } pInfo->IsHooked = true; pInfo->Callback->OnUserMessageSent(m_CurId); + if (pInfo->IsNew) + { + pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost); + } if (pInfo->KillMe) { @@ -373,8 +406,16 @@ void UserMessages::OnMessageEnd_Post() for (iter=pList->begin(); iter!=pList->end(); ) { pInfo = (*iter); + if (m_BlockEndPost && !pInfo->IsNew) + { + continue; + } pInfo->IsHooked = true; pInfo->Callback->OnUserMessageSent(m_CurId); + if (pInfo->IsNew) + { + pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost); + } if (pInfo->KillMe) { @@ -495,7 +536,6 @@ void UserMessages::OnMessageEnd_Pre() RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED); supercede: - m_InHook = false; m_BlockEndPost = true; RETURN_META(MRES_SUPERCEDE); } diff --git a/core/UserMessages.h b/core/UserMessages.h index 772cafe8..0ff262fc 100644 --- a/core/UserMessages.h +++ b/core/UserMessages.h @@ -48,6 +48,7 @@ struct ListenerInfo IUserMessageListener *Callback; bool IsHooked; bool KillMe; + bool IsNew; }; typedef List MsgList; @@ -71,6 +72,12 @@ public: //IUserMessages 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); bool EndMessage(); + bool HookUserMessage2(int msg_id, + IUserMessageListener *pListener, + bool intercept=false); + bool UnhookUserMessage2(int msg_id, + IUserMessageListener *pListener, + bool intercept=false); public: #if SOURCE_ENGINE == SE_LEFT4DEAD bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name); @@ -82,6 +89,8 @@ public: void OnMessageEnd_Pre(); void OnMessageEnd_Post(); 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(); private: List m_msgHooks[255]; diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index 3ea96ada..e5907903 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -309,7 +309,7 @@ ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IR return static_cast(res); } -void MsgListenerWrapper::OnUserMessageSent(int msg_id) +void MsgListenerWrapper::OnPostUserMessage(int msg_id, bool sent) { if (!m_Notify) { @@ -318,6 +318,7 @@ void MsgListenerWrapper::OnUserMessageSent(int msg_id) cell_t res; m_Notify->PushCell(msg_id); + m_Notify->PushCell(sent ? 1 : 0); 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->Initialize(msgid, pHook, pNotify, intercept); - g_UserMsgs.HookUserMessage(msgid, pListener, intercept); + g_UserMsgs.HookUserMessage2(msgid, pListener, intercept); return 1; } @@ -521,7 +522,7 @@ static cell_t smn_UnhookUserMessage(IPluginContext *pCtx, const cell_t *params) } 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"); } diff --git a/core/smn_usermsgs.h b/core/smn_usermsgs.h index bb16ab38..0e761d9d 100644 --- a/core/smn_usermsgs.h +++ b/core/smn_usermsgs.h @@ -45,7 +45,7 @@ public: public: //IUserMessageListener void OnUserMessage(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: size_t _FillInPlayers(int *pl_array, IRecipientFilter *pFilter); private: diff --git a/plugins/include/core.inc b/plugins/include/core.inc index 787cddb2..30b8df12 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -38,7 +38,7 @@ #include /** If this gets changed, you need to update Core's check. */ -#define SOURCEMOD_PLUGINAPI_VERSION 4 +#define SOURCEMOD_PLUGINAPI_VERSION 5 struct PlVers { diff --git a/plugins/include/usermessages.inc b/plugins/include/usermessages.inc index 00178df4..d7c4a6b7 100644 --- a/plugins/include/usermessages.inc +++ b/plugins/include/usermessages.inc @@ -127,11 +127,12 @@ native EndMessage(); 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 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. @@ -145,7 +146,7 @@ functag public MsgSentNotify(UserMsg:msg_id); * @noreturn * @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. diff --git a/public/IUserMessages.h b/public/IUserMessages.h index b63d45d8..450abb1d 100644 --- a/public/IUserMessages.h +++ b/public/IUserMessages.h @@ -44,7 +44,7 @@ */ #define SMINTERFACE_USERMSGS_NAME "IUserMessages" -#define SMINTERFACE_USERMSGS_VERSION 1 +#define SMINTERFACE_USERMSGS_VERSION 2 namespace SourceMod { @@ -81,11 +81,35 @@ namespace SourceMod /** * @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. */ 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 */ @@ -123,17 +147,22 @@ namespace SourceMod * @param intercept If true, message will be intercepted rather than merely hooked. * @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. * * @param msg_id Message Id. * @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. */ - 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. @@ -144,13 +173,41 @@ namespace SourceMod * @param flags Flags to use for sending the message. * @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(). * @return True on success, false otherwise. */ 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; }; }