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
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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"
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user