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 "CellRecipientFilter.h"
17 #include "CMsgIdPool.h"
19 #define USERMSG_PASSTHRU (1<<0)
20 #define USERMSG_PASSTHRU_ALL (1<<1)
21 #define USERMSG_RELIABLE (1<<2)
22 #define USERMSG_INITMSG (1<<3)
24 CMessageIdPool g_MessageIds;
25 CellRecipientFilter g_MsgRecFilter;
26 HandleType_t g_WrBitBufType;
27 Handle_t g_CurMsgHandle;
28 bool g_IsMsgInExec = false;
29 int g_CurMsgFlags = 0;
31 class UsrMessageNatives :
33 public IHandleTypeDispatch
36 void OnSourceModAllInitialized()
38 g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL);
40 void OnSourceModShutdown()
42 g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
45 void OnHandleDestroy(HandleType_t type, void *object)
50 static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
54 if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE)
56 pCtx->ThrowNativeErrorEx(err, NULL);
60 return g_MessageIds.GetMessageId(msgname);
63 static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
72 return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
75 if ((err=pCtx->LocalToString(params[1], &msgname)) != SP_ERROR_NONE)
77 pCtx->ThrowNativeErrorEx(err, NULL);
81 if ((msgid=g_MessageIds.GetMessageId(msgname)) == INVALID_MESSAGE_ID)
83 return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname);
86 pCtx->LocalToPhysAddr(params[2], &cl_array);
87 g_CurMsgFlags = params[4];
89 g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]);
90 if (g_CurMsgFlags & USERMSG_INITMSG)
92 g_MsgRecFilter.SetInitMessage(true);
94 if (g_CurMsgFlags & USERMSG_RELIABLE)
96 g_MsgRecFilter.SetReliable(true);
99 if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) //:TODO: change this when we can hook messages
101 pBitBuf = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
103 pBitBuf = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
106 g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
107 g_IsMsgInExec = true;
109 return g_CurMsgHandle;
112 static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params)
116 int msgid = params[1];
120 return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
123 if (msgid < 0 || msgid > 255)
125 return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
128 pCtx->LocalToPhysAddr(params[2], &cl_array);
129 g_CurMsgFlags = params[4];
131 g_MsgRecFilter.SetRecipientPtr(cl_array, params[3]);
132 if (g_CurMsgFlags & USERMSG_INITMSG)
134 g_MsgRecFilter.SetInitMessage(true);
136 if (g_CurMsgFlags & USERMSG_RELIABLE)
138 g_MsgRecFilter.SetReliable(true);
141 if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU)) //:TODO: change this when we can hook messages
143 pBitBuf = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
145 pBitBuf = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&g_MsgRecFilter), msgid);
148 g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
149 g_IsMsgInExec = true;
151 return g_CurMsgHandle;
154 static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params)
160 return pCtx->ThrowNativeError("Unable to end message, no message is in progress");
163 if (g_CurMsgFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
165 engine->MessageEnd();
167 ENGINE_CALL(MessageEnd)();
170 sec.pOwner = pCtx->GetIdentity();
171 sec.pIdentity = g_pCoreIdent;
172 g_HandleSys.FreeHandle(g_CurMsgHandle, &sec);
174 g_IsMsgInExec = false;
176 g_MsgRecFilter.ResetFilter();
181 static UsrMessageNatives s_UsrMessageNatives;
183 REGISTER_NATIVES(usrmsgnatives)
185 {"GetUserMessageId", smn_GetUserMessageId},
186 {"StartMessage", smn_StartMessage},
187 {"StartMessageEx", smn_StartMessageEx},
188 {"EndMessage", smn_EndMessage},