341 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			341 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/**
 | 
						|
* 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 "HandleSys.h"
 | 
						|
#include "PluginSys.h"
 | 
						|
#include "CUserMessages.h"
 | 
						|
#include "CMsgListenerWrapper.h"
 | 
						|
 | 
						|
HandleType_t g_WrBitBufType;
 | 
						|
Handle_t g_CurMsgHandle;
 | 
						|
int g_MsgPlayers[256];
 | 
						|
bool g_IsMsgInExec = false;
 | 
						|
 | 
						|
class UsrMessageNatives :
 | 
						|
	public SMGlobalClass,
 | 
						|
	public IHandleTypeDispatch,
 | 
						|
	public IPluginsListener
 | 
						|
{
 | 
						|
public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener
 | 
						|
	void OnSourceModAllInitialized();
 | 
						|
	void OnSourceModShutdown();
 | 
						|
	void OnHandleDestroy(HandleType_t type, void *object);
 | 
						|
	void OnPluginUnloaded(IPlugin *plugin);
 | 
						|
public:
 | 
						|
	MsgListenerWrapper *GetNewListener(IPluginContext *pCtx);
 | 
						|
	MsgListenerWrapper *FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept);
 | 
						|
	bool RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept);
 | 
						|
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 UsrMessageNatives::OnSourceModShutdown()
 | 
						|
{
 | 
						|
	g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
 | 
						|
	g_PluginSys.RemovePluginsListener(this);
 | 
						|
	g_WrBitBufType = 0;
 | 
						|
}
 | 
						|
 | 
						|
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)
 | 
						|
{
 | 
						|
	char *msgname;
 | 
						|
	int err;
 | 
						|
	if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE)
 | 
						|
	{
 | 
						|
		pCtx->ThrowNativeErrorEx(err, NULL);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	return g_UserMsgs.GetMessageIndex(msgname);
 | 
						|
}
 | 
						|
 | 
						|
static cell_t smn_GetUserMessageName(IPluginContext *pCtx, const cell_t *params)
 | 
						|
{
 | 
						|
	char *msgname;
 | 
						|
 | 
						|
	pCtx->LocalToPhysAddr(params[2], (cell_t **)&msgname);
 | 
						|
 | 
						|
	if (!g_UserMsgs.GetMessageName(params[1], msgname, params[3]))
 | 
						|
	{
 | 
						|
		msgname = "";
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
 | 
						|
{
 | 
						|
	char *msgname;
 | 
						|
	cell_t *cl_array;
 | 
						|
	int msgid, err;
 | 
						|
	bf_write *pBitBuf;
 | 
						|
 | 
						|
	if (g_IsMsgInExec)
 | 
						|
	{
 | 
						|
		return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
 | 
						|
	}
 | 
						|
 | 
						|
	if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE)
 | 
						|
	{
 | 
						|
		pCtx->ThrowNativeErrorEx(err, NULL);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((msgid=g_UserMsgs.GetMessageIndex(msgname)) == INVALID_MESSAGE_ID)
 | 
						|
	{
 | 
						|
		return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname);
 | 
						|
	}
 | 
						|
 | 
						|
	pCtx->LocalToPhysAddr(params[2], &cl_array);
 | 
						|
 | 
						|
	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;
 | 
						|
 | 
						|
	return g_CurMsgHandle;
 | 
						|
}
 | 
						|
 | 
						|
static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params)
 | 
						|
{
 | 
						|
	cell_t *cl_array;
 | 
						|
	bf_write *pBitBuf;
 | 
						|
	int msgid = params[1];
 | 
						|
 | 
						|
	if (g_IsMsgInExec)
 | 
						|
	{
 | 
						|
		return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
 | 
						|
	}
 | 
						|
 | 
						|
	if (msgid < 0 || msgid >= 255)
 | 
						|
	{
 | 
						|
		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
 | 
						|
	}
 | 
						|
 | 
						|
	pCtx->LocalToPhysAddr(params[2], &cl_array);
 | 
						|
 | 
						|
	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;
 | 
						|
 | 
						|
	return g_CurMsgHandle;
 | 
						|
}
 | 
						|
 | 
						|
static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params)
 | 
						|
{
 | 
						|
	HandleSecurity sec;
 | 
						|
 | 
						|
	if (!g_IsMsgInExec)
 | 
						|
	{
 | 
						|
		return pCtx->ThrowNativeError("Unable to end message, no message is in progress");
 | 
						|
	}
 | 
						|
 | 
						|
	g_UserMsgs.EndMessage();
 | 
						|
 | 
						|
	sec.pOwner = pCtx->GetIdentity();
 | 
						|
	sec.pIdentity = g_pCoreIdent;
 | 
						|
	g_HandleSys.FreeHandle(g_CurMsgHandle, &sec);
 | 
						|
 | 
						|
	g_IsMsgInExec = false;
 | 
						|
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
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)
 | 
						|
{
 | 
						|
	{"GetUserMessageId",			smn_GetUserMessageId},
 | 
						|
	{"GetUserMessageName",			smn_GetUserMessageName},
 | 
						|
	{"StartMessage",				smn_StartMessage},
 | 
						|
	{"StartMessageEx",				smn_StartMessageEx},
 | 
						|
	{"EndMessage",					smn_EndMessage},
 | 
						|
	{"HookUserMessage",				smn_HookUserMessage},
 | 
						|
	{"UnHookUserMessage",			smn_UnHookUserMessage},
 | 
						|
	{NULL,							NULL}
 | 
						|
};
 |