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