rewrite of user messages

fixed possible iterator corruption

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40599
This commit is contained in:
Borja Ferrer 2007-03-11 03:04:39 +00:00
parent 5b1f1d19c1
commit f78b3fa086
7 changed files with 278 additions and 161 deletions

View File

@ -21,7 +21,7 @@
class CellRecipientFilter : public IRecipientFilter
{
public:
CellRecipientFilter() : m_Reliable(false), m_InitMessage(false), m_Size(0) {}
CellRecipientFilter() : m_IsReliable(false), m_IsInitMessage(false), m_Size(0) {}
~CellRecipientFilter() {}
public: //IRecipientFilter
bool IsReliable() const;
@ -29,32 +29,32 @@ public: //IRecipientFilter
int GetRecipientCount() const;
int GetRecipientIndex(int slot) const;
public:
void SetRecipientPtr(cell_t *ptr, size_t count);
void SetReliable(bool isreliable);
void SetInitMessage(bool isinitmsg);
void ResetFilter();
void Initialize(cell_t *ptr, size_t count);
void SetToReliable(bool isreliable);
void SetToInit(bool isinitmsg);
void Reset();
private:
cell_t m_CellRecipients[255];
bool m_Reliable;
bool m_InitMessage;
cell_t m_Players[255];
bool m_IsReliable;
bool m_IsInitMessage;
size_t m_Size;
};
inline void CellRecipientFilter::ResetFilter()
inline void CellRecipientFilter::Reset()
{
m_Reliable = false;
m_InitMessage = false;
m_IsReliable = false;
m_IsInitMessage = false;
m_Size = 0;
}
inline bool CellRecipientFilter::IsReliable() const
{
return m_Reliable;
return m_IsReliable;
}
inline bool CellRecipientFilter::IsInitMessage() const
{
return m_InitMessage;
return m_IsInitMessage;
}
inline int CellRecipientFilter::GetRecipientCount() const
@ -68,22 +68,22 @@ inline int CellRecipientFilter::GetRecipientIndex(int slot) const
{
return -1;
}
return static_cast<int>(m_CellRecipients[slot]);
return static_cast<int>(m_Players[slot]);
}
inline void CellRecipientFilter::SetInitMessage(bool isinitmsg)
inline void CellRecipientFilter::SetToInit(bool isinitmsg)
{
m_InitMessage = isinitmsg;
m_IsInitMessage = isinitmsg;
}
inline void CellRecipientFilter::SetReliable(bool isreliable)
inline void CellRecipientFilter::SetToReliable(bool isreliable)
{
m_Reliable = isreliable;
m_IsReliable = isreliable;
}
inline void CellRecipientFilter::SetRecipientPtr(cell_t *ptr, size_t count)
inline void CellRecipientFilter::Initialize(cell_t *ptr, size_t count)
{
memcpy(m_CellRecipients, ptr, count * sizeof(cell_t));
memcpy(m_Players, ptr, count * sizeof(cell_t));
m_Size = count;
}

View File

@ -88,8 +88,8 @@ bool CUserMessages::GetMessageName(int msgid, char *buffer, size_t maxlen) const
bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags)
{
bf_write *buffer;
if (m_InExec)
if (m_InExec || m_InHook)
{
return NULL;
}
@ -98,16 +98,16 @@ bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int
return NULL;
}
m_CellRecFilter.SetRecipientPtr(players, playersNum);
m_CellRecFilter.Initialize(players, playersNum);
m_CurFlags = flags;
if (m_CurFlags & USERMSG_INITMSG)
{
m_CellRecFilter.SetInitMessage(true);
m_CellRecFilter.SetToInit(true);
}
if (m_CurFlags & USERMSG_RELIABLE)
{
m_CellRecFilter.SetReliable(true);
m_CellRecFilter.SetToReliable(true);
}
m_InExec = true;
@ -138,7 +138,7 @@ bool CUserMessages::EndMessage()
m_InExec = false;
m_CurFlags = 0;
m_CellRecFilter.ResetFilter();
m_CellRecFilter.Reset();
return true;
}
@ -150,6 +150,19 @@ bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener,
return false;
}
ListenerInfo *pInfo;
if (m_FreeListeners.empty())
{
pInfo = new ListenerInfo;
} else {
pInfo = m_FreeListeners.front();
m_FreeListeners.pop();
}
pInfo->Callback = pListener;
pInfo->IsHooked = false;
pInfo->KillMe = false;
if (!m_HookCount++)
{
SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
@ -160,20 +173,19 @@ bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener,
if (intercept)
{
m_msgIntercepts[msg_id].push_back(pListener);
m_msgIntercepts[msg_id].push_back(pInfo);
} else {
m_msgHooks[msg_id].push_back(pListener);
m_msgHooks[msg_id].push_back(pInfo);
}
return true;
}
bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
{
//:TODO: restrict user from unhooking stuff during a message hook to avoid iterator mess
List<IUserMessageListener *> *lst;
IUserMessageListener *listener;
{
MsgList *pList;
MsgIter iter;
ListenerInfo *pInfo;
bool deleted = false;
if (msg_id < 0 || msg_id >= 255)
@ -181,27 +193,40 @@ bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListene
return false;
}
lst = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
for (iter=lst->begin(); iter!=lst->end(); iter++)
pList = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
for (iter=pList->begin(); iter!=pList->end(); iter++)
{
listener = (*iter);
if (listener == pListener)
pInfo = (*iter);
if (pInfo->Callback == pListener)
{
lst->erase(iter);
if (pInfo->IsHooked)
{
pInfo->KillMe = true;
return true;
}
pList->erase(iter);
deleted = true;
break;
}
}
if (deleted && !(--m_HookCount))
if (deleted)
{
_DecRefCounter();
}
return deleted;
}
void CUserMessages::_DecRefCounter()
{
if (--m_HookCount == 0)
{
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
}
return (deleted) ? true : false;
}
bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
@ -209,13 +234,8 @@ bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_ty
bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
bool is_hook_empty = m_msgHooks[msg_type].empty();
if (is_intercept_empty && is_hook_empty)
{
m_InHook = false;
RETURN_META_VALUE(MRES_IGNORED, NULL);
}
if ((m_InExec) && !(m_CurFlags & USERMSG_PASSTHRU_ALL))
if ((is_intercept_empty && is_hook_empty)
|| (m_InExec && !(m_CurFlags & USERMSG_PASSTHRU_ALL)))
{
m_InHook = false;
RETURN_META_VALUE(MRES_IGNORED, NULL);
@ -223,11 +243,11 @@ bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_ty
m_CurId = msg_type;
m_CurRecFilter = filter;
m_InterceptBuffer.Reset();
m_InHook = true;
if (!is_intercept_empty)
{
m_InterceptBuffer.Reset();
RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
}
@ -253,23 +273,48 @@ void CUserMessages::OnMessageEnd_Post()
RETURN_META(MRES_IGNORED);
}
List<IUserMessageListener *> *lst;
IUserMessageListener *listener;
MsgList *pList;
MsgIter iter;
ListenerInfo *pInfo;
lst = &m_msgIntercepts[m_CurId];
for (iter=lst->begin(); iter!=lst->end(); iter++)
pList = &m_msgIntercepts[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); )
{
listener = (*iter);
listener->OnUserMessageSent(m_CurId);
pInfo = (*iter);
pInfo->IsHooked = true;
pInfo->Callback->OnUserMessageSent(m_CurId);
if (pInfo->KillMe)
{
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
pInfo->IsHooked = false;
iter++;
}
lst = &m_msgHooks[m_CurId];
for (iter=lst->begin(); iter!=lst->end(); iter++)
pList = &m_msgHooks[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); iter++)
{
listener = (*iter);
listener->OnUserMessageSent(m_CurId);
pInfo = (*iter);
pInfo->Callback->OnUserMessageSent(m_CurId);
if (pInfo->KillMe)
{
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
pInfo->IsHooked = false;
iter++;
}
m_InHook = false;
}
void CUserMessages::OnMessageEnd_Pre()
@ -279,26 +324,61 @@ void CUserMessages::OnMessageEnd_Pre()
RETURN_META(MRES_IGNORED);
}
List<IUserMessageListener *> *lst;
IUserMessageListener *listener;
bf_write *engine_bfw;
MsgList *pList;
MsgIter iter;
ListenerInfo *pInfo;
ResultType res;
bool intercepted = false;
bool handled = false;
lst = &m_msgIntercepts[m_CurId];
for (iter=lst->begin(); iter!=lst->end(); iter++)
pList = &m_msgIntercepts[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); )
{
listener = (*iter);
res = listener->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
if (res == Pl_Stop)
pInfo = (*iter);
pInfo->IsHooked = true;
res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
switch (res)
{
goto supercede;
} else if (res == Pl_Handled) {
handled = true;
case Pl_Stop:
{
if (pInfo->KillMe)
{
pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
goto supercede;
}
pInfo->IsHooked = false;
goto supercede;
}
case Pl_Handled:
{
handled = true;
if (pInfo->KillMe)
{
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
break;
}
default:
{
if (pInfo->KillMe)
{
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
}
}
pInfo->IsHooked = false;
intercepted = true;
iter++;
}
if (handled)
@ -308,21 +388,36 @@ void CUserMessages::OnMessageEnd_Pre()
if (intercepted)
{
bf_write *engine_bfw;
engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
ENGINE_CALL(MessageEnd)();
goto supercede;
}
lst = &m_msgHooks[m_CurId];
for (iter=lst->begin(); iter!=lst->end(); iter++)
pList = &m_msgHooks[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); )
{
listener = (*iter);
listener->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
pInfo = (*iter);
pInfo->IsHooked = true;
pInfo->Callback->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
if (pInfo->KillMe)
{
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
iter++;
}
RETURN_META(MRES_IGNORED);
supercede:
m_InHook = false;
RETURN_META(MRES_SUPERCEDE);
}

View File

@ -26,7 +26,15 @@ using namespace SourceMod;
#define INVALID_MESSAGE_ID -1
typedef List<IUserMessageListener *>::iterator MsgIter;
struct ListenerInfo
{
IUserMessageListener *Callback;
bool IsHooked;
bool KillMe;
};
typedef List<ListenerInfo *> MsgList;
typedef List<ListenerInfo *>::iterator MsgIter;
class CUserMessages :
public IUserMessages,
@ -51,8 +59,11 @@ public:
void OnMessageEnd_Pre();
void OnMessageEnd_Post();
private:
List<IUserMessageListener *> m_msgHooks[255];
List<IUserMessageListener *> m_msgIntercepts[255];
void _DecRefCounter();
private:
List<ListenerInfo *> m_msgHooks[255];
List<ListenerInfo *> m_msgIntercepts[255];
CStack<ListenerInfo *> m_FreeListeners;
unsigned char m_pBase[2500];
IRecipientFilter *m_CurRecFilter;
bf_write m_InterceptBuffer;

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Version="8,00"
Name="sourcemod_mm"
ProjectGUID="{E39527CD-7CAB-4420-97CC-DA1B93B260BC}"
RootNamespace="sourcemod_mm"

View File

@ -22,6 +22,9 @@ Handle_t g_CurMsgHandle;
int g_MsgPlayers[256];
bool g_IsMsgInExec = false;
typedef List<MsgListenerWrapper *> MsgWrapperList;
typedef List<MsgListenerWrapper *>::iterator MsgWrapperIter;
class UsrMessageNatives :
public SMGlobalClass,
public IHandleTypeDispatch,
@ -33,9 +36,9 @@ public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener
void OnHandleDestroy(HandleType_t type, void *object);
void OnPluginUnloaded(IPlugin *plugin);
public:
MsgListenerWrapper *GetNewListener(IPluginContext *pCtx);
MsgListenerWrapper *FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept);
bool RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept);
MsgListenerWrapper *CreateListener(IPluginContext *pCtx);
MsgWrapperIter FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept);
bool DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter);
private:
CStack<MsgListenerWrapper *> m_FreeListeners;
};
@ -59,92 +62,91 @@ void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object)
void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin)
{
List<MsgListenerWrapper *> *wrapper_list;
MsgWrapperList *pList;
if (plugin->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list), true))
if (plugin->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList), true))
{
List<MsgListenerWrapper *>::iterator iter;
MsgListenerWrapper *listener;
MsgWrapperIter iter;
MsgListenerWrapper *pListener;
for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
for (iter=pList->begin(); iter!=pList->end(); iter++)
{
listener = (*iter);
if (g_UserMsgs.UnhookUserMessage(listener->GetMessageId(), listener, listener->IsInterceptHook()))
pListener = (*iter);
if (g_UserMsgs.UnhookUserMessage(pListener->GetMessageId(), pListener, pListener->IsInterceptHook()))
{
m_FreeListeners.push(listener);
m_FreeListeners.push(pListener);
}
}
delete wrapper_list;
delete pList;
}
}
MsgListenerWrapper *UsrMessageNatives::GetNewListener(IPluginContext *pCtx)
MsgListenerWrapper *UsrMessageNatives::CreateListener(IPluginContext *pCtx)
{
MsgListenerWrapper *listener_wrapper;
MsgWrapperList *pList;
MsgListenerWrapper *pListener;
IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
if (m_FreeListeners.empty())
{
listener_wrapper = new MsgListenerWrapper;
pListener = new MsgListenerWrapper;
} else {
listener_wrapper = m_FreeListeners.front();
pListener = m_FreeListeners.front();
m_FreeListeners.pop();
}
List<MsgListenerWrapper *> *wrapper_list;
IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
{
wrapper_list = new List<MsgListenerWrapper *>;
pl->SetProperty("MsgListeners", wrapper_list);
pList = new List<MsgListenerWrapper *>;
pl->SetProperty("MsgListeners", pList);
}
wrapper_list->push_back(listener_wrapper);
pList->push_back(pListener);
return listener_wrapper;
return pListener;
}
MsgListenerWrapper *UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept)
MsgWrapperIter UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept)
{
MsgListenerWrapper *listener;
List<MsgListenerWrapper *> *wrapper_list;
List<MsgListenerWrapper *>::iterator iter;
MsgWrapperList *pList;
MsgWrapperIter iter;
MsgListenerWrapper *pListener;
IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
bool found = false;
if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
{
return NULL;
}
for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
for (iter=pList->begin(); iter!=pList->end(); iter++)
{
listener = (*iter);
if ((msgid == listener->GetMessageId())
&& (intercept == listener->IsInterceptHook())
&& (pHook == listener->GetHookedFunction()))
pListener = (*iter);
if ((msgid == pListener->GetMessageId())
&& (intercept == pListener->IsInterceptHook())
&& (pHook == pListener->GetHookedFunction()))
{
found = true;
break;
return iter;
}
}
return (found) ? listener : NULL;
return NULL;
}
bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept)
bool UsrMessageNatives::DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter)
{
List<MsgListenerWrapper *> *wrapper_list;
MsgWrapperList *pList;
MsgListenerWrapper *pListener;
IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
{
return false;
}
wrapper_list->remove(listener);
m_FreeListeners.push(listener);
pListener = (*iter);
pList->erase(iter);
m_FreeListeners.push(pListener);
return true;
}
@ -155,7 +157,29 @@ bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper
* *
***************************************/
size_t MsgListenerWrapper::PreparePlArray(int *pl_array, IRecipientFilter *pFilter)
void MsgListenerWrapper::Initialize(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept)
{
if (intercept)
{
m_Intercept = hook;
m_Hook = NULL;
} else {
m_Hook = hook;
m_Intercept = NULL;
}
if (notify)
{
m_Notify = notify;
} else {
m_Notify = NULL;
}
m_MsgId = msgid;
m_IsInterceptHook = intercept;
}
size_t MsgListenerWrapper::_FillInPlayers(int *pl_array, IRecipientFilter *pFilter)
{
size_t size = static_cast<size_t>(pFilter->GetRecipientCount());
@ -192,32 +216,10 @@ IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const
return m_Notify;
}
void MsgListenerWrapper::InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept)
{
if (intercept)
{
m_Intercept = hook;
m_Hook = NULL;
} else {
m_Hook = hook;
m_Intercept = NULL;
}
if (notify)
{
m_Notify = notify;
} else {
m_Notify = NULL;
}
m_MsgId = msgid;
m_IsInterceptHook = intercept;
}
void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
{
cell_t res;
size_t size = PreparePlArray(g_MsgPlayers, pFilter);
size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
m_Hook->PushCell(msg_id);
m_Hook->PushCell(0); //:TODO: push handle!
@ -231,7 +233,7 @@ void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilte
ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
{
cell_t res = static_cast<cell_t>(Pl_Continue);
size_t size = PreparePlArray(g_MsgPlayers, pFilter);
size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
m_Intercept->PushCell(msg_id);
m_Intercept->PushCell(0); //:TODO: push handle!
@ -246,13 +248,12 @@ ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IR
void MsgListenerWrapper::OnUserMessageSent(int msg_id)
{
cell_t res;
if (!m_Notify)
{
return;
}
cell_t res;
m_Notify->PushCell(msg_id);
m_Notify->Execute(&res);
}
@ -319,6 +320,10 @@ static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
pCtx->LocalToPhysAddr(params[2], &cl_array);
pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
if (!pBitBuf)
{
return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
}
g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
g_IsMsgInExec = true;
@ -345,6 +350,10 @@ static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params)
pCtx->LocalToPhysAddr(params[2], &cl_array);
pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
if (!pBitBuf)
{
return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
}
g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
g_IsMsgInExec = true;
@ -375,7 +384,7 @@ static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params)
static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
{
IPluginFunction *pHook, *pNotify;
MsgListenerWrapper *listener;
MsgListenerWrapper *pListener;
bool intercept;
int msgid = params[1];
@ -390,12 +399,12 @@ static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
}
pNotify = pCtx->GetFunctionById(params[4]);
intercept = (params[3]) ? true : false;
listener = s_UsrMessageNatives.GetNewListener(pCtx);
listener->InitListener(msgid, pHook, pNotify, intercept);
g_UserMsgs.HookUserMessage(msgid, listener, intercept);
pListener = s_UsrMessageNatives.CreateListener(pCtx);
pListener->Initialize(msgid, pHook, pNotify, intercept);
g_UserMsgs.HookUserMessage(msgid, pListener, intercept);
return 1;
}
@ -403,7 +412,8 @@ static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params)
{
IPluginFunction *pFunc;
MsgListenerWrapper *listener;
MsgListenerWrapper *pListener;
MsgWrapperIter iter;
bool intercept;
int msgid = params[1];
@ -417,20 +427,21 @@ static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params)
{
return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
}
intercept = (params[3]) ? true : false;
listener = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept);
if (!listener)
iter = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept);
if (iter == NULL)
{
return pCtx->ThrowNativeError("Unable to unhook the current user message");
}
if (!g_UserMsgs.UnhookUserMessage(msgid, listener, intercept))
pListener = (*iter);
if (!g_UserMsgs.UnhookUserMessage(msgid, pListener, intercept))
{
return pCtx->ThrowNativeError("Unable to unhook the current user message");
}
s_UsrMessageNatives.RemoveListener(pCtx, listener, intercept);
s_UsrMessageNatives.DeleteListener(pCtx, iter);
return 1;
}

View File

@ -20,7 +20,7 @@ extern int g_MsgPlayers[256];
class MsgListenerWrapper : public IUserMessageListener
{
public:
void InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept);
void Initialize(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept);
bool IsInterceptHook() const;
int GetMessageId() const;
IPluginFunction *GetHookedFunction() const;
@ -30,7 +30,7 @@ public: //IUserMessageListener
ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
void OnUserMessageSent(int msg_id);
private:
size_t PreparePlArray(int *pl_array, IRecipientFilter *pFilter);
size_t _FillInPlayers(int *pl_array, IRecipientFilter *pFilter);
private:
IPluginFunction *m_Hook;
IPluginFunction *m_Intercept;

View File

@ -26,7 +26,7 @@
#include "PlayerManager.h"
#include "Translator.h"
#include "ForwardSys.h"
#include "CTimerSys.h"
#include "TimerSys.h"
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);