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

View File

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

View File

@ -26,7 +26,15 @@ using namespace SourceMod;
#define INVALID_MESSAGE_ID -1 #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 : class CUserMessages :
public IUserMessages, public IUserMessages,
@ -51,8 +59,11 @@ public:
void OnMessageEnd_Pre(); void OnMessageEnd_Pre();
void OnMessageEnd_Post(); void OnMessageEnd_Post();
private: private:
List<IUserMessageListener *> m_msgHooks[255]; void _DecRefCounter();
List<IUserMessageListener *> m_msgIntercepts[255]; private:
List<ListenerInfo *> m_msgHooks[255];
List<ListenerInfo *> m_msgIntercepts[255];
CStack<ListenerInfo *> m_FreeListeners;
unsigned char m_pBase[2500]; unsigned char m_pBase[2500];
IRecipientFilter *m_CurRecFilter; IRecipientFilter *m_CurRecFilter;
bf_write m_InterceptBuffer; bf_write m_InterceptBuffer;

View File

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

View File

@ -22,6 +22,9 @@ Handle_t g_CurMsgHandle;
int g_MsgPlayers[256]; int g_MsgPlayers[256];
bool g_IsMsgInExec = false; bool g_IsMsgInExec = false;
typedef List<MsgListenerWrapper *> MsgWrapperList;
typedef List<MsgListenerWrapper *>::iterator MsgWrapperIter;
class UsrMessageNatives : class UsrMessageNatives :
public SMGlobalClass, public SMGlobalClass,
public IHandleTypeDispatch, public IHandleTypeDispatch,
@ -33,9 +36,9 @@ public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener
void OnHandleDestroy(HandleType_t type, void *object); void OnHandleDestroy(HandleType_t type, void *object);
void OnPluginUnloaded(IPlugin *plugin); void OnPluginUnloaded(IPlugin *plugin);
public: public:
MsgListenerWrapper *GetNewListener(IPluginContext *pCtx); MsgListenerWrapper *CreateListener(IPluginContext *pCtx);
MsgListenerWrapper *FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept); MsgWrapperIter FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept);
bool RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept); bool DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter);
private: private:
CStack<MsgListenerWrapper *> m_FreeListeners; CStack<MsgListenerWrapper *> m_FreeListeners;
}; };
@ -59,92 +62,91 @@ void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object)
void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin) 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; MsgWrapperIter iter;
MsgListenerWrapper *listener; MsgListenerWrapper *pListener;
for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++) for (iter=pList->begin(); iter!=pList->end(); iter++)
{ {
listener = (*iter); pListener = (*iter);
if (g_UserMsgs.UnhookUserMessage(listener->GetMessageId(), listener, listener->IsInterceptHook())) 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()) if (m_FreeListeners.empty())
{ {
listener_wrapper = new MsgListenerWrapper; pListener = new MsgListenerWrapper;
} else { } else {
listener_wrapper = m_FreeListeners.front(); pListener = m_FreeListeners.front();
m_FreeListeners.pop(); m_FreeListeners.pop();
} }
List<MsgListenerWrapper *> *wrapper_list; if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
{ {
wrapper_list = new List<MsgListenerWrapper *>; pList = new List<MsgListenerWrapper *>;
pl->SetProperty("MsgListeners", wrapper_list); 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; MsgWrapperList *pList;
List<MsgListenerWrapper *> *wrapper_list; MsgWrapperIter iter;
List<MsgListenerWrapper *>::iterator iter; MsgListenerWrapper *pListener;
IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext()); 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; return NULL;
} }
for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++) for (iter=pList->begin(); iter!=pList->end(); iter++)
{ {
listener = (*iter); pListener = (*iter);
if ((msgid == listener->GetMessageId()) if ((msgid == pListener->GetMessageId())
&& (intercept == listener->IsInterceptHook()) && (intercept == pListener->IsInterceptHook())
&& (pHook == listener->GetHookedFunction())) && (pHook == pListener->GetHookedFunction()))
{ {
found = true; return iter;
break;
} }
} }
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()); 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; return false;
} }
wrapper_list->remove(listener); pListener = (*iter);
m_FreeListeners.push(listener); pList->erase(iter);
m_FreeListeners.push(pListener);
return true; 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()); size_t size = static_cast<size_t>(pFilter->GetRecipientCount());
@ -192,32 +216,10 @@ IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const
return m_Notify; 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) void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
{ {
cell_t res; 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(msg_id);
m_Hook->PushCell(0); //:TODO: push handle! 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) ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
{ {
cell_t res = static_cast<cell_t>(Pl_Continue); 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(msg_id);
m_Intercept->PushCell(0); //:TODO: push handle! 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) void MsgListenerWrapper::OnUserMessageSent(int msg_id)
{ {
cell_t res;
if (!m_Notify) if (!m_Notify)
{ {
return; return;
} }
cell_t res;
m_Notify->PushCell(msg_id); m_Notify->PushCell(msg_id);
m_Notify->Execute(&res); 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); pCtx->LocalToPhysAddr(params[2], &cl_array);
pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]); 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_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
g_IsMsgInExec = true; g_IsMsgInExec = true;
@ -345,6 +350,10 @@ static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params)
pCtx->LocalToPhysAddr(params[2], &cl_array); pCtx->LocalToPhysAddr(params[2], &cl_array);
pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]); 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_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
g_IsMsgInExec = true; 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) static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
{ {
IPluginFunction *pHook, *pNotify; IPluginFunction *pHook, *pNotify;
MsgListenerWrapper *listener; MsgListenerWrapper *pListener;
bool intercept; bool intercept;
int msgid = params[1]; 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]); return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
} }
pNotify = pCtx->GetFunctionById(params[4]); pNotify = pCtx->GetFunctionById(params[4]);
intercept = (params[3]) ? true : false; 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; 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) static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params)
{ {
IPluginFunction *pFunc; IPluginFunction *pFunc;
MsgListenerWrapper *listener; MsgListenerWrapper *pListener;
MsgWrapperIter iter;
bool intercept; bool intercept;
int msgid = params[1]; 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]); return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
} }
intercept = (params[3]) ? true : false; 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"); 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"); return pCtx->ThrowNativeError("Unable to unhook the current user message");
} }
s_UsrMessageNatives.RemoveListener(pCtx, listener, intercept); s_UsrMessageNatives.DeleteListener(pCtx, iter);
return 1; return 1;
} }

View File

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

View File

@ -26,7 +26,7 @@
#include "PlayerManager.h" #include "PlayerManager.h"
#include "Translator.h" #include "Translator.h"
#include "ForwardSys.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_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); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);