core/smn_usermsgs.cpp
author David Anderson <dvander@alliedmods.net>
Sat Feb 16 15:52:11 2013 -0800 (2013-02-16)
changeset 3791 47e1ee9cea86
parent 3743 a98686a77974
child 3872 4c93f74cae51
permissions -rw-r--r--
Move filesystem natives from Core to Logic (bug 5606, r=psychonic).
faluco@505
     1
/**
dvander@600
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
ds@1947
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@600
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1231
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1231
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@600
    28
 *
dvander@600
    29
 * Version: $Id$
dvander@600
    30
 */
faluco@505
    31
faluco@505
    32
#include "HandleSys.h"
faluco@552
    33
#include "PluginSys.h"
ds@2112
    34
#include "PlayerManager.h"
dvander@590
    35
#include "smn_usermsgs.h"
skamonkey@3743
    36
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
    37
#include "UserMessagePBHelpers.h"
skamonkey@3743
    38
#endif
faluco@505
    39
skamonkey@3743
    40
HandleType_t g_ProtobufType = NO_HANDLE_TYPE;
skamonkey@3743
    41
HandleType_t g_WrBitBufType = NO_HANDLE_TYPE;
skamonkey@3743
    42
HandleType_t g_RdBitBufType = NO_HANDLE_TYPE;
skamonkey@3743
    43
faluco@505
    44
Handle_t g_CurMsgHandle;
skamonkey@3743
    45
skamonkey@3743
    46
#ifndef USE_PROTOBUF_USERMESSAGES
faluco@598
    47
Handle_t g_ReadBufHandle;
faluco@598
    48
bf_read g_ReadBitBuf;
skamonkey@3743
    49
#endif
faluco@598
    50
faluco@552
    51
int g_MsgPlayers[256];
faluco@505
    52
bool g_IsMsgInExec = false;
faluco@505
    53
faluco@593
    54
typedef List<MsgListenerWrapper *> MsgWrapperList;
faluco@593
    55
typedef List<MsgListenerWrapper *>::iterator MsgWrapperIter;
faluco@593
    56
faluco@505
    57
class UsrMessageNatives :
faluco@505
    58
	public SMGlobalClass,
faluco@552
    59
	public IHandleTypeDispatch,
faluco@552
    60
	public IPluginsListener
faluco@505
    61
{
faluco@641
    62
public:
faluco@641
    63
	~UsrMessageNatives();
faluco@552
    64
public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener
faluco@552
    65
	void OnSourceModAllInitialized();
faluco@552
    66
	void OnSourceModShutdown();
faluco@552
    67
	void OnHandleDestroy(HandleType_t type, void *object);
dvander@1766
    68
	bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
faluco@552
    69
	void OnPluginUnloaded(IPlugin *plugin);
faluco@505
    70
public:
faluco@593
    71
	MsgListenerWrapper *CreateListener(IPluginContext *pCtx);
faluco@1541
    72
	bool FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept, MsgWrapperIter *iter);
faluco@593
    73
	bool DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter);
faluco@552
    74
private:
faluco@552
    75
	CStack<MsgListenerWrapper *> m_FreeListeners;
faluco@552
    76
};
faluco@552
    77
faluco@641
    78
UsrMessageNatives::~UsrMessageNatives()
faluco@641
    79
{
faluco@641
    80
	CStack<MsgListenerWrapper *>::iterator iter;
faluco@641
    81
	for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++)
faluco@641
    82
	{
faluco@641
    83
		delete (*iter);
faluco@641
    84
	}
faluco@641
    85
	m_FreeListeners.popall();
faluco@641
    86
}
faluco@641
    87
faluco@552
    88
void UsrMessageNatives::OnSourceModAllInitialized()
faluco@552
    89
{
faluco@598
    90
	HandleAccess sec;
faluco@1397
    91
faluco@1397
    92
	g_HandleSys.InitAccessDefaults(NULL, &sec);
faluco@1397
    93
	sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY;
faluco@598
    94
skamonkey@3743
    95
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
    96
	g_ProtobufType = g_HandleSys.CreateType("ProtobufUM", this, 0, NULL, NULL, g_pCoreIdent, NULL);
skamonkey@3743
    97
#else
faluco@552
    98
	g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL);
faluco@598
    99
	g_RdBitBufType = g_HandleSys.CreateType("BitBufReader", this, 0, NULL, &sec, g_pCoreIdent, NULL);
faluco@598
   100
faluco@598
   101
	g_ReadBufHandle = g_HandleSys.CreateHandle(g_RdBitBufType, &g_ReadBitBuf, NULL, g_pCoreIdent, NULL);
skamonkey@3743
   102
#endif
faluco@598
   103
faluco@552
   104
	g_PluginSys.AddPluginsListener(this);
faluco@552
   105
}
faluco@552
   106
faluco@552
   107
void UsrMessageNatives::OnSourceModShutdown()
faluco@552
   108
{
faluco@598
   109
	HandleSecurity sec;
faluco@598
   110
	sec.pIdentity = g_pCoreIdent;
faluco@598
   111
skamonkey@3743
   112
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   113
	g_HandleSys.RemoveType(g_ProtobufType, g_pCoreIdent);
skamonkey@3743
   114
skamonkey@3743
   115
	g_ProtobufType = 0;
skamonkey@3743
   116
#else
faluco@598
   117
	g_HandleSys.FreeHandle(g_ReadBufHandle, &sec);
faluco@598
   118
faluco@552
   119
	g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent);
faluco@598
   120
	g_HandleSys.RemoveType(g_RdBitBufType, g_pCoreIdent);
faluco@598
   121
faluco@552
   122
	g_WrBitBufType = 0;
faluco@598
   123
	g_RdBitBufType = 0;
skamonkey@3743
   124
#endif
faluco@552
   125
}
faluco@553
   126
faluco@552
   127
void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object)
faluco@552
   128
{
skamonkey@3743
   129
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   130
	delete (SMProtobufMessage *)object;
skamonkey@3743
   131
#endif
faluco@552
   132
}
faluco@552
   133
dvander@1766
   134
bool UsrMessageNatives::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
dvander@1766
   135
{
skamonkey@3743
   136
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   137
	// Different messages have different sizes, but this works as an approximate
skamonkey@3743
   138
	*pSize = sizeof(protobuf::Message) + sizeof(SMProtobufMessage);
skamonkey@3743
   139
#else
pred@1871
   140
	*pSize = sizeof(bf_read);
skamonkey@3743
   141
#endif
dvander@1766
   142
dvander@1766
   143
	return true;
dvander@1766
   144
}
dvander@1766
   145
faluco@552
   146
void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin)
faluco@552
   147
{
faluco@593
   148
	MsgWrapperList *pList;
faluco@552
   149
faluco@593
   150
	if (plugin->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList), true))
faluco@505
   151
	{
faluco@593
   152
		MsgWrapperIter iter;
faluco@593
   153
		MsgListenerWrapper *pListener;
faluco@552
   154
faluco@593
   155
		for (iter=pList->begin(); iter!=pList->end(); iter++)
faluco@552
   156
		{
faluco@593
   157
			pListener = (*iter);
fyrenmoo@2736
   158
			if (g_UserMsgs.UnhookUserMessage2(pListener->GetMessageId(), pListener, pListener->IsInterceptHook()))
faluco@552
   159
			{
faluco@593
   160
				m_FreeListeners.push(pListener);
faluco@552
   161
			}
faluco@552
   162
		}
faluco@552
   163
faluco@593
   164
		delete pList;
faluco@552
   165
	}
faluco@552
   166
}
faluco@552
   167
faluco@593
   168
MsgListenerWrapper *UsrMessageNatives::CreateListener(IPluginContext *pCtx)
faluco@552
   169
{
faluco@593
   170
	MsgWrapperList *pList;
faluco@593
   171
	MsgListenerWrapper *pListener;
faluco@593
   172
	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
faluco@552
   173
faluco@552
   174
	if (m_FreeListeners.empty())
faluco@552
   175
	{
faluco@593
   176
		pListener = new MsgListenerWrapper;
faluco@552
   177
	} else {
faluco@593
   178
		pListener = m_FreeListeners.front();
faluco@552
   179
		m_FreeListeners.pop();
faluco@505
   180
	}
faluco@552
   181
faluco@593
   182
	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
faluco@505
   183
	{
faluco@593
   184
		pList = new List<MsgListenerWrapper *>;
faluco@593
   185
		pl->SetProperty("MsgListeners", pList);
faluco@552
   186
	}
faluco@552
   187
faluco@593
   188
	pList->push_back(pListener);
faluco@552
   189
faluco@593
   190
	return pListener;
faluco@552
   191
}
faluco@552
   192
faluco@1541
   193
bool UsrMessageNatives::FindListener(int msgid, IPluginContext *pCtx, IPluginFunction *pHook, bool intercept, MsgWrapperIter *iter)
faluco@552
   194
{
faluco@593
   195
	MsgWrapperList *pList;
faluco@1541
   196
	MsgWrapperIter _iter;
faluco@593
   197
	MsgListenerWrapper *pListener;
faluco@552
   198
	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
faluco@552
   199
faluco@593
   200
	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
faluco@552
   201
	{
faluco@1541
   202
		return false;
faluco@505
   203
	}
faluco@552
   204
faluco@1541
   205
	for (_iter=pList->begin(); _iter!=pList->end(); _iter++)
faluco@505
   206
	{
faluco@1541
   207
		pListener = (*_iter);
faluco@593
   208
		if ((msgid == pListener->GetMessageId()) 
faluco@593
   209
			&& (intercept == pListener->IsInterceptHook()) 
faluco@593
   210
			&& (pHook == pListener->GetHookedFunction()))
faluco@552
   211
		{
faluco@1541
   212
			*iter = _iter;
faluco@1541
   213
			return true;
faluco@552
   214
		}
faluco@505
   215
	}
faluco@552
   216
faluco@1541
   217
	return false;
faluco@552
   218
}
faluco@553
   219
faluco@593
   220
bool UsrMessageNatives::DeleteListener(IPluginContext *pCtx, MsgWrapperIter iter)
faluco@552
   221
{
faluco@593
   222
	MsgWrapperList *pList;
faluco@593
   223
	MsgListenerWrapper *pListener;
faluco@552
   224
	IPlugin *pl = g_PluginSys.FindPluginByContext(pCtx->GetContext());
faluco@552
   225
faluco@593
   226
	if (!pl->GetProperty("MsgListeners", reinterpret_cast<void **>(&pList)))
faluco@552
   227
	{
faluco@552
   228
		return false;
faluco@552
   229
	}
faluco@552
   230
faluco@593
   231
	pListener = (*iter);
faluco@593
   232
	pList->erase(iter);
faluco@593
   233
	m_FreeListeners.push(pListener);
faluco@552
   234
faluco@552
   235
	return true;
faluco@552
   236
}
faluco@552
   237
dvander@590
   238
/***************************************
dvander@590
   239
 *                                     *
dvander@590
   240
 * USER MESSAGE WRAPPER IMPLEMENTATION *
dvander@590
   241
 *                                     *
dvander@590
   242
 ***************************************/
dvander@590
   243
faluco@593
   244
void MsgListenerWrapper::Initialize(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept)
faluco@593
   245
{
faluco@593
   246
	if (intercept)
faluco@593
   247
	{
faluco@593
   248
		m_Intercept = hook;
faluco@593
   249
		m_Hook = NULL;
faluco@593
   250
	} else {
faluco@593
   251
		m_Hook = hook;
faluco@593
   252
		m_Intercept = NULL;
faluco@593
   253
	}
faluco@593
   254
faluco@593
   255
	if (notify)
faluco@593
   256
	{
faluco@593
   257
		m_Notify = notify;
faluco@593
   258
	} else {
faluco@593
   259
		m_Notify = NULL;
faluco@593
   260
	}
faluco@593
   261
faluco@593
   262
	m_MsgId = msgid;
faluco@593
   263
	m_IsInterceptHook = intercept;
faluco@593
   264
}
faluco@593
   265
faluco@593
   266
size_t MsgListenerWrapper::_FillInPlayers(int *pl_array, IRecipientFilter *pFilter)
dvander@590
   267
{
dvander@590
   268
	size_t size = static_cast<size_t>(pFilter->GetRecipientCount());
dvander@590
   269
dvander@590
   270
	for (size_t i=0; i<size; i++)
dvander@590
   271
	{
dvander@590
   272
		pl_array[i] = pFilter->GetRecipientIndex(i);
dvander@590
   273
	}
dvander@590
   274
dvander@590
   275
	return size;
dvander@590
   276
}
dvander@590
   277
dvander@590
   278
bool MsgListenerWrapper::IsInterceptHook() const
dvander@590
   279
{
dvander@590
   280
	return m_IsInterceptHook;
dvander@590
   281
}
dvander@590
   282
dvander@590
   283
int MsgListenerWrapper::GetMessageId() const
dvander@590
   284
{
dvander@590
   285
	return m_MsgId;
dvander@590
   286
}
dvander@590
   287
dvander@590
   288
IPluginFunction *MsgListenerWrapper::GetHookedFunction() const
dvander@590
   289
{
dvander@590
   290
	if (m_Hook)
dvander@590
   291
	{
dvander@590
   292
		return m_Hook;
dvander@590
   293
	} else {
dvander@590
   294
		return m_Intercept;
dvander@590
   295
	}
dvander@590
   296
}
dvander@590
   297
dvander@590
   298
IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const
dvander@590
   299
{
dvander@590
   300
	return m_Notify;
dvander@590
   301
}
dvander@590
   302
skamonkey@3743
   303
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   304
void MsgListenerWrapper::OnUserMessage(int msg_id, protobuf::Message *msg, IRecipientFilter *pFilter)
skamonkey@3743
   305
#else
dvander@590
   306
void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
skamonkey@3743
   307
#endif
dvander@590
   308
{
dvander@590
   309
	cell_t res;
skamonkey@3743
   310
	Handle_t hndl;
faluco@593
   311
	size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
dvander@590
   312
skamonkey@3743
   313
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   314
	hndl = g_HandleSys.CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), NULL, g_pCoreIdent, NULL);
skamonkey@3743
   315
#else
faluco@598
   316
	g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten());
skamonkey@3743
   317
	hndl = g_ReadBufHandle;
skamonkey@3743
   318
#endif
faluco@598
   319
dvander@590
   320
	m_Hook->PushCell(msg_id);
skamonkey@3743
   321
	m_Hook->PushCell(hndl);
dvander@590
   322
	m_Hook->PushArray(g_MsgPlayers, size);
dvander@590
   323
	m_Hook->PushCell(size);
dvander@590
   324
	m_Hook->PushCell(pFilter->IsReliable());
dvander@590
   325
	m_Hook->PushCell(pFilter->IsInitMessage());
dvander@590
   326
	m_Hook->Execute(&res);
skamonkey@3743
   327
skamonkey@3743
   328
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   329
	HandleSecurity sec;
skamonkey@3743
   330
	sec.pIdentity = g_pCoreIdent;
skamonkey@3743
   331
	g_HandleSys.FreeHandle(hndl, &sec);
skamonkey@3743
   332
#endif
dvander@590
   333
}
dvander@590
   334
skamonkey@3743
   335
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   336
ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, protobuf::Message *msg, IRecipientFilter *pFilter)
skamonkey@3743
   337
#else
dvander@590
   338
ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
skamonkey@3743
   339
#endif
dvander@590
   340
{
skamonkey@3743
   341
	Handle_t hndl;
dvander@590
   342
	cell_t res = static_cast<cell_t>(Pl_Continue);
faluco@593
   343
	size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
dvander@590
   344
skamonkey@3743
   345
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   346
	hndl = g_HandleSys.CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), NULL, g_pCoreIdent, NULL);
skamonkey@3743
   347
#else
faluco@598
   348
	g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten());
skamonkey@3743
   349
	hndl = g_ReadBufHandle;
skamonkey@3743
   350
#endif
faluco@598
   351
dvander@590
   352
	m_Intercept->PushCell(msg_id);
skamonkey@3743
   353
	m_Intercept->PushCell(hndl);
dvander@590
   354
	m_Intercept->PushArray(g_MsgPlayers, size);
dvander@590
   355
	m_Intercept->PushCell(size);
dvander@590
   356
	m_Intercept->PushCell(pFilter->IsReliable());
dvander@590
   357
	m_Intercept->PushCell(pFilter->IsInitMessage());
dvander@590
   358
	m_Intercept->Execute(&res);
dvander@590
   359
skamonkey@3743
   360
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   361
	HandleSecurity sec;
skamonkey@3743
   362
	sec.pIdentity = g_pCoreIdent;
skamonkey@3743
   363
	g_HandleSys.FreeHandle(hndl, &sec);
skamonkey@3743
   364
#endif
skamonkey@3743
   365
dvander@590
   366
	return static_cast<ResultType>(res);
dvander@590
   367
}
dvander@590
   368
dvander@2636
   369
void MsgListenerWrapper::OnPostUserMessage(int msg_id, bool sent)
dvander@590
   370
{
dvander@590
   371
	if (!m_Notify)
dvander@590
   372
	{
dvander@590
   373
		return;
dvander@590
   374
	}
dvander@590
   375
faluco@593
   376
	cell_t res;
dvander@590
   377
	m_Notify->PushCell(msg_id);
dvander@2636
   378
	m_Notify->PushCell(sent ? 1 : 0);
dvander@590
   379
	m_Notify->Execute(&res);
dvander@590
   380
}
dvander@590
   381
dvander@590
   382
/***************************************
dvander@590
   383
 *                                     *
dvander@590
   384
 * USER MESSAGE NATIVE IMPLEMENTATIONS *
dvander@590
   385
 *                                     *
dvander@590
   386
 ***************************************/
faluco@552
   387
faluco@552
   388
static UsrMessageNatives s_UsrMessageNatives;
faluco@505
   389
skamonkey@3743
   390
static cell_t smn_GetUserMessageType(IPluginContext *pCtx, const cell_t *params)
skamonkey@3743
   391
{
skamonkey@3743
   392
	return g_UserMsgs.GetUserMessageType();
skamonkey@3743
   393
}
skamonkey@3743
   394
faluco@505
   395
static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
faluco@505
   396
{
faluco@505
   397
	char *msgname;
ds@698
   398
	pCtx->LocalToString(params[1], &msgname);
faluco@505
   399
faluco@552
   400
	return g_UserMsgs.GetMessageIndex(msgname);
faluco@505
   401
}
faluco@505
   402
faluco@553
   403
static cell_t smn_GetUserMessageName(IPluginContext *pCtx, const cell_t *params)
faluco@553
   404
{
ds@765
   405
	char *msgname;
faluco@553
   406
ds@765
   407
	pCtx->LocalToPhysAddr(params[2], (cell_t **)&msgname);
faluco@553
   408
ds@765
   409
	return g_UserMsgs.GetMessageName(params[1], msgname, params[3]);
faluco@553
   410
}
faluco@553
   411
faluco@505
   412
static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
faluco@505
   413
{
faluco@505
   414
	char *msgname;
faluco@505
   415
	cell_t *cl_array;
ds@2112
   416
	unsigned int numClients;
ds@698
   417
	int msgid;
ds@2112
   418
	int client;
ds@2112
   419
	CPlayer *pPlayer = NULL;
faluco@505
   420
faluco@505
   421
	if (g_IsMsgInExec)
faluco@505
   422
	{
faluco@505
   423
		return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
faluco@505
   424
	}
faluco@505
   425
ds@698
   426
	pCtx->LocalToString(params[1], &msgname);
faluco@505
   427
faluco@552
   428
	if ((msgid=g_UserMsgs.GetMessageIndex(msgname)) == INVALID_MESSAGE_ID)
faluco@505
   429
	{
faluco@505
   430
		return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname);
faluco@505
   431
	}
faluco@505
   432
faluco@505
   433
	pCtx->LocalToPhysAddr(params[2], &cl_array);
faluco@505
   434
ds@2112
   435
	numClients = params[3];
ds@2112
   436
ds@2112
   437
	/* Client validation */
ds@2112
   438
	for (unsigned int i = 0; i < numClients; i++)
ds@2112
   439
	{
ds@2112
   440
		client = cl_array[i];
ds@2112
   441
		pPlayer = g_Players.GetPlayerByIndex(client);
ds@2112
   442
ds@2112
   443
		if (!pPlayer)
ds@2112
   444
		{
ds@2112
   445
			return pCtx->ThrowNativeError("Client index %d is invalid", client);
ds@2112
   446
		} else if (!pPlayer->IsConnected()) {
ds@2112
   447
			return pCtx->ThrowNativeError("Client %d is not connected", client);
ds@2112
   448
		}
ds@2112
   449
	}
ds@2112
   450
skamonkey@3743
   451
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   452
	protobuf::Message *msg = g_UserMsgs.StartProtobufMessage(msgid, cl_array, numClients, params[4]);
skamonkey@3743
   453
	if (!msg)
skamonkey@3743
   454
	{
skamonkey@3743
   455
		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
skamonkey@3743
   456
	}
skamonkey@3743
   457
skamonkey@3743
   458
	g_CurMsgHandle = g_HandleSys.CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), pCtx->GetIdentity(), g_pCoreIdent, NULL);
skamonkey@3743
   459
#else
skamonkey@3743
   460
	bf_write *pBitBuf = g_UserMsgs.StartBitBufMessage(msgid, cl_array, numClients, params[4]);
faluco@593
   461
	if (!pBitBuf)
faluco@593
   462
	{
faluco@593
   463
		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
faluco@593
   464
	}
faluco@505
   465
faluco@505
   466
	g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
skamonkey@3743
   467
#endif
skamonkey@3743
   468
faluco@505
   469
	g_IsMsgInExec = true;
faluco@505
   470
faluco@505
   471
	return g_CurMsgHandle;
faluco@505
   472
}
faluco@505
   473
faluco@505
   474
static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params)
faluco@505
   475
{
faluco@505
   476
	cell_t *cl_array;
ds@2112
   477
	unsigned int numClients;
ds@2112
   478
	int client;
ds@2112
   479
	CPlayer *pPlayer = NULL;
faluco@505
   480
	int msgid = params[1];
faluco@505
   481
faluco@505
   482
	if (g_IsMsgInExec)
faluco@505
   483
	{
faluco@505
   484
		return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
faluco@505
   485
	}
faluco@505
   486
faluco@552
   487
	if (msgid < 0 || msgid >= 255)
faluco@505
   488
	{
faluco@505
   489
		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
faluco@505
   490
	}
faluco@505
   491
faluco@505
   492
	pCtx->LocalToPhysAddr(params[2], &cl_array);
faluco@505
   493
ds@2112
   494
	numClients = params[3];
ds@2112
   495
ds@2112
   496
	/* Client validation */
ds@2112
   497
	for (unsigned int i = 0; i < numClients; i++)
ds@2112
   498
	{
ds@2112
   499
		client = cl_array[i];
ds@2112
   500
		pPlayer = g_Players.GetPlayerByIndex(client);
ds@2112
   501
ds@2112
   502
		if (!pPlayer)
ds@2112
   503
		{
ds@2112
   504
			return pCtx->ThrowNativeError("Client index %d is invalid", client);
ds@2112
   505
		} else if (!pPlayer->IsConnected()) {
ds@2112
   506
			return pCtx->ThrowNativeError("Client %d is not connected", client);
ds@2112
   507
		}
ds@2112
   508
	}
ds@2112
   509
skamonkey@3743
   510
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   511
	protobuf::Message *msg = g_UserMsgs.StartProtobufMessage(msgid, cl_array, numClients, params[4]);
skamonkey@3743
   512
	if (!msg)
skamonkey@3743
   513
	{
skamonkey@3743
   514
		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
skamonkey@3743
   515
	}
skamonkey@3743
   516
skamonkey@3743
   517
	g_CurMsgHandle = g_HandleSys.CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), pCtx->GetIdentity(), g_pCoreIdent, NULL);
skamonkey@3743
   518
#else
skamonkey@3743
   519
	bf_write *pBitBuf = g_UserMsgs.StartBitBufMessage(msgid, cl_array, numClients, params[4]);
faluco@593
   520
	if (!pBitBuf)
faluco@593
   521
	{
faluco@593
   522
		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
faluco@593
   523
	}
faluco@505
   524
faluco@505
   525
	g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
skamonkey@3743
   526
#endif
faluco@505
   527
	g_IsMsgInExec = true;
faluco@505
   528
faluco@505
   529
	return g_CurMsgHandle;
faluco@505
   530
}
faluco@505
   531
faluco@505
   532
static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params)
faluco@505
   533
{
faluco@505
   534
	HandleSecurity sec;
faluco@505
   535
faluco@505
   536
	if (!g_IsMsgInExec)
faluco@505
   537
	{
faluco@505
   538
		return pCtx->ThrowNativeError("Unable to end message, no message is in progress");
faluco@505
   539
	}
faluco@505
   540
faluco@552
   541
	g_UserMsgs.EndMessage();
faluco@505
   542
faluco@505
   543
	sec.pOwner = pCtx->GetIdentity();
faluco@505
   544
	sec.pIdentity = g_pCoreIdent;
faluco@505
   545
	g_HandleSys.FreeHandle(g_CurMsgHandle, &sec);
faluco@505
   546
faluco@505
   547
	g_IsMsgInExec = false;
faluco@552
   548
faluco@552
   549
	return 1;
faluco@552
   550
}
faluco@552
   551
faluco@552
   552
static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
faluco@552
   553
{
faluco@552
   554
	IPluginFunction *pHook, *pNotify;
faluco@593
   555
	MsgListenerWrapper *pListener;
faluco@552
   556
	bool intercept;
faluco@552
   557
	int msgid = params[1];
faluco@552
   558
faluco@552
   559
	if (msgid < 0 || msgid >= 255)
faluco@552
   560
	{
faluco@552
   561
		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
faluco@552
   562
	}
faluco@552
   563
faluco@552
   564
	pHook = pCtx->GetFunctionById(params[2]);
faluco@552
   565
	if (!pHook)
faluco@552
   566
	{
faluco@552
   567
		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
faluco@552
   568
	}
faluco@552
   569
	pNotify = pCtx->GetFunctionById(params[4]);
faluco@593
   570
	intercept = (params[3]) ? true : false;
faluco@552
   571
faluco@593
   572
	pListener = s_UsrMessageNatives.CreateListener(pCtx);
faluco@593
   573
	pListener->Initialize(msgid, pHook, pNotify, intercept);
faluco@553
   574
dvander@2636
   575
	g_UserMsgs.HookUserMessage2(msgid, pListener, intercept);
faluco@505
   576
faluco@505
   577
	return 1;
faluco@505
   578
}
faluco@505
   579
ds@626
   580
static cell_t smn_UnhookUserMessage(IPluginContext *pCtx, const cell_t *params)
faluco@552
   581
{
faluco@552
   582
	IPluginFunction *pFunc;
faluco@593
   583
	MsgListenerWrapper *pListener;
faluco@593
   584
	MsgWrapperIter iter;
faluco@552
   585
	bool intercept;
faluco@552
   586
	int msgid = params[1];
faluco@552
   587
faluco@552
   588
	if (msgid < 0 || msgid >= 255)
faluco@552
   589
	{
faluco@552
   590
		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
faluco@552
   591
	}
faluco@552
   592
faluco@552
   593
	pFunc = pCtx->GetFunctionById(params[2]);
faluco@552
   594
	if (!pFunc)
faluco@552
   595
	{
faluco@552
   596
		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
faluco@552
   597
	}
faluco@593
   598
	intercept = (params[3]) ? true : false;
faluco@552
   599
faluco@1541
   600
	if (!s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept, &iter))
faluco@552
   601
	{
faluco@552
   602
		return pCtx->ThrowNativeError("Unable to unhook the current user message");
faluco@552
   603
	}
faluco@552
   604
faluco@593
   605
	pListener = (*iter);
dvander@2636
   606
	if (!g_UserMsgs.UnhookUserMessage2(msgid, pListener, intercept))
faluco@552
   607
	{
faluco@552
   608
		return pCtx->ThrowNativeError("Unable to unhook the current user message");
faluco@552
   609
	}
faluco@552
   610
faluco@593
   611
	s_UsrMessageNatives.DeleteListener(pCtx, iter);
faluco@552
   612
faluco@552
   613
	return 1;
faluco@552
   614
}
faluco@505
   615
faluco@505
   616
REGISTER_NATIVES(usrmsgnatives)
faluco@505
   617
{
skamonkey@3743
   618
	{"GetUserMessageType",			smn_GetUserMessageType},
faluco@505
   619
	{"GetUserMessageId",			smn_GetUserMessageId},
faluco@553
   620
	{"GetUserMessageName",			smn_GetUserMessageName},
faluco@505
   621
	{"StartMessage",				smn_StartMessage},
faluco@505
   622
	{"StartMessageEx",				smn_StartMessageEx},
faluco@505
   623
	{"EndMessage",					smn_EndMessage},
faluco@552
   624
	{"HookUserMessage",				smn_HookUserMessage},
ds@626
   625
	{"UnhookUserMessage",			smn_UnhookUserMessage},
faluco@505
   626
	{NULL,							NULL}
faluco@505
   627
};