Moved smn_functions to logic binary.
3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
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.
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
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/>.
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>.
32 #include "HandleSys.h"
33 #include "PluginSys.h"
34 #include "UserMessages.h"
35 #include "PlayerManager.h"
36 #include "smn_usermsgs.h"
38 HandleType_t g_WrBitBufType;
39 HandleType_t g_RdBitBufType;
40 Handle_t g_CurMsgHandle;
41 Handle_t g_ReadBufHandle;
44 int g_MsgPlayers[256];
45 bool g_IsMsgInExec = false;
47 typedef List<MsgListenerWrapper *> MsgWrapperList;
48 typedef List<MsgListenerWrapper *>::iterator MsgWrapperIter;
50 class UsrMessageNatives :
52 public IHandleTypeDispatch,
53 public IPluginsListener
57 public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener
58 void OnSourceModAllInitialized();
59 void OnSourceModShutdown();
60 void OnHandleDestroy(HandleType_t type, void *object);
61 bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
62 void OnPluginUnloaded(IPlugin *plugin);
64 MsgListenerWrapper *CreateListener(IPluginContext *pCtx);
65 bool FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept, MsgWrapperIter *iter);
66 bool DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter);
68 CStack<MsgListenerWrapper *> m_FreeListeners;
71 UsrMessageNatives::~UsrMessageNatives()
73 CStack<MsgListenerWrapper *>::iterator iter;
74 for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++)
78 m_FreeListeners.popall();
81 void UsrMessageNatives::OnSourceModAllInitialized()
85 g_HandleSys.InitAccessDefaults(NULL, &sec);
86 sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY;
88 g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL);
89 g_RdBitBufType = g_HandleSys.CreateType("BitBufReader", this, 0, NULL, &sec, g_pCoreIdent, NULL);
91 g_ReadBufHandle = g_HandleSys.CreateHandle(g_RdBitBufType, &g_ReadBitBuf, NULL, g_pCoreIdent, NULL);
93 g_PluginSys.AddPluginsListener(this);
96 void UsrMessageNatives::OnSourceModShutdown()
99 sec.pIdentity = g_pCoreIdent;
101 g_HandleSys.FreeHandle(g_ReadBufHandle, &sec);
103 g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
104 g_HandleSys.RemoveType(g_RdBitBufType, g_pCoreIdent);
110 void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object)
114 bool UsrMessageNatives::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
116 *pSize = sizeof(bf_read);
121 void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin)
123 MsgWrapperList *pList;
125 if (plugin->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList), true))
128 MsgListenerWrapper *pListener;
130 for (iter=pList->begin(); iter!=pList->end(); iter++)
133 if (g_UserMsgs.UnhookUserMessage(pListener->GetMessageId(), pListener, pListener->IsInterceptHook()))
135 m_FreeListeners.push(pListener);
143 MsgListenerWrapper *UsrMessageNatives::CreateListener(IPluginContext *pCtx)
145 MsgWrapperList *pList;
146 MsgListenerWrapper *pListener;
147 IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
149 if (m_FreeListeners.empty())
151 pListener = new MsgListenerWrapper;
153 pListener = m_FreeListeners.front();
154 m_FreeListeners.pop();
157 if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
159 pList = new List<MsgListenerWrapper *>;
160 pl->SetProperty("MsgListeners", pList);
163 pList->push_back(pListener);
168 bool UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept, MsgWrapperIter *iter)
170 MsgWrapperList *pList;
171 MsgWrapperIter _iter;
172 MsgListenerWrapper *pListener;
173 IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
175 if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
180 for (_iter=pList->begin(); _iter!=pList->end(); _iter++)
182 pListener = (*_iter);
183 if ((msgid == pListener->GetMessageId())
184 && (intercept == pListener->IsInterceptHook())
185 && (pHook == pListener->GetHookedFunction()))
195 bool UsrMessageNatives::DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter)
197 MsgWrapperList *pList;
198 MsgListenerWrapper *pListener;
199 IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
201 if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
208 m_FreeListeners.push(pListener);
213 /***************************************
215 * USER MESSAGE WRAPPER IMPLEMENTATION *
217 ***************************************/
219 void MsgListenerWrapper::Initialize(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept)
238 m_IsInterceptHook = intercept;
241 size_t MsgListenerWrapper::_FillInPlayers(int *pl_array, IRecipientFilter *pFilter)
243 size_t size = static_cast<size_t>(pFilter->GetRecipientCount());
245 for (size_t i=0; i<size; i++)
247 pl_array[i] = pFilter->GetRecipientIndex(i);
253 bool MsgListenerWrapper::IsInterceptHook() const
255 return m_IsInterceptHook;
258 int MsgListenerWrapper::GetMessageId() const
263 IPluginFunction *MsgListenerWrapper::GetHookedFunction() const
273 IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const
278 void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
281 size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
283 g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten());
285 m_Hook->PushCell(msg_id);
286 m_Hook->PushCell(g_ReadBufHandle);
287 m_Hook->PushArray(g_MsgPlayers, size);
288 m_Hook->PushCell(size);
289 m_Hook->PushCell(pFilter->IsReliable());
290 m_Hook->PushCell(pFilter->IsInitMessage());
291 m_Hook->Execute(&res);
294 ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
296 cell_t res = static_cast<cell_t>(Pl_Continue);
297 size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
299 g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten());
301 m_Intercept->PushCell(msg_id);
302 m_Intercept->PushCell(g_ReadBufHandle);
303 m_Intercept->PushArray(g_MsgPlayers, size);
304 m_Intercept->PushCell(size);
305 m_Intercept->PushCell(pFilter->IsReliable());
306 m_Intercept->PushCell(pFilter->IsInitMessage());
307 m_Intercept->Execute(&res);
309 return static_cast<ResultType>(res);
312 void MsgListenerWrapper::OnPostUserMessage(int msg_id, bool sent)
320 m_Notify->PushCell(msg_id);
321 m_Notify->PushCell(sent ? 1 : 0);
322 m_Notify->Execute(&res);
325 /***************************************
327 * USER MESSAGE NATIVE IMPLEMENTATIONS *
329 ***************************************/
331 static UsrMessageNatives s_UsrMessageNatives;
333 static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
336 pCtx->LocalToString(params[1], &msgname);
338 return g_UserMsgs.GetMessageIndex(msgname);
341 static cell_t smn_GetUserMessageName(IPluginContext *pCtx, const cell_t *params)
345 pCtx->LocalToPhysAddr(params[2], (cell_t **)&msgname);
347 return g_UserMsgs.GetMessageName(params[1], msgname, params[3]);
350 static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
354 unsigned int numClients;
358 CPlayer *pPlayer = NULL;
362 return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
365 pCtx->LocalToString(params[1], &msgname);
367 if ((msgid=g_UserMsgs.GetMessageIndex(msgname)) == INVALID_MESSAGE_ID)
369 return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname);
372 pCtx->LocalToPhysAddr(params[2], &cl_array);
374 numClients = params[3];
376 /* Client validation */
377 for (unsigned int i = 0; i < numClients; i++)
379 client = cl_array[i];
380 pPlayer = g_Players.GetPlayerByIndex(client);
384 return pCtx->ThrowNativeError("Client index %d is invalid", client);
385 } else if (!pPlayer->IsConnected()) {
386 return pCtx->ThrowNativeError("Client %d is not connected", client);
390 pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, numClients, params[4]);
393 return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
396 g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
397 g_IsMsgInExec = true;
399 return g_CurMsgHandle;
402 static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params)
405 unsigned int numClients;
408 CPlayer *pPlayer = NULL;
409 int msgid = params[1];
413 return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
416 if (msgid < 0 || msgid >= 255)
418 return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
421 pCtx->LocalToPhysAddr(params[2], &cl_array);
423 numClients = params[3];
425 /* Client validation */
426 for (unsigned int i = 0; i < numClients; i++)
428 client = cl_array[i];
429 pPlayer = g_Players.GetPlayerByIndex(client);
433 return pCtx->ThrowNativeError("Client index %d is invalid", client);
434 } else if (!pPlayer->IsConnected()) {
435 return pCtx->ThrowNativeError("Client %d is not connected", client);
439 pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, numClients, params[4]);
442 return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
445 g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
446 g_IsMsgInExec = true;
448 return g_CurMsgHandle;
451 static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params)
457 return pCtx->ThrowNativeError("Unable to end message, no message is in progress");
460 g_UserMsgs.EndMessage();
462 sec.pOwner = pCtx->GetIdentity();
463 sec.pIdentity = g_pCoreIdent;
464 g_HandleSys.FreeHandle(g_CurMsgHandle, &sec);
466 g_IsMsgInExec = false;
471 static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
473 IPluginFunction *pHook, *pNotify;
474 MsgListenerWrapper *pListener;
476 int msgid = params[1];
478 if (msgid < 0 || msgid >= 255)
480 return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
483 pHook = pCtx->GetFunctionById(params[2]);
486 return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
488 pNotify = pCtx->GetFunctionById(params[4]);
489 intercept = (params[3]) ? true : false;
491 pListener = s_UsrMessageNatives.CreateListener(pCtx);
492 pListener->Initialize(msgid, pHook, pNotify, intercept);
494 g_UserMsgs.HookUserMessage2(msgid, pListener, intercept);
499 static cell_t smn_UnhookUserMessage(IPluginContext *pCtx, const cell_t *params)
501 IPluginFunction *pFunc;
502 MsgListenerWrapper *pListener;
505 int msgid = params[1];
507 if (msgid < 0 || msgid >= 255)
509 return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
512 pFunc = pCtx->GetFunctionById(params[2]);
515 return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
517 intercept = (params[3]) ? true : false;
519 if (!s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept, &iter))
521 return pCtx->ThrowNativeError("Unable to unhook the current user message");
525 if (!g_UserMsgs.UnhookUserMessage2(msgid, pListener, intercept))
527 return pCtx->ThrowNativeError("Unable to unhook the current user message");
530 s_UsrMessageNatives.DeleteListener(pCtx, iter);
535 REGISTER_NATIVES(usrmsgnatives)
537 {"GetUserMessageId", smn_GetUserMessageId},
538 {"GetUserMessageName", smn_GetUserMessageName},
539 {"StartMessage", smn_StartMessage},
540 {"StartMessageEx", smn_StartMessageEx},
541 {"EndMessage", smn_EndMessage},
542 {"HookUserMessage", smn_HookUserMessage},
543 {"UnhookUserMessage", smn_UnhookUserMessage},