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
|
||||
{
|
||||
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() {}
|
||||
public: //IRecipientFilter
|
||||
bool IsReliable() const;
|
||||
@ -34,10 +34,10 @@ public:
|
||||
void SetInitMessage(bool isinitmsg);
|
||||
void ResetFilter();
|
||||
private:
|
||||
cell_t m_CellRecipients[255];
|
||||
bool m_Reliable;
|
||||
bool m_InitMessage;
|
||||
size_t m_Size;
|
||||
cell_t *m_CellRecipients;
|
||||
};
|
||||
|
||||
inline void CellRecipientFilter::ResetFilter()
|
||||
@ -45,7 +45,6 @@ inline void CellRecipientFilter::ResetFilter()
|
||||
m_Reliable = false;
|
||||
m_InitMessage = false;
|
||||
m_Size = 0;
|
||||
m_CellRecipients = NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
m_CellRecipients = ptr;
|
||||
memcpy(m_CellRecipients, ptr, count * sizeof(cell_t));
|
||||
m_Size = count;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
@ -223,6 +223,10 @@
|
||||
RelativePath="..\CTranslator.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CUserMessages.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sm_autonatives.cpp"
|
||||
>
|
||||
@ -294,7 +298,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CMsgIdPool.h"
|
||||
RelativePath="..\CMsgListenerWrapper.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -309,6 +313,10 @@
|
||||
RelativePath="..\CTranslator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CUserMessages.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sm_autonatives.h"
|
||||
>
|
||||
@ -409,6 +417,10 @@
|
||||
RelativePath="..\..\public\ITextParsers.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\public\IUserMessages.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Systems"
|
||||
|
@ -13,39 +13,147 @@
|
||||
*/
|
||||
|
||||
#include "HandleSys.h"
|
||||
#include "CellRecipientFilter.h"
|
||||
#include "CMsgIdPool.h"
|
||||
#include "PluginSys.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;
|
||||
Handle_t g_CurMsgHandle;
|
||||
int g_MsgPlayers[256];
|
||||
bool g_IsMsgInExec = false;
|
||||
int g_CurMsgFlags = 0;
|
||||
|
||||
class UsrMessageNatives :
|
||||
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:
|
||||
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_PluginSys.AddPluginsListener(this);
|
||||
}
|
||||
void OnSourceModShutdown()
|
||||
|
||||
void UsrMessageNatives::OnSourceModShutdown()
|
||||
{
|
||||
g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
|
||||
g_PluginSys.RemovePluginsListener(this);
|
||||
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)
|
||||
{
|
||||
@ -57,7 +165,7 @@ static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return g_MessageIds.GetMessageId(msgname);
|
||||
return g_UserMsgs.GetMessageIndex(msgname);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
pCtx->LocalToPhysAddr(params[2], &cl_array);
|
||||
g_CurMsgFlags = params[4];
|
||||
|
||||
g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]);
|
||||
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);
|
||||
}
|
||||
pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
|
||||
|
||||
g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
|
||||
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");
|
||||
}
|
||||
|
||||
if (msgid < 0 || msgid > 255)
|
||||
if (msgid < 0 || msgid >= 255)
|
||||
{
|
||||
return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
|
||||
}
|
||||
|
||||
pCtx->LocalToPhysAddr(params[2], &cl_array);
|
||||
g_CurMsgFlags = params[4];
|
||||
|
||||
g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]);
|
||||
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);
|
||||
}
|
||||
pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
|
||||
|
||||
g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
|
||||
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");
|
||||
}
|
||||
|
||||
if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
|
||||
{
|
||||
engine->MessageEnd();
|
||||
} else {
|
||||
ENGINE_CALL(MessageEnd)();
|
||||
}
|
||||
g_UserMsgs.EndMessage();
|
||||
|
||||
sec.pOwner = pCtx->GetIdentity();
|
||||
sec.pIdentity = g_pCoreIdent;
|
||||
g_HandleSys.FreeHandle(g_CurMsgHandle, &sec);
|
||||
|
||||
g_IsMsgInExec = false;
|
||||
g_CurMsgFlags = 0;
|
||||
g_MsgRecFilter.ResetFilter();
|
||||
|
||||
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)
|
||||
{
|
||||
@ -186,5 +315,7 @@ REGISTER_NATIVES(usrmsgnatives)
|
||||
{"StartMessage", smn_StartMessage},
|
||||
{"StartMessageEx", smn_StartMessageEx},
|
||||
{"EndMessage", smn_EndMessage},
|
||||
{"HookUserMessage", smn_HookUserMessage},
|
||||
{"UnHookUserMessage", smn_UnHookUserMessage},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
@ -85,6 +85,7 @@ native EndMessage();
|
||||
* @brief Called when a message is hooked
|
||||
*
|
||||
* @param msg_id Message index.
|
||||
* @param bf Handle to the input bit buffer of the message.
|
||||
* @param players Array containing player indexes.
|
||||
* @param playersNum Number of players in the array.
|
||||
* @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
|
||||
* 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.
|
||||
@ -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,
|
||||
* allowing the user to block the message. Otherwise,
|
||||
* the hook is normal and ignores the return value.
|
||||
* @param notify Notification function.
|
||||
* @noreturn
|
||||
* @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.
|
||||
@ -118,33 +127,6 @@ native HookUserMessage(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.
|
||||
* @note See StartMessage or StartMessageEx().
|
||||
|
@ -19,7 +19,9 @@
|
||||
#ifndef _INCLUDE_SOURCEMOD_INTERFACE_USERMESSAGES_H_
|
||||
#define _INCLUDE_SOURCEMOD_INTERFACE_USERMESSAGES_H_
|
||||
|
||||
#include <IShareSys.h>
|
||||
#include <sp_vm_api.h>
|
||||
#include <IForwardSys.h>
|
||||
#include <bitbuf.h>
|
||||
#include <irecipientfilter.h>
|
||||
|
||||
@ -59,9 +61,9 @@ namespace SourceMod
|
||||
* @param pFtiler Recipient filter.
|
||||
* @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.
|
||||
*/
|
||||
@ -127,14 +134,15 @@ namespace SourceMod
|
||||
* @param players Array containing player indexes.
|
||||
* @param playersNum Number of players in the array.
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @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