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