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