3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
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
15 #include "HandleSys.h"
16 #include "PluginSys.h"
17 #include "CUserMessages.h"
18 #include "CMsgListenerWrapper.h"
20 HandleType_t g_WrBitBufType;
21 Handle_t g_CurMsgHandle;
22 int g_MsgPlayers[256];
23 bool g_IsMsgInExec = false;
25 class UsrMessageNatives :
27 public IHandleTypeDispatch,
28 public IPluginsListener
30 public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener
31 void OnSourceModAllInitialized();
32 void OnSourceModShutdown();
33 void OnHandleDestroy(HandleType_t type, void *object);
34 void OnPluginUnloaded(IPlugin *plugin);
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);
40 CStack<MsgListenerWrapper *> m_FreeListeners;
43 void UsrMessageNatives::OnSourceModAllInitialized()
45 g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL);
46 g_PluginSys.AddPluginsListener(this);
49 void UsrMessageNatives::OnSourceModShutdown()
51 g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
52 g_PluginSys.RemovePluginsListener(this);
56 void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object)
60 void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin)
62 List<MsgListenerWrapper *> *wrapper_list;
64 if (plugin->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list), true))
66 List<MsgListenerWrapper *>::iterator iter;
67 MsgListenerWrapper *listener;
69 for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
72 if (g_UserMsgs.UnhookUserMessage(listener->GetMessageId(), listener, listener->IsInterceptHook()))
74 m_FreeListeners.push(listener);
82 MsgListenerWrapper *UsrMessageNatives::GetNewListener(IPluginContext *pCtx)
84 MsgListenerWrapper *listener_wrapper;
86 if (m_FreeListeners.empty())
88 listener_wrapper = new MsgListenerWrapper;
90 listener_wrapper = m_FreeListeners.front();
91 m_FreeListeners.pop();
94 List<MsgListenerWrapper *> *wrapper_list;
95 IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
97 if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
99 wrapper_list = new List<MsgListenerWrapper *>;
100 pl->SetProperty("MsgListeners", wrapper_list);
103 wrapper_list->push_back(listener_wrapper);
105 return listener_wrapper;
108 MsgListenerWrapper *UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept)
110 MsgListenerWrapper *listener;
111 List<MsgListenerWrapper *> *wrapper_list;
112 List<MsgListenerWrapper *>::iterator iter;
113 IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
116 if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
121 for (iter=wrapper_list->begin(); iter!=wrapper_list->end(); iter++)
124 if ((msgid == listener->GetMessageId())
125 && (intercept == listener->IsInterceptHook())
126 && (pHook == listener->GetHookedFunction()))
133 return (found) ? listener : NULL;
136 bool UsrMessageNatives::RemoveListener(IPluginContext *pCtx, MsgListenerWrapper *listener, bool intercept)
138 List<MsgListenerWrapper *> *wrapper_list;
139 IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
141 if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&wrapper_list)))
146 wrapper_list->remove(listener);
147 m_FreeListeners.push(listener);
152 /**************************************
154 * USER MESSAGE NATIVE IMPLEMENTATIONS *
156 ***************************************/
158 static UsrMessageNatives s_UsrMessageNatives;
160 static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
164 if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE)
166 pCtx->ThrowNativeErrorEx(err, NULL);
170 return g_UserMsgs.GetMessageIndex(msgname);
173 static cell_t smn_GetUserMessageName(IPluginContext *pCtx, const cell_t *params)
177 pCtx->LocalToPhysAddr(params[2], (cell_t **)&msgname);
179 if (!g_UserMsgs.GetMessageName(params[1], msgname, params[3]))
188 static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
197 return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
200 if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE)
202 pCtx->ThrowNativeErrorEx(err, NULL);
206 if ((msgid=g_UserMsgs.GetMessageIndex(msgname)) == INVALID_MESSAGE_ID)
208 return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname);
211 pCtx->LocalToPhysAddr(params[2], &cl_array);
213 pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
215 g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
216 g_IsMsgInExec = true;
218 return g_CurMsgHandle;
221 static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params)
225 int msgid = params[1];
229 return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
232 if (msgid < 0 || msgid >= 255)
234 return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
237 pCtx->LocalToPhysAddr(params[2], &cl_array);
239 pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, params[3], params[4]);
241 g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
242 g_IsMsgInExec = true;
244 return g_CurMsgHandle;
247 static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params)
253 return pCtx->ThrowNativeError("Unable to end message, no message is in progress");
256 g_UserMsgs.EndMessage();
258 sec.pOwner = pCtx->GetIdentity();
259 sec.pIdentity = g_pCoreIdent;
260 g_HandleSys.FreeHandle(g_CurMsgHandle, &sec);
262 g_IsMsgInExec = false;
267 static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
269 IPluginFunction *pHook, *pNotify;
270 MsgListenerWrapper *listener;
272 int msgid = params[1];
274 if (msgid < 0 || msgid >= 255)
276 return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
279 pHook = pCtx->GetFunctionById(params[2]);
282 return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
284 pNotify = pCtx->GetFunctionById(params[4]);
286 intercept = (params[3]) ? true : false;
287 listener = s_UsrMessageNatives.GetNewListener(pCtx);
288 listener->InitListener(msgid, pHook, pNotify, intercept);
290 g_UserMsgs.HookUserMessage(msgid, listener, intercept);
295 static cell_t smn_UnHookUserMessage(IPluginContext *pCtx, const cell_t *params)
297 IPluginFunction *pFunc;
298 MsgListenerWrapper *listener;
300 int msgid = params[1];
302 if (msgid < 0 || msgid >= 255)
304 return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
307 pFunc = pCtx->GetFunctionById(params[2]);
310 return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
313 intercept = (params[3]) ? true : false;
314 listener = s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept);
317 return pCtx->ThrowNativeError("Unable to unhook the current user message");
320 if (!g_UserMsgs.UnhookUserMessage(msgid, listener, intercept))
322 return pCtx->ThrowNativeError("Unable to unhook the current user message");
325 s_UsrMessageNatives.RemoveListener(pCtx, listener, intercept);
330 REGISTER_NATIVES(usrmsgnatives)
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},