initial implementation of message hooks
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40558
This commit is contained in:
parent
f7df18f6fd
commit
7ebe3f33cd
@ -1,63 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* ===============================================================
|
|
||||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
|
||||||
* ===============================================================
|
|
||||||
*
|
|
||||||
* This file is not open source and may not be copied without explicit
|
|
||||||
* written permission of AlliedModders LLC. This file may not be redistributed
|
|
||||||
* in whole or significant part.
|
|
||||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
|
||||||
*
|
|
||||||
* Version: $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_SOURCEMOD_CMSGIDPOOL_H_
|
|
||||||
#define _INCLUDE_SOURCEMOD_CMSGIDPOOL_H_
|
|
||||||
|
|
||||||
#include "sm_trie.h"
|
|
||||||
#include "sourcemm_api.h"
|
|
||||||
|
|
||||||
#define INVALID_MESSAGE_ID -1
|
|
||||||
|
|
||||||
class CMessageIdPool
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CMessageIdPool()
|
|
||||||
{
|
|
||||||
m_Names = sm_trie_create();
|
|
||||||
}
|
|
||||||
~CMessageIdPool()
|
|
||||||
{
|
|
||||||
sm_trie_destroy(m_Names);
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
int GetMessageId(const char *name)
|
|
||||||
{
|
|
||||||
int msgid;
|
|
||||||
if (!sm_trie_retrieve(m_Names, name, reinterpret_cast<void **>(&msgid)))
|
|
||||||
{
|
|
||||||
char buf[255];
|
|
||||||
int dummy;
|
|
||||||
msgid = 0;
|
|
||||||
|
|
||||||
while (gamedll->GetUserMessageInfo(msgid, buf, sizeof(buf), dummy))
|
|
||||||
{
|
|
||||||
if (strcmp(name, buf) == 0)
|
|
||||||
{
|
|
||||||
sm_trie_insert(m_Names, name, reinterpret_cast<void *>(msgid));
|
|
||||||
return msgid;
|
|
||||||
}
|
|
||||||
msgid++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return INVALID_MESSAGE_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
return msgid;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
Trie *m_Names;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_CMSGIDPOOL_H_
|
|
144
core/CMsgListenerWrapper.h
Normal file
144
core/CMsgListenerWrapper.h
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 :
|
||||||
|
* ===============================================================
|
||||||
|
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||||
|
* ===============================================================
|
||||||
|
*
|
||||||
|
* This file is not open source and may not be copied without explicit
|
||||||
|
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||||
|
* in whole or significant part.
|
||||||
|
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_
|
||||||
|
|
||||||
|
extern int g_MsgPlayers[256];
|
||||||
|
|
||||||
|
class MsgListenerWrapper : public IUserMessageListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void InitListener(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept);
|
||||||
|
bool IsInterceptHook() const;
|
||||||
|
int GetMessageId() const;
|
||||||
|
IPluginFunction *GetHookedFunction() const;
|
||||||
|
IPluginFunction *GetNotifyFunction() const;
|
||||||
|
public: //IUserMessageListener
|
||||||
|
void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
|
||||||
|
ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
|
||||||
|
void OnUserMessageSent(int msg_id);
|
||||||
|
private:
|
||||||
|
size_t PreparePlArray(int *pl_array, IRecipientFilter *pFilter);
|
||||||
|
private:
|
||||||
|
IPluginFunction *m_Hook;
|
||||||
|
IPluginFunction *m_Intercept;
|
||||||
|
IPluginFunction *m_Notify;
|
||||||
|
bool m_IsInterceptHook;
|
||||||
|
int m_MsgId;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline size_t MsgListenerWrapper::PreparePlArray(int *pl_array, IRecipientFilter *pFilter)
|
||||||
|
{
|
||||||
|
size_t size = static_cast<size_t>(pFilter->GetRecipientCount());
|
||||||
|
|
||||||
|
for (size_t i=0; i<size; i++)
|
||||||
|
{
|
||||||
|
pl_array[i] = pFilter->GetRecipientIndex(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool MsgListenerWrapper::IsInterceptHook() const
|
||||||
|
{
|
||||||
|
return m_IsInterceptHook;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int MsgListenerWrapper::GetMessageId() const
|
||||||
|
{
|
||||||
|
return m_MsgId;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IPluginFunction *MsgListenerWrapper::GetHookedFunction() const
|
||||||
|
{
|
||||||
|
if (m_Hook)
|
||||||
|
{
|
||||||
|
return m_Hook;
|
||||||
|
} else {
|
||||||
|
return m_Intercept;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const
|
||||||
|
{
|
||||||
|
return m_Notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
|
||||||
|
{
|
||||||
|
cell_t res;
|
||||||
|
size_t size = PreparePlArray(g_MsgPlayers, pFilter);
|
||||||
|
|
||||||
|
m_Hook->PushCell(msg_id);
|
||||||
|
m_Hook->PushCell(0); //:TODO: push handle!
|
||||||
|
m_Hook->PushArray(g_MsgPlayers, size, NULL);
|
||||||
|
m_Hook->PushCell(size);
|
||||||
|
m_Hook->PushCell(pFilter->IsReliable());
|
||||||
|
m_Hook->PushCell(pFilter->IsInitMessage());
|
||||||
|
m_Hook->Execute(&res);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline 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);
|
||||||
|
|
||||||
|
m_Intercept->PushCell(msg_id);
|
||||||
|
m_Intercept->PushCell(0); //:TODO: push handle!
|
||||||
|
m_Intercept->PushArray(g_MsgPlayers, size, NULL);
|
||||||
|
m_Intercept->PushCell(size);
|
||||||
|
m_Intercept->PushCell(pFilter->IsReliable());
|
||||||
|
m_Intercept->PushCell(pFilter->IsInitMessage());
|
||||||
|
m_Intercept->Execute(&res);
|
||||||
|
|
||||||
|
return static_cast<ResultType>(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MsgListenerWrapper::OnUserMessageSent(int msg_id)
|
||||||
|
{
|
||||||
|
cell_t res;
|
||||||
|
|
||||||
|
if (!m_Notify)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Notify->PushCell(msg_id);
|
||||||
|
m_Notify->Execute(&res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_
|
314
core/CUserMessages.cpp
Normal file
314
core/CUserMessages.cpp
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 :
|
||||||
|
* ===============================================================
|
||||||
|
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||||
|
* ===============================================================
|
||||||
|
*
|
||||||
|
* This file is not open source and may not be copied without explicit
|
||||||
|
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||||
|
* in whole or significant part.
|
||||||
|
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CUserMessages.h"
|
||||||
|
|
||||||
|
CUserMessages g_UserMsgs;
|
||||||
|
|
||||||
|
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
|
||||||
|
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
|
||||||
|
|
||||||
|
CUserMessages::CUserMessages() : m_InterceptBuffer(m_pBase, 2500)
|
||||||
|
{
|
||||||
|
m_Names = sm_trie_create();
|
||||||
|
m_HookCount = 0;
|
||||||
|
m_InExec = false;
|
||||||
|
m_InHook = false;
|
||||||
|
m_CurFlags = 0;
|
||||||
|
m_CurId = INVALID_MESSAGE_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUserMessages::~CUserMessages()
|
||||||
|
{
|
||||||
|
sm_trie_destroy(m_Names);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUserMessages::OnSourceModAllShutdown()
|
||||||
|
{
|
||||||
|
if (m_HookCount)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
m_HookCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CUserMessages::GetMessageIndex(const char *msg)
|
||||||
|
{
|
||||||
|
int msgid;
|
||||||
|
if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
|
||||||
|
{
|
||||||
|
char buf[255];
|
||||||
|
int dummy;
|
||||||
|
msgid = 0;
|
||||||
|
|
||||||
|
while (gamedll->GetUserMessageInfo(msgid, buf, sizeof(buf), dummy))
|
||||||
|
{
|
||||||
|
if (strcmp(msg, buf) == 0)
|
||||||
|
{
|
||||||
|
sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
|
||||||
|
return msgid;
|
||||||
|
}
|
||||||
|
msgid++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return INVALID_MESSAGE_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return msgid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags)
|
||||||
|
{
|
||||||
|
bf_write *buffer;
|
||||||
|
|
||||||
|
if (m_InExec)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (msg_id < 0 || msg_id >= 255)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_CellRecFilter.SetRecipientPtr(players, playersNum);
|
||||||
|
|
||||||
|
m_CurFlags = flags;
|
||||||
|
if (m_CurFlags & USERMSG_INITMSG)
|
||||||
|
{
|
||||||
|
m_CellRecFilter.SetInitMessage(true);
|
||||||
|
}
|
||||||
|
if (m_CurFlags & USERMSG_RELIABLE)
|
||||||
|
{
|
||||||
|
m_CellRecFilter.SetReliable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_InExec = true;
|
||||||
|
|
||||||
|
if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
|
||||||
|
{
|
||||||
|
buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
|
||||||
|
} else {
|
||||||
|
buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CUserMessages::EndMessage()
|
||||||
|
{
|
||||||
|
if (!m_InExec)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
|
||||||
|
{
|
||||||
|
engine->MessageEnd();
|
||||||
|
} else {
|
||||||
|
ENGINE_CALL(MessageEnd)();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_InExec = false;
|
||||||
|
m_CurFlags = 0;
|
||||||
|
m_CellRecFilter.ResetFilter();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
|
||||||
|
{
|
||||||
|
if (msg_id < 0 || msg_id >= 255)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_Post, true);
|
||||||
|
SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
|
||||||
|
SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intercept)
|
||||||
|
{
|
||||||
|
m_msgIntercepts[msg_id].push_back(pListener);
|
||||||
|
} else {
|
||||||
|
m_msgHooks[msg_id].push_back(pListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
MsgIter iter;
|
||||||
|
bool deleted = false;
|
||||||
|
|
||||||
|
if (msg_id < 0 || msg_id >= 255)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lst = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
|
||||||
|
for (iter=lst->begin(); iter!=lst->end(); iter++)
|
||||||
|
{
|
||||||
|
listener = (*iter);
|
||||||
|
if (listener == pListener)
|
||||||
|
{
|
||||||
|
lst->erase(iter);
|
||||||
|
deleted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deleted && !(--m_HookCount))
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
m_InHook = false;
|
||||||
|
RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_CurId = msg_type;
|
||||||
|
m_CurRecFilter = filter;
|
||||||
|
m_InterceptBuffer.Reset();
|
||||||
|
m_InHook = true;
|
||||||
|
|
||||||
|
if (!is_intercept_empty)
|
||||||
|
{
|
||||||
|
RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bf_write *CUserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
|
||||||
|
{
|
||||||
|
if (!m_InHook)
|
||||||
|
{
|
||||||
|
RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
|
||||||
|
|
||||||
|
RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUserMessages::OnMessageEnd_Post()
|
||||||
|
{
|
||||||
|
if (!m_InHook || (META_RESULT_STATUS == MRES_SUPERCEDE))
|
||||||
|
{
|
||||||
|
RETURN_META(MRES_IGNORED);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IUserMessageListener *> *lst;
|
||||||
|
IUserMessageListener *listener;
|
||||||
|
MsgIter iter;
|
||||||
|
|
||||||
|
lst = &m_msgIntercepts[m_CurId];
|
||||||
|
for (iter=lst->begin(); iter!=lst->end(); iter++)
|
||||||
|
{
|
||||||
|
listener = (*iter);
|
||||||
|
listener->OnUserMessageSent(m_CurId);
|
||||||
|
}
|
||||||
|
|
||||||
|
lst = &m_msgHooks[m_CurId];
|
||||||
|
for (iter=lst->begin(); iter!=lst->end(); iter++)
|
||||||
|
{
|
||||||
|
listener = (*iter);
|
||||||
|
listener->OnUserMessageSent(m_CurId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUserMessages::OnMessageEnd_Pre()
|
||||||
|
{
|
||||||
|
if (!m_InHook)
|
||||||
|
{
|
||||||
|
RETURN_META(MRES_IGNORED);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IUserMessageListener *> *lst;
|
||||||
|
IUserMessageListener *listener;
|
||||||
|
bf_write *engine_bfw;
|
||||||
|
MsgIter iter;
|
||||||
|
ResultType res;
|
||||||
|
bool intercepted = false;
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
lst = &m_msgIntercepts[m_CurId];
|
||||||
|
for (iter=lst->begin(); iter!=lst->end(); iter++)
|
||||||
|
{
|
||||||
|
listener = (*iter);
|
||||||
|
res = listener->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
|
||||||
|
if (res == Pl_Stop)
|
||||||
|
{
|
||||||
|
goto supercede;
|
||||||
|
} else if (res == Pl_Handled) {
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
intercepted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled)
|
||||||
|
{
|
||||||
|
goto supercede;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intercepted)
|
||||||
|
{
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
listener = (*iter);
|
||||||
|
listener->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_META(MRES_IGNORED);
|
||||||
|
supercede:
|
||||||
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
|
}
|
72
core/CUserMessages.h
Normal file
72
core/CUserMessages.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 :
|
||||||
|
* ===============================================================
|
||||||
|
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||||
|
* ===============================================================
|
||||||
|
*
|
||||||
|
* This file is not open source and may not be copied without explicit
|
||||||
|
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||||
|
* in whole or significant part.
|
||||||
|
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_
|
||||||
|
|
||||||
|
#include "sm_globals.h"
|
||||||
|
#include <IUserMessages.h>
|
||||||
|
#include <sh_list.h>
|
||||||
|
#include "sourcemm_api.h"
|
||||||
|
#include "sm_trie.h"
|
||||||
|
#include "CellRecipientFilter.h"
|
||||||
|
|
||||||
|
using namespace SourceHook;
|
||||||
|
using namespace SourceMod;
|
||||||
|
|
||||||
|
#define INVALID_MESSAGE_ID -1
|
||||||
|
|
||||||
|
typedef List<IUserMessageListener *>::iterator MsgIter;
|
||||||
|
|
||||||
|
class CUserMessages :
|
||||||
|
public IUserMessages,
|
||||||
|
public SMGlobalClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CUserMessages();
|
||||||
|
~CUserMessages();
|
||||||
|
public: //SMGlobalClass
|
||||||
|
void OnSourceModAllShutdown();
|
||||||
|
public: //IUserMessages
|
||||||
|
int GetMessageIndex(const char *msg);
|
||||||
|
bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
|
||||||
|
bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
|
||||||
|
bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags);
|
||||||
|
bool EndMessage();
|
||||||
|
public:
|
||||||
|
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type);
|
||||||
|
bf_write *OnStartMessage_Post(IRecipientFilter *filter, int msg_type);
|
||||||
|
void OnMessageEnd_Pre();
|
||||||
|
void OnMessageEnd_Post();
|
||||||
|
private:
|
||||||
|
List<IUserMessageListener *> m_msgHooks[255];
|
||||||
|
List<IUserMessageListener *> m_msgIntercepts[255];
|
||||||
|
unsigned char m_pBase[2500];
|
||||||
|
IRecipientFilter *m_CurRecFilter;
|
||||||
|
bf_write m_InterceptBuffer;
|
||||||
|
bf_write *m_OrigBuffer;
|
||||||
|
bf_read m_ReadBuffer;
|
||||||
|
size_t m_HookCount;
|
||||||
|
bool m_InHook;
|
||||||
|
|
||||||
|
Trie *m_Names;
|
||||||
|
CellRecipientFilter m_CellRecFilter;
|
||||||
|
bool m_InExec;
|
||||||
|
int m_CurFlags;
|
||||||
|
int m_CurId;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern CUserMessages g_UserMsgs;
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SOURCEMOD_CUSERMESSAGES_H_
|
@ -21,7 +21,7 @@
|
|||||||
class CellRecipientFilter : public IRecipientFilter
|
class CellRecipientFilter : public IRecipientFilter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CellRecipientFilter() : m_Reliable(false), m_InitMessage(false), m_Size(0), m_CellRecipients(NULL) {}
|
CellRecipientFilter() : m_Reliable(false), m_InitMessage(false), m_Size(0) {}
|
||||||
~CellRecipientFilter() {}
|
~CellRecipientFilter() {}
|
||||||
public: //IRecipientFilter
|
public: //IRecipientFilter
|
||||||
bool IsReliable() const;
|
bool IsReliable() const;
|
||||||
@ -34,10 +34,10 @@ public:
|
|||||||
void SetInitMessage(bool isinitmsg);
|
void SetInitMessage(bool isinitmsg);
|
||||||
void ResetFilter();
|
void ResetFilter();
|
||||||
private:
|
private:
|
||||||
|
cell_t m_CellRecipients[255];
|
||||||
bool m_Reliable;
|
bool m_Reliable;
|
||||||
bool m_InitMessage;
|
bool m_InitMessage;
|
||||||
size_t m_Size;
|
size_t m_Size;
|
||||||
cell_t *m_CellRecipients;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void CellRecipientFilter::ResetFilter()
|
inline void CellRecipientFilter::ResetFilter()
|
||||||
@ -45,7 +45,6 @@ inline void CellRecipientFilter::ResetFilter()
|
|||||||
m_Reliable = false;
|
m_Reliable = false;
|
||||||
m_InitMessage = false;
|
m_InitMessage = false;
|
||||||
m_Size = 0;
|
m_Size = 0;
|
||||||
m_CellRecipients = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool CellRecipientFilter::IsReliable() const
|
inline bool CellRecipientFilter::IsReliable() const
|
||||||
@ -84,7 +83,7 @@ inline void CellRecipientFilter::SetReliable(bool isreliable)
|
|||||||
|
|
||||||
inline void CellRecipientFilter::SetRecipientPtr(cell_t *ptr, size_t count)
|
inline void CellRecipientFilter::SetRecipientPtr(cell_t *ptr, size_t count)
|
||||||
{
|
{
|
||||||
m_CellRecipients = ptr;
|
memcpy(m_CellRecipients, ptr, count * sizeof(cell_t));
|
||||||
m_Size = count;
|
m_Size = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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"
|
||||||
@ -223,6 +223,10 @@
|
|||||||
RelativePath="..\CTranslator.cpp"
|
RelativePath="..\CTranslator.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\CUserMessages.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\sm_autonatives.cpp"
|
RelativePath="..\sm_autonatives.cpp"
|
||||||
>
|
>
|
||||||
@ -294,7 +298,7 @@
|
|||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\CMsgIdPool.h"
|
RelativePath="..\CMsgListenerWrapper.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
@ -309,6 +313,10 @@
|
|||||||
RelativePath="..\CTranslator.h"
|
RelativePath="..\CTranslator.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\CUserMessages.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\sm_autonatives.h"
|
RelativePath="..\sm_autonatives.h"
|
||||||
>
|
>
|
||||||
@ -409,6 +417,10 @@
|
|||||||
RelativePath="..\..\public\ITextParsers.h"
|
RelativePath="..\..\public\ITextParsers.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\public\IUserMessages.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Systems"
|
Name="Systems"
|
||||||
|
@ -13,39 +13,147 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "HandleSys.h"
|
#include "HandleSys.h"
|
||||||
#include "CellRecipientFilter.h"
|
#include "PluginSys.h"
|
||||||
#include "CMsgIdPool.h"
|
#include "CUserMessages.h"
|
||||||
|
#include "CMsgListenerWrapper.h"
|
||||||
|
|
||||||
#define USERMSG_PASSTHRU (1<<0)
|
|
||||||
#define USERMSG_PASSTHRU_ALL (1<<1)
|
|
||||||
#define USERMSG_RELIABLE (1<<2)
|
|
||||||
#define USERMSG_INITMSG (1<<3)
|
|
||||||
|
|
||||||
CMessageIdPool g_MessageIds;
|
|
||||||
CellRecipientFilter g_MsgRecFilter;
|
|
||||||
HandleType_t g_WrBitBufType;
|
HandleType_t g_WrBitBufType;
|
||||||
Handle_t g_CurMsgHandle;
|
Handle_t g_CurMsgHandle;
|
||||||
|
int g_MsgPlayers[256];
|
||||||
bool g_IsMsgInExec = false;
|
bool g_IsMsgInExec = false;
|
||||||
int g_CurMsgFlags = 0;
|
|
||||||
|
|
||||||
class UsrMessageNatives :
|
class UsrMessageNatives :
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IHandleTypeDispatch
|
public IHandleTypeDispatch,
|
||||||
|
public IPluginsListener
|
||||||
{
|
{
|
||||||
|
public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener
|
||||||
|
void OnSourceModAllInitialized();
|
||||||
|
void OnSourceModShutdown();
|
||||||
|
void OnHandleDestroy(HandleType_t type, void *object);
|
||||||
|
void OnPluginUnloaded(IPlugin *plugin);
|
||||||
public:
|
public:
|
||||||
void OnSourceModAllInitialized()
|
MsgListenerWrapper *GetNewListener(IPluginContext *pCtx);
|
||||||
|
MsgListenerWrapper *FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept);
|
||||||
|
bool RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept);
|
||||||
|
private:
|
||||||
|
CStack<MsgListenerWrapper *> m_FreeListeners;
|
||||||
|
};
|
||||||
|
|
||||||
|
void UsrMessageNatives::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||||
|
g_PluginSys.AddPluginsListener(this);
|
||||||
}
|
}
|
||||||
void OnSourceModShutdown()
|
|
||||||
|
void UsrMessageNatives::OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
|
g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
|
||||||
|
g_PluginSys.RemovePluginsListener(this);
|
||||||
g_WrBitBufType = 0;
|
g_WrBitBufType = 0;
|
||||||
}
|
}
|
||||||
void OnHandleDestroy(HandleType_t type, void *object)
|
void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin)
|
||||||
|
{
|
||||||
|
List<MsgListenerWrapper *> *wrapper_list;
|
||||||
|
|
||||||
|
if (plugin->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list), true))
|
||||||
|
{
|
||||||
|
List<MsgListenerWrapper *>::iterator iter;
|
||||||
|
MsgListenerWrapper *listener;
|
||||||
|
|
||||||
|
for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
|
||||||
|
{
|
||||||
|
listener = (*iter);
|
||||||
|
if (g_UserMsgs.UnhookUserMessage(listener->GetMessageId(), listener, listener->IsInterceptHook()))
|
||||||
|
{
|
||||||
|
m_FreeListeners.push(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete wrapper_list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MsgListenerWrapper *UsrMessageNatives::GetNewListener(IPluginContext *pCtx)
|
||||||
|
{
|
||||||
|
MsgListenerWrapper *listener_wrapper;
|
||||||
|
|
||||||
|
if (m_FreeListeners.empty())
|
||||||
|
{
|
||||||
|
listener_wrapper = new MsgListenerWrapper;
|
||||||
|
} else {
|
||||||
|
listener_wrapper = 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)))
|
||||||
|
{
|
||||||
|
wrapper_list = new List<MsgListenerWrapper *>;
|
||||||
|
pl->SetProperty("MsgListeners", wrapper_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper_list->push_back(listener_wrapper);
|
||||||
|
|
||||||
|
return listener_wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
MsgListenerWrapper *UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept)
|
||||||
|
{
|
||||||
|
MsgListenerWrapper *listener;
|
||||||
|
List<MsgListenerWrapper *> *wrapper_list;
|
||||||
|
List<MsgListenerWrapper *>::iterator iter;
|
||||||
|
IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
|
||||||
|
{
|
||||||
|
listener = (*iter);
|
||||||
|
if ((msgid == listener->GetMessageId())
|
||||||
|
&& (intercept == listener->IsInterceptHook())
|
||||||
|
&& (pHook == listener->GetHookedFunction()))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (found) ? listener : NULL;
|
||||||
|
}
|
||||||
|
bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept)
|
||||||
|
{
|
||||||
|
List<MsgListenerWrapper *> *wrapper_list;
|
||||||
|
IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
|
||||||
|
|
||||||
|
if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper_list->remove(listener);
|
||||||
|
m_FreeListeners.push(listener);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* *
|
||||||
|
* USER MESSAGE NATIVE IMPLEMENTATIONS *
|
||||||
|
* *
|
||||||
|
***************************************/
|
||||||
|
|
||||||
|
static UsrMessageNatives s_UsrMessageNatives;
|
||||||
|
|
||||||
static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
|
static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
|
||||||
{
|
{
|
||||||
@ -57,7 +165,7 @@ static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_MessageIds.GetMessageId(msgname);
|
return g_UserMsgs.GetMessageIndex(msgname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
|
static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
|
||||||
@ -78,30 +186,14 @@ static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((msgid=g_MessageIds.GetMessageId(msgname)) == INVALID_MESSAGE_ID)
|
if ((msgid=g_UserMsgs.GetMessageIndex(msgname)) == INVALID_MESSAGE_ID)
|
||||||
{
|
{
|
||||||
return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname);
|
return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname);
|
||||||
}
|
}
|
||||||
|
|
||||||
pCtx->LocalToPhysAddr(params[2], &cl_array);
|
pCtx->LocalToPhysAddr(params[2], &cl_array);
|
||||||
g_CurMsgFlags = params[4];
|
|
||||||
|
|
||||||
g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]);
|
pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
|
||||||
if (g_CurMsgFlags & USERMSG_INITMSG)
|
|
||||||
{
|
|
||||||
g_MsgRecFilter.SetInitMessage(true);
|
|
||||||
}
|
|
||||||
if (g_CurMsgFlags & USERMSG_RELIABLE)
|
|
||||||
{
|
|
||||||
g_MsgRecFilter.SetReliable(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) //:TODO: change this when we can hook messages
|
|
||||||
{
|
|
||||||
pBitBuf = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
|
|
||||||
} else {
|
|
||||||
pBitBuf = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
@ -120,30 +212,14 @@ static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params)
|
|||||||
return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
|
return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msgid < 0 || msgid > 255)
|
if (msgid < 0 || msgid >= 255)
|
||||||
{
|
{
|
||||||
return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
|
return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
|
||||||
}
|
}
|
||||||
|
|
||||||
pCtx->LocalToPhysAddr(params[2], &cl_array);
|
pCtx->LocalToPhysAddr(params[2], &cl_array);
|
||||||
g_CurMsgFlags = params[4];
|
|
||||||
|
|
||||||
g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]);
|
pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
|
||||||
if (g_CurMsgFlags & USERMSG_INITMSG)
|
|
||||||
{
|
|
||||||
g_MsgRecFilter.SetInitMessage(true);
|
|
||||||
}
|
|
||||||
if (g_CurMsgFlags & USERMSG_RELIABLE)
|
|
||||||
{
|
|
||||||
g_MsgRecFilter.SetReliable(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) //:TODO: change this when we can hook messages
|
|
||||||
{
|
|
||||||
pBitBuf = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
|
|
||||||
} else {
|
|
||||||
pBitBuf = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
@ -160,25 +236,78 @@ static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params)
|
|||||||
return pCtx->ThrowNativeError("Unable to end message, no message is in progress");
|
return pCtx->ThrowNativeError("Unable to end message, no message is in progress");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
|
g_UserMsgs.EndMessage();
|
||||||
{
|
|
||||||
engine->MessageEnd();
|
|
||||||
} else {
|
|
||||||
ENGINE_CALL(MessageEnd)();
|
|
||||||
}
|
|
||||||
|
|
||||||
sec.pOwner = pCtx->GetIdentity();
|
sec.pOwner = pCtx->GetIdentity();
|
||||||
sec.pIdentity = g_pCoreIdent;
|
sec.pIdentity = g_pCoreIdent;
|
||||||
g_HandleSys.FreeHandle(g_CurMsgHandle, &sec);
|
g_HandleSys.FreeHandle(g_CurMsgHandle, &sec);
|
||||||
|
|
||||||
g_IsMsgInExec = false;
|
g_IsMsgInExec = false;
|
||||||
g_CurMsgFlags = 0;
|
|
||||||
g_MsgRecFilter.ResetFilter();
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UsrMessageNatives s_UsrMessageNatives;
|
static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
|
||||||
|
{
|
||||||
|
IPluginFunction *pHook, *pNotify;
|
||||||
|
MsgListenerWrapper *listener;
|
||||||
|
bool intercept;
|
||||||
|
int msgid = params[1];
|
||||||
|
|
||||||
|
if (msgid < 0 || msgid >= 255)
|
||||||
|
{
|
||||||
|
return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
|
||||||
|
}
|
||||||
|
|
||||||
|
pHook = pCtx->GetFunctionById(params[2]);
|
||||||
|
if (!pHook)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params)
|
||||||
|
{
|
||||||
|
IPluginFunction *pFunc;
|
||||||
|
MsgListenerWrapper *listener;
|
||||||
|
bool intercept;
|
||||||
|
int msgid = params[1];
|
||||||
|
|
||||||
|
if (msgid < 0 || msgid >= 255)
|
||||||
|
{
|
||||||
|
return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
|
||||||
|
}
|
||||||
|
|
||||||
|
pFunc = pCtx->GetFunctionById(params[2]);
|
||||||
|
if (!pFunc)
|
||||||
|
{
|
||||||
|
return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
intercept = (params[3]) ? true : false;
|
||||||
|
listener = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept);
|
||||||
|
if (!listener)
|
||||||
|
{
|
||||||
|
return pCtx->ThrowNativeError("Unable to unhook the current user message");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_UserMsgs.UnhookUserMessage(msgid, listener, intercept))
|
||||||
|
{
|
||||||
|
return pCtx->ThrowNativeError("Unable to unhook the current user message");
|
||||||
|
}
|
||||||
|
|
||||||
|
s_UsrMessageNatives.RemoveListener(pCtx, listener, intercept);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
REGISTER_NATIVES(usrmsgnatives)
|
REGISTER_NATIVES(usrmsgnatives)
|
||||||
{
|
{
|
||||||
@ -186,5 +315,7 @@ REGISTER_NATIVES(usrmsgnatives)
|
|||||||
{"StartMessage", smn_StartMessage},
|
{"StartMessage", smn_StartMessage},
|
||||||
{"StartMessageEx", smn_StartMessageEx},
|
{"StartMessageEx", smn_StartMessageEx},
|
||||||
{"EndMessage", smn_EndMessage},
|
{"EndMessage", smn_EndMessage},
|
||||||
|
{"HookUserMessage", smn_HookUserMessage},
|
||||||
|
{"UnHookUserMessage", smn_UnHookUserMessage},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
@ -85,6 +85,7 @@ native EndMessage();
|
|||||||
* @brief Called when a message is hooked
|
* @brief Called when a message is hooked
|
||||||
*
|
*
|
||||||
* @param msg_id Message index.
|
* @param msg_id Message index.
|
||||||
|
* @param bf Handle to the input bit buffer of the message.
|
||||||
* @param players Array containing player indexes.
|
* @param players Array containing player indexes.
|
||||||
* @param playersNum Number of players in the array.
|
* @param playersNum Number of players in the array.
|
||||||
* @param reliable True if message is reliable, false otherwise.
|
* @param reliable True if message is reliable, false otherwise.
|
||||||
@ -92,7 +93,14 @@ native EndMessage();
|
|||||||
* @return Ignored for normal hooks. For intercept hooks, false blocks
|
* @return Ignored for normal hooks. For intercept hooks, false blocks
|
||||||
* the message from being sent, and true continues.
|
* the message from being sent, and true continues.
|
||||||
*/
|
*/
|
||||||
functag MsgHook bool:public(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init);
|
functag MsgHook Action:public(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when a message is finished sending.
|
||||||
|
*
|
||||||
|
* @param msg_id Message index.
|
||||||
|
*/
|
||||||
|
functag MsgSentNotify public(UserMsg:msg_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Hooks a user message.
|
* @brief Hooks a user message.
|
||||||
@ -102,10 +110,11 @@ functag MsgHook bool:public(UserMsg:msg_id, Handle:bf, const players[], playersN
|
|||||||
* @param intercept If intercept is true, message will be fully intercepted,
|
* @param intercept If intercept is true, message will be fully intercepted,
|
||||||
* allowing the user to block the message. Otherwise,
|
* allowing the user to block the message. Otherwise,
|
||||||
* the hook is normal and ignores the return value.
|
* the hook is normal and ignores the return value.
|
||||||
|
* @param notify Notification function.
|
||||||
* @noreturn
|
* @noreturn
|
||||||
* @error Invalid message index.
|
* @error Invalid message index.
|
||||||
*/
|
*/
|
||||||
native HookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false);
|
native HookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false, MsgSentNotify:notify=MsgSentNotify:-1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Removes one usermessage hook.
|
* @brief Removes one usermessage hook.
|
||||||
@ -118,33 +127,6 @@ native HookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false);
|
|||||||
*/
|
*/
|
||||||
native UnHookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false);
|
native UnHookUserMessage(UserMsg:msg_id, MsgHook:hook, bool:intercept=false);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Called when a message is finished sending.
|
|
||||||
*
|
|
||||||
* @param msg_id Message index.
|
|
||||||
*/
|
|
||||||
functag MsgSentNotify public(UserMsg:msg_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Notifies when a message has finished sending.
|
|
||||||
*
|
|
||||||
* @param msg_id Message index.
|
|
||||||
* @param notify Notification function.
|
|
||||||
* @noreturn
|
|
||||||
* @error Invalid message index.
|
|
||||||
*/
|
|
||||||
native NotifyUserMessage(UserMsg:msg_id, MsgSentNotify:notify);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Removes a user message notification.
|
|
||||||
*
|
|
||||||
* @param msg_id Message index.
|
|
||||||
* @param notify Notification function.
|
|
||||||
* @noreturn
|
|
||||||
* @error Invalid message index.
|
|
||||||
*/
|
|
||||||
native RemoveNotifyUserMessage(UserMsg:msg_id, MsgSentNotify:notify);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a usermessage (network message) that broadcasts to all clients.
|
* Starts a usermessage (network message) that broadcasts to all clients.
|
||||||
* @note See StartMessage or StartMessageEx().
|
* @note See StartMessage or StartMessageEx().
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_INTERFACE_USERMESSAGES_H_
|
#ifndef _INCLUDE_SOURCEMOD_INTERFACE_USERMESSAGES_H_
|
||||||
#define _INCLUDE_SOURCEMOD_INTERFACE_USERMESSAGES_H_
|
#define _INCLUDE_SOURCEMOD_INTERFACE_USERMESSAGES_H_
|
||||||
|
|
||||||
|
#include <IShareSys.h>
|
||||||
#include <sp_vm_api.h>
|
#include <sp_vm_api.h>
|
||||||
|
#include <IForwardSys.h>
|
||||||
#include <bitbuf.h>
|
#include <bitbuf.h>
|
||||||
#include <irecipientfilter.h>
|
#include <irecipientfilter.h>
|
||||||
|
|
||||||
@ -59,9 +61,9 @@ namespace SourceMod
|
|||||||
* @param pFtiler Recipient filter.
|
* @param pFtiler Recipient filter.
|
||||||
* @return True to allow message, false to scrap it.
|
* @return True to allow message, false to scrap it.
|
||||||
*/
|
*/
|
||||||
virtual bool InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
|
virtual ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
|
||||||
{
|
{
|
||||||
return true;
|
return Pl_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,6 +75,11 @@ namespace SourceMod
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define USERMSG_PASSTHRU (1<<0) /**< Message will pass through other SourceMM plugins */
|
||||||
|
#define USERMSG_PASSTHRU_ALL (1<<1) /**< Message will pass through other SourceMM plugins AND SourceMod */
|
||||||
|
#define USERMSG_RELIABLE (1<<2) /**< Message will be set to reliable */
|
||||||
|
#define USERMSG_INITMSG (1<<3) /**< Message will be considered to be an initmsg */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Contains functions for hooking user messages.
|
* @brief Contains functions for hooking user messages.
|
||||||
*/
|
*/
|
||||||
@ -127,14 +134,15 @@ namespace SourceMod
|
|||||||
* @param players Array containing player indexes.
|
* @param players Array containing player indexes.
|
||||||
* @param playersNum Number of players in the array.
|
* @param playersNum Number of players in the array.
|
||||||
* @param flags Flags to use for sending the message.
|
* @param flags Flags to use for sending the message.
|
||||||
* @return bf_write structure to write message with.
|
* @return bf_write structure to write message with, or NULL on failure.
|
||||||
*/
|
*/
|
||||||
virtual bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) =0;
|
virtual bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) =0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Wrapper around UserMessageEnd for use with StartMessage().
|
* @brief Wrapper around UserMessageEnd for use with StartMessage().
|
||||||
|
* @return True on success, false otherwise.
|
||||||
*/
|
*/
|
||||||
virtual void EndMessage() =0;
|
virtual bool EndMessage() =0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user