core/smn_usermsgs.cpp
author Borja Ferrer <faluco@alliedmods.net>
Thu Mar 01 23:44:27 2007 +0000 (2007-03-01)
changeset 553 a8efe0286237
parent 552 e58968c96860
child 590 cb5add383a86
permissions -rw-r--r--
implemented GetUserMessageName native
     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 "CUserMessages.h"
    18 #include "CMsgListenerWrapper.h"
    19 
    20 HandleType_t g_WrBitBufType;
    21 Handle_t g_CurMsgHandle;
    22 int g_MsgPlayers[256];
    23 bool g_IsMsgInExec = false;
    24 
    25 class UsrMessageNatives :
    26 	public SMGlobalClass,
    27 	public IHandleTypeDispatch,
    28 	public IPluginsListener
    29 {
    30 public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener
    31 	void OnSourceModAllInitialized();
    32 	void OnSourceModShutdown();
    33 	void OnHandleDestroy(HandleType_t type, void *object);
    34 	void OnPluginUnloaded(IPlugin *plugin);
    35 public:
    36 	MsgListenerWrapper *GetNewListener(IPluginContext *pCtx);
    37 	MsgListenerWrapper *FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept);
    38 	bool RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept);
    39 private:
    40 	CStack<MsgListenerWrapper *> m_FreeListeners;
    41 };
    42 
    43 void UsrMessageNatives::OnSourceModAllInitialized()
    44 {
    45 	g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    46 	g_PluginSys.AddPluginsListener(this);
    47 }
    48 
    49 void UsrMessageNatives::OnSourceModShutdown()
    50 {
    51 	g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
    52 	g_PluginSys.RemovePluginsListener(this);
    53 	g_WrBitBufType = 0;
    54 }
    55 
    56 void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object)
    57 {
    58 }
    59 
    60 void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin)
    61 {
    62 	List<MsgListenerWrapper *> *wrapper_list;
    63 
    64 	if (plugin->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list), true))
    65 	{
    66 		List<MsgListenerWrapper *>::iterator iter;
    67 		MsgListenerWrapper *listener;
    68 
    69 		for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
    70 		{
    71 			listener = (*iter);
    72 			if (g_UserMsgs.UnhookUserMessage(listener->GetMessageId(), listener, listener->IsInterceptHook()))
    73 			{
    74 				m_FreeListeners.push(listener);
    75 			}
    76 		}
    77 
    78 		delete wrapper_list;
    79 	}
    80 }
    81 
    82 MsgListenerWrapper *UsrMessageNatives::GetNewListener(IPluginContext *pCtx)
    83 {
    84 	MsgListenerWrapper *listener_wrapper;
    85 
    86 	if (m_FreeListeners.empty())
    87 	{
    88 		listener_wrapper = new MsgListenerWrapper;
    89 	} else {
    90 		listener_wrapper = m_FreeListeners.front();
    91 		m_FreeListeners.pop();
    92 	}
    93 
    94 	List<MsgListenerWrapper *> *wrapper_list;
    95 	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
    96 
    97 	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
    98 	{
    99 		wrapper_list = new List<MsgListenerWrapper *>;
   100 		pl->SetProperty("MsgListeners", wrapper_list);
   101 	}
   102 
   103 	wrapper_list->push_back(listener_wrapper);
   104 
   105 	return listener_wrapper;
   106 }
   107 
   108 MsgListenerWrapper *UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept)
   109 {
   110 	MsgListenerWrapper *listener;
   111 	List<MsgListenerWrapper *> *wrapper_list;
   112 	List<MsgListenerWrapper *>::iterator iter;
   113 	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
   114 	bool found = false;
   115 
   116 	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
   117 	{
   118 		return NULL;
   119 	}
   120 
   121 	for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
   122 	{
   123 		listener = (*iter);
   124 		if ((msgid == listener->GetMessageId()) 
   125 			&& (intercept == listener->IsInterceptHook()) 
   126 			&& (pHook == listener->GetHookedFunction()))
   127 		{
   128 			found = true;
   129 			break;
   130 		}
   131 	}
   132 
   133 	return (found) ? listener : NULL;
   134 }
   135 
   136 bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept)
   137 {
   138 	List<MsgListenerWrapper *> *wrapper_list;
   139 	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
   140 
   141 	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
   142 	{
   143 		return false;
   144 	}
   145 
   146 	wrapper_list->remove(listener);
   147 	m_FreeListeners.push(listener);
   148 
   149 	return true;
   150 }
   151 
   152 /**************************************
   153 *                                     *
   154 * USER MESSAGE NATIVE IMPLEMENTATIONS *
   155 *                                     *
   156 ***************************************/
   157 
   158 static UsrMessageNatives s_UsrMessageNatives;
   159 
   160 static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
   161 {
   162 	char *msgname;
   163 	int err;
   164 	if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE)
   165 	{
   166 		pCtx->ThrowNativeErrorEx(err, NULL);
   167 		return 0;
   168 	}
   169 
   170 	return g_UserMsgs.GetMessageIndex(msgname);
   171 }
   172 
   173 static cell_t smn_GetUserMessageName(IPluginContext *pCtx, const cell_t *params)
   174 {
   175 	char *msgname;
   176 
   177 	pCtx->LocalToPhysAddr(params[2], (cell_t **)&msgname);
   178 
   179 	if (!g_UserMsgs.GetMessageName(params[1], msgname, params[3]))
   180 	{
   181 		msgname = "";
   182 		return 0;
   183 	}
   184 
   185 	return 1;
   186 }
   187 
   188 static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
   189 {
   190 	char *msgname;
   191 	cell_t *cl_array;
   192 	int msgid, err;
   193 	bf_write *pBitBuf;
   194 
   195 	if (g_IsMsgInExec)
   196 	{
   197 		return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
   198 	}
   199 
   200 	if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE)
   201 	{
   202 		pCtx->ThrowNativeErrorEx(err, NULL);
   203 		return 0;
   204 	}
   205 
   206 	if ((msgid=g_UserMsgs.GetMessageIndex(msgname)) == INVALID_MESSAGE_ID)
   207 	{
   208 		return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname);
   209 	}
   210 
   211 	pCtx->LocalToPhysAddr(params[2], &cl_array);
   212 
   213 	pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
   214 
   215 	g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   216 	g_IsMsgInExec = true;
   217 
   218 	return g_CurMsgHandle;
   219 }
   220 
   221 static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params)
   222 {
   223 	cell_t *cl_array;
   224 	bf_write *pBitBuf;
   225 	int msgid = params[1];
   226 
   227 	if (g_IsMsgInExec)
   228 	{
   229 		return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
   230 	}
   231 
   232 	if (msgid < 0 || msgid >= 255)
   233 	{
   234 		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
   235 	}
   236 
   237 	pCtx->LocalToPhysAddr(params[2], &cl_array);
   238 
   239 	pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
   240 
   241 	g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   242 	g_IsMsgInExec = true;
   243 
   244 	return g_CurMsgHandle;
   245 }
   246 
   247 static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params)
   248 {
   249 	HandleSecurity sec;
   250 
   251 	if (!g_IsMsgInExec)
   252 	{
   253 		return pCtx->ThrowNativeError("Unable to end message, no message is in progress");
   254 	}
   255 
   256 	g_UserMsgs.EndMessage();
   257 
   258 	sec.pOwner = pCtx->GetIdentity();
   259 	sec.pIdentity = g_pCoreIdent;
   260 	g_HandleSys.FreeHandle(g_CurMsgHandle, &sec);
   261 
   262 	g_IsMsgInExec = false;
   263 
   264 	return 1;
   265 }
   266 
   267 static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
   268 {
   269 	IPluginFunction *pHook, *pNotify;
   270 	MsgListenerWrapper *listener;
   271 	bool intercept;
   272 	int msgid = params[1];
   273 
   274 	if (msgid < 0 || msgid >= 255)
   275 	{
   276 		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
   277 	}
   278 
   279 	pHook = pCtx->GetFunctionById(params[2]);
   280 	if (!pHook)
   281 	{
   282 		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   283 	}
   284 	pNotify = pCtx->GetFunctionById(params[4]);
   285 
   286 	intercept = (params[3]) ? true : false;
   287 	listener = s_UsrMessageNatives.GetNewListener(pCtx);
   288 	listener->InitListener(msgid, pHook, pNotify, intercept);
   289 
   290 	g_UserMsgs.HookUserMessage(msgid, listener, intercept);
   291 
   292 	return 1;
   293 }
   294 
   295 static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params)
   296 {
   297 	IPluginFunction *pFunc;
   298 	MsgListenerWrapper *listener;
   299 	bool intercept;
   300 	int msgid = params[1];
   301 
   302 	if (msgid < 0 || msgid >= 255)
   303 	{
   304 		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
   305 	}
   306 
   307 	pFunc = pCtx->GetFunctionById(params[2]);
   308 	if (!pFunc)
   309 	{
   310 		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   311 	}
   312 
   313 	intercept = (params[3]) ? true : false;
   314 	listener = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept);
   315 	if (!listener)
   316 	{
   317 		return pCtx->ThrowNativeError("Unable to unhook the current user message");
   318 	}
   319 
   320 	if (!g_UserMsgs.UnhookUserMessage(msgid, listener, intercept))
   321 	{
   322 		return pCtx->ThrowNativeError("Unable to unhook the current user message");
   323 	}
   324 
   325 	s_UsrMessageNatives.RemoveListener(pCtx, listener, intercept);
   326 
   327 	return 1;
   328 }
   329 
   330 REGISTER_NATIVES(usrmsgnatives)
   331 {
   332 	{"GetUserMessageId",			smn_GetUserMessageId},
   333 	{"GetUserMessageName",			smn_GetUserMessageName},
   334 	{"StartMessage",				smn_StartMessage},
   335 	{"StartMessageEx",				smn_StartMessageEx},
   336 	{"EndMessage",					smn_EndMessage},
   337 	{"HookUserMessage",				smn_HookUserMessage},
   338 	{"UnHookUserMessage",			smn_UnHookUserMessage},
   339 	{NULL,							NULL}
   340 };