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:
parent
5b1f1d19c1
commit
f78b3fa086
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user