core/smn_usermsgs.cpp
changeset 552 e58968c96860
parent 505 9fb8a1ccd4ec
child 553 a8efe0286237
     1.1 --- a/core/smn_usermsgs.cpp	Thu Mar 01 16:35:06 2007 +0000
     1.2 +++ b/core/smn_usermsgs.cpp	Thu Mar 01 22:49:08 2007 +0000
     1.3 @@ -13,39 +13,147 @@
     1.4  */
     1.5  
     1.6  #include "HandleSys.h"
     1.7 -#include "CellRecipientFilter.h"
     1.8 -#include "CMsgIdPool.h"
     1.9 +#include "PluginSys.h"
    1.10 +#include "CUserMessages.h"
    1.11 +#include "CMsgListenerWrapper.h"
    1.12  
    1.13 -#define USERMSG_PASSTHRU			(1<<0)
    1.14 -#define USERMSG_PASSTHRU_ALL		(1<<1)
    1.15 -#define USERMSG_RELIABLE			(1<<2)
    1.16 -#define USERMSG_INITMSG				(1<<3)
    1.17 -
    1.18 -CMessageIdPool g_MessageIds;
    1.19 -CellRecipientFilter g_MsgRecFilter;
    1.20  HandleType_t g_WrBitBufType;
    1.21  Handle_t g_CurMsgHandle;
    1.22 +int g_MsgPlayers[256];
    1.23  bool g_IsMsgInExec = false;
    1.24 -int g_CurMsgFlags = 0;
    1.25  
    1.26  class UsrMessageNatives :
    1.27  	public SMGlobalClass,
    1.28 -	public IHandleTypeDispatch
    1.29 +	public IHandleTypeDispatch,
    1.30 +	public IPluginsListener
    1.31  {
    1.32 +public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener
    1.33 +	void OnSourceModAllInitialized();
    1.34 +	void OnSourceModShutdown();
    1.35 +	void OnHandleDestroy(HandleType_t type, void *object);
    1.36 +	void OnPluginUnloaded(IPlugin *plugin);
    1.37  public:
    1.38 -	void OnSourceModAllInitialized()
    1.39 +	MsgListenerWrapper *GetNewListener(IPluginContext *pCtx);
    1.40 +	MsgListenerWrapper *FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept);
    1.41 +	bool RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept);
    1.42 +private:
    1.43 +	CStack<MsgListenerWrapper *> m_FreeListeners;
    1.44 +};
    1.45 +
    1.46 +void UsrMessageNatives::OnSourceModAllInitialized()
    1.47 +{
    1.48 +	g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    1.49 +	g_PluginSys.AddPluginsListener(this);
    1.50 +}
    1.51 +
    1.52 +void UsrMessageNatives::OnSourceModShutdown()
    1.53 +{
    1.54 +	g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
    1.55 +	g_PluginSys.RemovePluginsListener(this);
    1.56 +	g_WrBitBufType = 0;
    1.57 +}
    1.58 +void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object)
    1.59 +{
    1.60 +}
    1.61 +
    1.62 +void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin)
    1.63 +{
    1.64 +	List<MsgListenerWrapper *> *wrapper_list;
    1.65 +
    1.66 +	if (plugin->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list), true))
    1.67  	{
    1.68 -		g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    1.69 +		List<MsgListenerWrapper *>::iterator iter;
    1.70 +		MsgListenerWrapper *listener;
    1.71 +
    1.72 +		for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
    1.73 +		{
    1.74 +			listener = (*iter);
    1.75 +			if (g_UserMsgs.UnhookUserMessage(listener->GetMessageId(), listener, listener->IsInterceptHook()))
    1.76 +			{
    1.77 +				m_FreeListeners.push(listener);
    1.78 +			}
    1.79 +		}
    1.80 +
    1.81 +		delete wrapper_list;
    1.82 +	}
    1.83 +}
    1.84 +
    1.85 +MsgListenerWrapper *UsrMessageNatives::GetNewListener(IPluginContext *pCtx)
    1.86 +{
    1.87 +	MsgListenerWrapper *listener_wrapper;
    1.88 +
    1.89 +	if (m_FreeListeners.empty())
    1.90 +	{
    1.91 +		listener_wrapper = new MsgListenerWrapper;
    1.92 +	} else {
    1.93 +		listener_wrapper = m_FreeListeners.front();
    1.94 +		m_FreeListeners.pop();
    1.95  	}
    1.96 -	void OnSourceModShutdown()
    1.97 +
    1.98 +	List<MsgListenerWrapper *> *wrapper_list;
    1.99 +	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
   1.100 +
   1.101 +	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
   1.102  	{
   1.103 -		g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
   1.104 -		g_WrBitBufType = 0;
   1.105 +		wrapper_list = new List<MsgListenerWrapper *>;
   1.106 +		pl->SetProperty("MsgListeners", wrapper_list);
   1.107 +	}
   1.108 +
   1.109 +	wrapper_list->push_back(listener_wrapper);
   1.110 +
   1.111 +	return listener_wrapper;
   1.112 +}
   1.113 +
   1.114 +MsgListenerWrapper *UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept)
   1.115 +{
   1.116 +	MsgListenerWrapper *listener;
   1.117 +	List<MsgListenerWrapper *> *wrapper_list;
   1.118 +	List<MsgListenerWrapper *>::iterator iter;
   1.119 +	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
   1.120 +	bool found = false;
   1.121 +
   1.122 +	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
   1.123 +	{
   1.124 +		return NULL;
   1.125  	}
   1.126 -	void OnHandleDestroy(HandleType_t type, void *object)
   1.127 +
   1.128 +	for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
   1.129  	{
   1.130 +		listener = (*iter);
   1.131 +		if ((msgid == listener->GetMessageId()) 
   1.132 +			&& (intercept == listener->IsInterceptHook()) 
   1.133 +			&& (pHook == listener->GetHookedFunction()))
   1.134 +		{
   1.135 +			found = true;
   1.136 +			break;
   1.137 +		}
   1.138  	}
   1.139 -};
   1.140 +
   1.141 +	return (found) ? listener : NULL;
   1.142 +}
   1.143 +bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept)
   1.144 +{
   1.145 +	List<MsgListenerWrapper *> *wrapper_list;
   1.146 +	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
   1.147 +
   1.148 +	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
   1.149 +	{
   1.150 +		return false;
   1.151 +	}
   1.152 +
   1.153 +	wrapper_list->remove(listener);
   1.154 +	m_FreeListeners.push(listener);
   1.155 +
   1.156 +	return true;
   1.157 +}
   1.158 +
   1.159 +/**************************************
   1.160 +*                                     *
   1.161 +* USER MESSAGE NATIVE IMPLEMENTATIONS *
   1.162 +*                                     *
   1.163 +***************************************/
   1.164 +
   1.165 +static UsrMessageNatives s_UsrMessageNatives;
   1.166  
   1.167  static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
   1.168  {
   1.169 @@ -57,7 +165,7 @@
   1.170  		return 0;
   1.171  	}
   1.172  
   1.173 -	return g_MessageIds.GetMessageId(msgname);
   1.174 +	return g_UserMsgs.GetMessageIndex(msgname);
   1.175  }
   1.176  
   1.177  static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
   1.178 @@ -78,30 +186,14 @@
   1.179  		return 0;
   1.180  	}
   1.181  
   1.182 -	if ((msgid=g_MessageIds.GetMessageId(msgname)) == INVALID_MESSAGE_ID)
   1.183 +	if ((msgid=g_UserMsgs.GetMessageIndex(msgname)) == INVALID_MESSAGE_ID)
   1.184  	{
   1.185  		return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname);
   1.186  	}
   1.187  
   1.188  	pCtx->LocalToPhysAddr(params[2], &cl_array);
   1.189 -	g_CurMsgFlags = params[4];
   1.190  
   1.191 -	g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]);
   1.192 -	if (g_CurMsgFlags & USERMSG_INITMSG)
   1.193 -	{
   1.194 -		g_MsgRecFilter.SetInitMessage(true);
   1.195 -	}
   1.196 -	if (g_CurMsgFlags & USERMSG_RELIABLE)
   1.197 -	{
   1.198 -		g_MsgRecFilter.SetReliable(true);
   1.199 -	}
   1.200 -
   1.201 -	if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) //:TODO: change this when we can hook messages
   1.202 -	{
   1.203 -		pBitBuf = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
   1.204 -	} else {
   1.205 -		pBitBuf = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
   1.206 -	}
   1.207 +	pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
   1.208  
   1.209  	g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   1.210  	g_IsMsgInExec = true;
   1.211 @@ -120,30 +212,14 @@
   1.212  		return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
   1.213  	}
   1.214  
   1.215 -	if (msgid < 0 || msgid > 255)
   1.216 +	if (msgid < 0 || msgid >= 255)
   1.217  	{
   1.218  		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
   1.219  	}
   1.220  
   1.221  	pCtx->LocalToPhysAddr(params[2], &cl_array);
   1.222 -	g_CurMsgFlags = params[4];
   1.223  
   1.224 -	g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]);
   1.225 -	if (g_CurMsgFlags & USERMSG_INITMSG)
   1.226 -	{
   1.227 -		g_MsgRecFilter.SetInitMessage(true);
   1.228 -	}
   1.229 -	if (g_CurMsgFlags & USERMSG_RELIABLE)
   1.230 -	{
   1.231 -		g_MsgRecFilter.SetReliable(true);
   1.232 -	}
   1.233 -
   1.234 -	if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) //:TODO: change this when we can hook messages
   1.235 -	{
   1.236 -		pBitBuf = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
   1.237 -	} else {
   1.238 -		pBitBuf = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
   1.239 -	}
   1.240 +	pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
   1.241  
   1.242  	g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   1.243  	g_IsMsgInExec = true;
   1.244 @@ -160,25 +236,78 @@
   1.245  		return pCtx->ThrowNativeError("Unable to end message, no message is in progress");
   1.246  	}
   1.247  
   1.248 -	if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
   1.249 -	{
   1.250 -		engine->MessageEnd();
   1.251 -	} else {
   1.252 -		ENGINE_CALL(MessageEnd)();
   1.253 -	}
   1.254 +	g_UserMsgs.EndMessage();
   1.255  
   1.256  	sec.pOwner = pCtx->GetIdentity();
   1.257  	sec.pIdentity = g_pCoreIdent;
   1.258  	g_HandleSys.FreeHandle(g_CurMsgHandle, &sec);
   1.259  
   1.260  	g_IsMsgInExec = false;
   1.261 -	g_CurMsgFlags = 0;
   1.262 -	g_MsgRecFilter.ResetFilter();
   1.263 +
   1.264 +	return 1;
   1.265 +}
   1.266 +
   1.267 +static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
   1.268 +{
   1.269 +	IPluginFunction *pHook, *pNotify;
   1.270 +	MsgListenerWrapper *listener;
   1.271 +	bool intercept;
   1.272 +	int msgid = params[1];
   1.273 +
   1.274 +	if (msgid < 0 || msgid >= 255)
   1.275 +	{
   1.276 +		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
   1.277 +	}
   1.278 +
   1.279 +	pHook = pCtx->GetFunctionById(params[2]);
   1.280 +	if (!pHook)
   1.281 +	{
   1.282 +		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   1.283 +	}
   1.284 +	pNotify = pCtx->GetFunctionById(params[4]);
   1.285 +
   1.286 +	intercept = (params[3]) ? true : false;
   1.287 +	listener = s_UsrMessageNatives.GetNewListener(pCtx);
   1.288 +	listener->InitListener(msgid, pHook, pNotify, intercept);
   1.289 +	g_UserMsgs.HookUserMessage(msgid, listener, intercept);
   1.290  
   1.291  	return 1;
   1.292  }
   1.293  
   1.294 -static UsrMessageNatives s_UsrMessageNatives;
   1.295 +static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params)
   1.296 +{
   1.297 +	IPluginFunction *pFunc;
   1.298 +	MsgListenerWrapper *listener;
   1.299 +	bool intercept;
   1.300 +	int msgid = params[1];
   1.301 +
   1.302 +	if (msgid < 0 || msgid >= 255)
   1.303 +	{
   1.304 +		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
   1.305 +	}
   1.306 +
   1.307 +	pFunc = pCtx->GetFunctionById(params[2]);
   1.308 +	if (!pFunc)
   1.309 +	{
   1.310 +		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   1.311 +	}
   1.312 +
   1.313 +	intercept = (params[3]) ? true : false;
   1.314 +	listener = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept);
   1.315 +	if (!listener)
   1.316 +	{
   1.317 +		return pCtx->ThrowNativeError("Unable to unhook the current user message");
   1.318 +	}
   1.319 +
   1.320 +	if (!g_UserMsgs.UnhookUserMessage(msgid, listener, intercept))
   1.321 +	{
   1.322 +		return pCtx->ThrowNativeError("Unable to unhook the current user message");
   1.323 +	}
   1.324 +
   1.325 +	s_UsrMessageNatives.RemoveListener(pCtx, listener, intercept);
   1.326 +
   1.327 +	return 1;
   1.328 +}
   1.329  
   1.330  REGISTER_NATIVES(usrmsgnatives)
   1.331  {
   1.332 @@ -186,5 +315,7 @@
   1.333  	{"StartMessage",				smn_StartMessage},
   1.334  	{"StartMessageEx",				smn_StartMessageEx},
   1.335  	{"EndMessage",					smn_EndMessage},
   1.336 +	{"HookUserMessage",				smn_HookUserMessage},
   1.337 +	{"UnHookUserMessage",			smn_UnHookUserMessage},
   1.338  	{NULL,							NULL}
   1.339  };