core/smn_usermsgs.cpp
author David Anderson <dvander@alliedmods.net>
Thu Mar 15 04:45:33 2007 +0000 (2007-03-15)
changeset 617 dc7671b320e4
parent 600 f6d811158ad3
child 626 ad539443ad7f
permissions -rw-r--r--
fixed two spelling mistakes
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "HandleSys.h"
    16 #include "PluginSys.h"
    17 #include "UserMessages.h"
    18 #include "smn_usermsgs.h"
    19 
    20 HandleType_t g_WrBitBufType;
    21 HandleType_t g_RdBitBufType;
    22 Handle_t g_CurMsgHandle;
    23 Handle_t g_ReadBufHandle;
    24 bf_read g_ReadBitBuf;
    25 
    26 int g_MsgPlayers[256];
    27 bool g_IsMsgInExec = false;
    28 
    29 typedef List<MsgListenerWrapper *> MsgWrapperList;
    30 typedef List<MsgListenerWrapper *>::iterator MsgWrapperIter;
    31 
    32 class UsrMessageNatives :
    33 	public SMGlobalClass,
    34 	public IHandleTypeDispatch,
    35 	public IPluginsListener
    36 {
    37 public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener
    38 	void OnSourceModAllInitialized();
    39 	void OnSourceModShutdown();
    40 	void OnHandleDestroy(HandleType_t type, void *object);
    41 	void OnPluginUnloaded(IPlugin *plugin);
    42 public:
    43 	MsgListenerWrapper *CreateListener(IPluginContext *pCtx);
    44 	MsgWrapperIter FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept);
    45 	bool DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter);
    46 private:
    47 	CStack<MsgListenerWrapper *> m_FreeListeners;
    48 };
    49 
    50 void UsrMessageNatives::OnSourceModAllInitialized()
    51 {
    52 	HandleAccess sec;
    53 	sec.access[HandleAccess_Delete] |= HANDLE_RESTRICT_IDENTITY;
    54 
    55 	g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    56 	g_RdBitBufType = g_HandleSys.CreateType("BitBufReader", this, 0, NULL, &sec, g_pCoreIdent, NULL);
    57 
    58 	g_ReadBufHandle = g_HandleSys.CreateHandle(g_RdBitBufType, &g_ReadBitBuf, NULL, g_pCoreIdent, NULL);
    59 
    60 	g_PluginSys.AddPluginsListener(this);
    61 }
    62 
    63 void UsrMessageNatives::OnSourceModShutdown()
    64 {
    65 	HandleSecurity sec;
    66 	sec.pIdentity = g_pCoreIdent;
    67 
    68 	g_HandleSys.FreeHandle(g_ReadBufHandle, &sec);
    69 
    70 	g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
    71 	g_HandleSys.RemoveType(g_RdBitBufType, g_pCoreIdent);
    72 
    73 	g_PluginSys.RemovePluginsListener(this);
    74 	g_WrBitBufType = 0;
    75 	g_RdBitBufType = 0;
    76 }
    77 
    78 void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object)
    79 {
    80 }
    81 
    82 void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin)
    83 {
    84 	MsgWrapperList *pList;
    85 
    86 	if (plugin->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList), true))
    87 	{
    88 		MsgWrapperIter iter;
    89 		MsgListenerWrapper *pListener;
    90 
    91 		for (iter=pList->begin(); iter!=pList->end(); iter++)
    92 		{
    93 			pListener = (*iter);
    94 			if (g_UserMsgs.UnhookUserMessage(pListener->GetMessageId(), pListener, pListener->IsInterceptHook()))
    95 			{
    96 				m_FreeListeners.push(pListener);
    97 			}
    98 		}
    99 
   100 		delete pList;
   101 	}
   102 }
   103 
   104 MsgListenerWrapper *UsrMessageNatives::CreateListener(IPluginContext *pCtx)
   105 {
   106 	MsgWrapperList *pList;
   107 	MsgListenerWrapper *pListener;
   108 	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
   109 
   110 	if (m_FreeListeners.empty())
   111 	{
   112 		pListener = new MsgListenerWrapper;
   113 	} else {
   114 		pListener = m_FreeListeners.front();
   115 		m_FreeListeners.pop();
   116 	}
   117 
   118 	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
   119 	{
   120 		pList = new List<MsgListenerWrapper *>;
   121 		pl->SetProperty("MsgListeners", pList);
   122 	}
   123 
   124 	pList->push_back(pListener);
   125 
   126 	return pListener;
   127 }
   128 
   129 MsgWrapperIter UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept)
   130 {
   131 	MsgWrapperList *pList;
   132 	MsgWrapperIter iter;
   133 	MsgListenerWrapper *pListener;
   134 	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
   135 
   136 	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
   137 	{
   138 		return NULL;
   139 	}
   140 
   141 	for (iter=pList->begin(); iter!=pList->end(); iter++)
   142 	{
   143 		pListener = (*iter);
   144 		if ((msgid == pListener->GetMessageId()) 
   145 			&& (intercept == pListener->IsInterceptHook()) 
   146 			&& (pHook == pListener->GetHookedFunction()))
   147 		{
   148 			return iter;
   149 		}
   150 	}
   151 
   152 	return NULL;
   153 }
   154 
   155 bool UsrMessageNatives::DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter)
   156 {
   157 	MsgWrapperList *pList;
   158 	MsgListenerWrapper *pListener;
   159 	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
   160 
   161 	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
   162 	{
   163 		return false;
   164 	}
   165 
   166 	pListener = (*iter);
   167 	pList->erase(iter);
   168 	m_FreeListeners.push(pListener);
   169 
   170 	return true;
   171 }
   172 
   173 /***************************************
   174  *                                     *
   175  * USER MESSAGE WRAPPER IMPLEMENTATION *
   176  *                                     *
   177  ***************************************/
   178 
   179 void MsgListenerWrapper::Initialize(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept)
   180 {
   181 	if (intercept)
   182 	{
   183 		m_Intercept = hook;
   184 		m_Hook = NULL;
   185 	} else {
   186 		m_Hook = hook;
   187 		m_Intercept = NULL;
   188 	}
   189 
   190 	if (notify)
   191 	{
   192 		m_Notify = notify;
   193 	} else {
   194 		m_Notify = NULL;
   195 	}
   196 
   197 	m_MsgId = msgid;
   198 	m_IsInterceptHook = intercept;
   199 }
   200 
   201 size_t MsgListenerWrapper::_FillInPlayers(int *pl_array, IRecipientFilter *pFilter)
   202 {
   203 	size_t size = static_cast<size_t>(pFilter->GetRecipientCount());
   204 
   205 	for (size_t i=0; i<size; i++)
   206 	{
   207 		pl_array[i] = pFilter->GetRecipientIndex(i);
   208 	}
   209 
   210 	return size;
   211 }
   212 
   213 bool MsgListenerWrapper::IsInterceptHook() const
   214 {
   215 	return m_IsInterceptHook;
   216 }
   217 
   218 int MsgListenerWrapper::GetMessageId() const
   219 {
   220 	return m_MsgId;
   221 }
   222 
   223 IPluginFunction *MsgListenerWrapper::GetHookedFunction() const
   224 {
   225 	if (m_Hook)
   226 	{
   227 		return m_Hook;
   228 	} else {
   229 		return m_Intercept;
   230 	}
   231 }
   232 
   233 IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const
   234 {
   235 	return m_Notify;
   236 }
   237 
   238 void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
   239 {
   240 	cell_t res;
   241 	size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
   242 
   243 	g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten());
   244 
   245 	m_Hook->PushCell(msg_id);
   246 	m_Hook->PushCell(g_ReadBufHandle);
   247 	m_Hook->PushArray(g_MsgPlayers, size);
   248 	m_Hook->PushCell(size);
   249 	m_Hook->PushCell(pFilter->IsReliable());
   250 	m_Hook->PushCell(pFilter->IsInitMessage());
   251 	m_Hook->Execute(&res);
   252 }
   253 
   254 ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
   255 {
   256 	cell_t res = static_cast<cell_t>(Pl_Continue);
   257 	size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
   258 
   259 	g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten());
   260 
   261 	m_Intercept->PushCell(msg_id);
   262 	m_Intercept->PushCell(g_ReadBufHandle);
   263 	m_Intercept->PushArray(g_MsgPlayers, size);
   264 	m_Intercept->PushCell(size);
   265 	m_Intercept->PushCell(pFilter->IsReliable());
   266 	m_Intercept->PushCell(pFilter->IsInitMessage());
   267 	m_Intercept->Execute(&res);
   268 
   269 	return static_cast<ResultType>(res);
   270 }
   271 
   272 void MsgListenerWrapper::OnUserMessageSent(int msg_id)
   273 {
   274 	if (!m_Notify)
   275 	{
   276 		return;
   277 	}
   278 
   279 	cell_t res;
   280 	m_Notify->PushCell(msg_id);
   281 	m_Notify->Execute(&res);
   282 }
   283 
   284 /***************************************
   285  *                                     *
   286  * USER MESSAGE NATIVE IMPLEMENTATIONS *
   287  *                                     *
   288  ***************************************/
   289 
   290 static UsrMessageNatives s_UsrMessageNatives;
   291 
   292 static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
   293 {
   294 	char *msgname;
   295 	int err;
   296 	if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE)
   297 	{
   298 		pCtx->ThrowNativeErrorEx(err, NULL);
   299 		return 0;
   300 	}
   301 
   302 	return g_UserMsgs.GetMessageIndex(msgname);
   303 }
   304 
   305 static cell_t smn_GetUserMessageName(IPluginContext *pCtx, const cell_t *params)
   306 {
   307 	char *msgname;
   308 
   309 	pCtx->LocalToPhysAddr(params[2], (cell_t **)&msgname);
   310 
   311 	if (!g_UserMsgs.GetMessageName(params[1], msgname, params[3]))
   312 	{
   313 		msgname = "";
   314 		return 0;
   315 	}
   316 
   317 	return 1;
   318 }
   319 
   320 static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
   321 {
   322 	char *msgname;
   323 	cell_t *cl_array;
   324 	int msgid, err;
   325 	bf_write *pBitBuf;
   326 
   327 	if (g_IsMsgInExec)
   328 	{
   329 		return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
   330 	}
   331 
   332 	if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE)
   333 	{
   334 		pCtx->ThrowNativeErrorEx(err, NULL);
   335 		return 0;
   336 	}
   337 
   338 	if ((msgid=g_UserMsgs.GetMessageIndex(msgname)) == INVALID_MESSAGE_ID)
   339 	{
   340 		return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname);
   341 	}
   342 
   343 	pCtx->LocalToPhysAddr(params[2], &cl_array);
   344 
   345 	pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
   346 	if (!pBitBuf)
   347 	{
   348 		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
   349 	}
   350 
   351 	g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   352 	g_IsMsgInExec = true;
   353 
   354 	return g_CurMsgHandle;
   355 }
   356 
   357 static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params)
   358 {
   359 	cell_t *cl_array;
   360 	bf_write *pBitBuf;
   361 	int msgid = params[1];
   362 
   363 	if (g_IsMsgInExec)
   364 	{
   365 		return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
   366 	}
   367 
   368 	if (msgid < 0 || msgid >= 255)
   369 	{
   370 		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
   371 	}
   372 
   373 	pCtx->LocalToPhysAddr(params[2], &cl_array);
   374 
   375 	pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
   376 	if (!pBitBuf)
   377 	{
   378 		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
   379 	}
   380 
   381 	g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   382 	g_IsMsgInExec = true;
   383 
   384 	return g_CurMsgHandle;
   385 }
   386 
   387 static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params)
   388 {
   389 	HandleSecurity sec;
   390 
   391 	if (!g_IsMsgInExec)
   392 	{
   393 		return pCtx->ThrowNativeError("Unable to end message, no message is in progress");
   394 	}
   395 
   396 	g_UserMsgs.EndMessage();
   397 
   398 	sec.pOwner = pCtx->GetIdentity();
   399 	sec.pIdentity = g_pCoreIdent;
   400 	g_HandleSys.FreeHandle(g_CurMsgHandle, &sec);
   401 
   402 	g_IsMsgInExec = false;
   403 
   404 	return 1;
   405 }
   406 
   407 static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
   408 {
   409 	IPluginFunction *pHook, *pNotify;
   410 	MsgListenerWrapper *pListener;
   411 	bool intercept;
   412 	int msgid = params[1];
   413 
   414 	if (msgid < 0 || msgid >= 255)
   415 	{
   416 		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
   417 	}
   418 
   419 	pHook = pCtx->GetFunctionById(params[2]);
   420 	if (!pHook)
   421 	{
   422 		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   423 	}
   424 	pNotify = pCtx->GetFunctionById(params[4]);
   425 	intercept = (params[3]) ? true : false;
   426 
   427 	pListener = s_UsrMessageNatives.CreateListener(pCtx);
   428 	pListener->Initialize(msgid, pHook, pNotify, intercept);
   429 
   430 	g_UserMsgs.HookUserMessage(msgid, pListener, intercept);
   431 
   432 	return 1;
   433 }
   434 
   435 static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params)
   436 {
   437 	IPluginFunction *pFunc;
   438 	MsgListenerWrapper *pListener;
   439 	MsgWrapperIter iter;
   440 	bool intercept;
   441 	int msgid = params[1];
   442 
   443 	if (msgid < 0 || msgid >= 255)
   444 	{
   445 		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
   446 	}
   447 
   448 	pFunc = pCtx->GetFunctionById(params[2]);
   449 	if (!pFunc)
   450 	{
   451 		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   452 	}
   453 	intercept = (params[3]) ? true : false;
   454 
   455 	iter = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept);
   456 	if (iter == NULL)
   457 	{
   458 		return pCtx->ThrowNativeError("Unable to unhook the current user message");
   459 	}
   460 
   461 	pListener = (*iter);
   462 	if (!g_UserMsgs.UnhookUserMessage(msgid, pListener, intercept))
   463 	{
   464 		return pCtx->ThrowNativeError("Unable to unhook the current user message");
   465 	}
   466 
   467 	s_UsrMessageNatives.DeleteListener(pCtx, iter);
   468 
   469 	return 1;
   470 }
   471 
   472 REGISTER_NATIVES(usrmsgnatives)
   473 {
   474 	{"GetUserMessageId",			smn_GetUserMessageId},
   475 	{"GetUserMessageName",			smn_GetUserMessageName},
   476 	{"StartMessage",				smn_StartMessage},
   477 	{"StartMessageEx",				smn_StartMessageEx},
   478 	{"EndMessage",					smn_EndMessage},
   479 	{"HookUserMessage",				smn_HookUserMessage},
   480 	{"UnHookUserMessage",			smn_UnHookUserMessage},
   481 	{NULL,							NULL}
   482 };