core/smn_usermsgs.cpp
author Kyle Sanderson <kyle.leet@gmail.com>
Mon Aug 12 00:45:29 2013 +0100 (2013-08-12)
changeset 3996 4a0daf289347
parent 3942 7aaa00382627
child 4344 c445c3266192
permissions -rw-r--r--
Dump handle information when a plugin is forcefully unloaded. (bug 5666, r=asherkin)
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
	{
skamonkey@3916
   271
		int index;
skamonkey@3916
   272
#if SOURCE_ENGINE == SE_DOTA
skamonkey@3942
   273
		index = pFilter->GetRecipientIndex(i).Get();
skamonkey@3916
   274
#else
skamonkey@3916
   275
		index = pFilter->GetRecipientIndex(i);
skamonkey@3916
   276
#endif
skamonkey@3916
   277
		pl_array[i] = index;
dvander@590
   278
	}
dvander@590
   279
dvander@590
   280
	return size;
dvander@590
   281
}
dvander@590
   282
dvander@590
   283
bool MsgListenerWrapper::IsInterceptHook() const
dvander@590
   284
{
dvander@590
   285
	return m_IsInterceptHook;
dvander@590
   286
}
dvander@590
   287
dvander@590
   288
int MsgListenerWrapper::GetMessageId() const
dvander@590
   289
{
dvander@590
   290
	return m_MsgId;
dvander@590
   291
}
dvander@590
   292
dvander@590
   293
IPluginFunction *MsgListenerWrapper::GetHookedFunction() const
dvander@590
   294
{
dvander@590
   295
	if (m_Hook)
dvander@590
   296
	{
dvander@590
   297
		return m_Hook;
dvander@590
   298
	} else {
dvander@590
   299
		return m_Intercept;
dvander@590
   300
	}
dvander@590
   301
}
dvander@590
   302
dvander@590
   303
IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const
dvander@590
   304
{
dvander@590
   305
	return m_Notify;
dvander@590
   306
}
dvander@590
   307
skamonkey@3743
   308
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   309
void MsgListenerWrapper::OnUserMessage(int msg_id, protobuf::Message *msg, IRecipientFilter *pFilter)
skamonkey@3743
   310
#else
dvander@590
   311
void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
skamonkey@3743
   312
#endif
dvander@590
   313
{
dvander@590
   314
	cell_t res;
skamonkey@3743
   315
	Handle_t hndl;
faluco@593
   316
	size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
dvander@590
   317
skamonkey@3743
   318
#ifdef USE_PROTOBUF_USERMESSAGES
dvander@3872
   319
	hndl = handlesys->CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), NULL, g_pCoreIdent, NULL);
skamonkey@3743
   320
#else
faluco@598
   321
	g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten());
skamonkey@3743
   322
	hndl = g_ReadBufHandle;
skamonkey@3743
   323
#endif
faluco@598
   324
dvander@590
   325
	m_Hook->PushCell(msg_id);
skamonkey@3743
   326
	m_Hook->PushCell(hndl);
dvander@590
   327
	m_Hook->PushArray(g_MsgPlayers, size);
dvander@590
   328
	m_Hook->PushCell(size);
dvander@590
   329
	m_Hook->PushCell(pFilter->IsReliable());
dvander@590
   330
	m_Hook->PushCell(pFilter->IsInitMessage());
dvander@590
   331
	m_Hook->Execute(&res);
skamonkey@3743
   332
skamonkey@3743
   333
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   334
	HandleSecurity sec;
skamonkey@3743
   335
	sec.pIdentity = g_pCoreIdent;
dvander@3872
   336
	handlesys->FreeHandle(hndl, &sec);
skamonkey@3743
   337
#endif
dvander@590
   338
}
dvander@590
   339
skamonkey@3743
   340
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   341
ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, protobuf::Message *msg, IRecipientFilter *pFilter)
skamonkey@3743
   342
#else
dvander@590
   343
ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
skamonkey@3743
   344
#endif
dvander@590
   345
{
skamonkey@3743
   346
	Handle_t hndl;
dvander@590
   347
	cell_t res = static_cast<cell_t>(Pl_Continue);
faluco@593
   348
	size_t size = _FillInPlayers(g_MsgPlayers, pFilter);
dvander@590
   349
skamonkey@3743
   350
#ifdef USE_PROTOBUF_USERMESSAGES
dvander@3872
   351
	hndl = handlesys->CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), NULL, g_pCoreIdent, NULL);
skamonkey@3743
   352
#else
faluco@598
   353
	g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten());
skamonkey@3743
   354
	hndl = g_ReadBufHandle;
skamonkey@3743
   355
#endif
faluco@598
   356
dvander@590
   357
	m_Intercept->PushCell(msg_id);
skamonkey@3743
   358
	m_Intercept->PushCell(hndl);
dvander@590
   359
	m_Intercept->PushArray(g_MsgPlayers, size);
dvander@590
   360
	m_Intercept->PushCell(size);
dvander@590
   361
	m_Intercept->PushCell(pFilter->IsReliable());
dvander@590
   362
	m_Intercept->PushCell(pFilter->IsInitMessage());
dvander@590
   363
	m_Intercept->Execute(&res);
dvander@590
   364
skamonkey@3743
   365
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   366
	HandleSecurity sec;
skamonkey@3743
   367
	sec.pIdentity = g_pCoreIdent;
dvander@3872
   368
	handlesys->FreeHandle(hndl, &sec);
skamonkey@3743
   369
#endif
skamonkey@3743
   370
dvander@590
   371
	return static_cast<ResultType>(res);
dvander@590
   372
}
dvander@590
   373
dvander@2636
   374
void MsgListenerWrapper::OnPostUserMessage(int msg_id, bool sent)
dvander@590
   375
{
dvander@590
   376
	if (!m_Notify)
dvander@590
   377
	{
dvander@590
   378
		return;
dvander@590
   379
	}
dvander@590
   380
faluco@593
   381
	cell_t res;
dvander@590
   382
	m_Notify->PushCell(msg_id);
dvander@2636
   383
	m_Notify->PushCell(sent ? 1 : 0);
dvander@590
   384
	m_Notify->Execute(&res);
dvander@590
   385
}
dvander@590
   386
dvander@590
   387
/***************************************
dvander@590
   388
 *                                     *
dvander@590
   389
 * USER MESSAGE NATIVE IMPLEMENTATIONS *
dvander@590
   390
 *                                     *
dvander@590
   391
 ***************************************/
faluco@552
   392
faluco@552
   393
static UsrMessageNatives s_UsrMessageNatives;
faluco@505
   394
skamonkey@3743
   395
static cell_t smn_GetUserMessageType(IPluginContext *pCtx, const cell_t *params)
skamonkey@3743
   396
{
skamonkey@3743
   397
	return g_UserMsgs.GetUserMessageType();
skamonkey@3743
   398
}
skamonkey@3743
   399
faluco@505
   400
static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params)
faluco@505
   401
{
faluco@505
   402
	char *msgname;
ds@698
   403
	pCtx->LocalToString(params[1], &msgname);
faluco@505
   404
faluco@552
   405
	return g_UserMsgs.GetMessageIndex(msgname);
faluco@505
   406
}
faluco@505
   407
faluco@553
   408
static cell_t smn_GetUserMessageName(IPluginContext *pCtx, const cell_t *params)
faluco@553
   409
{
ds@765
   410
	char *msgname;
faluco@553
   411
ds@765
   412
	pCtx->LocalToPhysAddr(params[2], (cell_t **)&msgname);
faluco@553
   413
ds@765
   414
	return g_UserMsgs.GetMessageName(params[1], msgname, params[3]);
faluco@553
   415
}
faluco@553
   416
faluco@505
   417
static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params)
faluco@505
   418
{
faluco@505
   419
	char *msgname;
faluco@505
   420
	cell_t *cl_array;
ds@2112
   421
	unsigned int numClients;
ds@698
   422
	int msgid;
ds@2112
   423
	int client;
ds@2112
   424
	CPlayer *pPlayer = NULL;
faluco@505
   425
faluco@505
   426
	if (g_IsMsgInExec)
faluco@505
   427
	{
faluco@505
   428
		return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
faluco@505
   429
	}
faluco@505
   430
ds@698
   431
	pCtx->LocalToString(params[1], &msgname);
faluco@505
   432
faluco@552
   433
	if ((msgid=g_UserMsgs.GetMessageIndex(msgname)) == INVALID_MESSAGE_ID)
faluco@505
   434
	{
faluco@505
   435
		return pCtx->ThrowNativeError("Invalid message name: \"%s\"", msgname);
faluco@505
   436
	}
faluco@505
   437
faluco@505
   438
	pCtx->LocalToPhysAddr(params[2], &cl_array);
faluco@505
   439
ds@2112
   440
	numClients = params[3];
ds@2112
   441
ds@2112
   442
	/* Client validation */
ds@2112
   443
	for (unsigned int i = 0; i < numClients; i++)
ds@2112
   444
	{
ds@2112
   445
		client = cl_array[i];
ds@2112
   446
		pPlayer = g_Players.GetPlayerByIndex(client);
ds@2112
   447
ds@2112
   448
		if (!pPlayer)
ds@2112
   449
		{
ds@2112
   450
			return pCtx->ThrowNativeError("Client index %d is invalid", client);
ds@2112
   451
		} else if (!pPlayer->IsConnected()) {
ds@2112
   452
			return pCtx->ThrowNativeError("Client %d is not connected", client);
ds@2112
   453
		}
ds@2112
   454
	}
ds@2112
   455
skamonkey@3743
   456
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   457
	protobuf::Message *msg = g_UserMsgs.StartProtobufMessage(msgid, cl_array, numClients, params[4]);
skamonkey@3743
   458
	if (!msg)
skamonkey@3743
   459
	{
skamonkey@3743
   460
		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
skamonkey@3743
   461
	}
skamonkey@3743
   462
dvander@3872
   463
	g_CurMsgHandle = handlesys->CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), pCtx->GetIdentity(), g_pCoreIdent, NULL);
skamonkey@3743
   464
#else
skamonkey@3743
   465
	bf_write *pBitBuf = g_UserMsgs.StartBitBufMessage(msgid, cl_array, numClients, params[4]);
faluco@593
   466
	if (!pBitBuf)
faluco@593
   467
	{
faluco@593
   468
		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
faluco@593
   469
	}
faluco@505
   470
dvander@3872
   471
	g_CurMsgHandle = handlesys->CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
skamonkey@3743
   472
#endif
skamonkey@3743
   473
faluco@505
   474
	g_IsMsgInExec = true;
faluco@505
   475
faluco@505
   476
	return g_CurMsgHandle;
faluco@505
   477
}
faluco@505
   478
faluco@505
   479
static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params)
faluco@505
   480
{
faluco@505
   481
	cell_t *cl_array;
ds@2112
   482
	unsigned int numClients;
ds@2112
   483
	int client;
ds@2112
   484
	CPlayer *pPlayer = NULL;
faluco@505
   485
	int msgid = params[1];
faluco@505
   486
faluco@505
   487
	if (g_IsMsgInExec)
faluco@505
   488
	{
faluco@505
   489
		return pCtx->ThrowNativeError("Unable to execute a new message, there is already one in progress");
faluco@505
   490
	}
faluco@505
   491
faluco@552
   492
	if (msgid < 0 || msgid >= 255)
faluco@505
   493
	{
faluco@505
   494
		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
faluco@505
   495
	}
faluco@505
   496
faluco@505
   497
	pCtx->LocalToPhysAddr(params[2], &cl_array);
faluco@505
   498
ds@2112
   499
	numClients = params[3];
ds@2112
   500
ds@2112
   501
	/* Client validation */
ds@2112
   502
	for (unsigned int i = 0; i < numClients; i++)
ds@2112
   503
	{
ds@2112
   504
		client = cl_array[i];
ds@2112
   505
		pPlayer = g_Players.GetPlayerByIndex(client);
ds@2112
   506
ds@2112
   507
		if (!pPlayer)
ds@2112
   508
		{
ds@2112
   509
			return pCtx->ThrowNativeError("Client index %d is invalid", client);
ds@2112
   510
		} else if (!pPlayer->IsConnected()) {
ds@2112
   511
			return pCtx->ThrowNativeError("Client %d is not connected", client);
ds@2112
   512
		}
ds@2112
   513
	}
ds@2112
   514
skamonkey@3743
   515
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   516
	protobuf::Message *msg = g_UserMsgs.StartProtobufMessage(msgid, cl_array, numClients, params[4]);
skamonkey@3743
   517
	if (!msg)
skamonkey@3743
   518
	{
skamonkey@3743
   519
		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
skamonkey@3743
   520
	}
skamonkey@3743
   521
dvander@3872
   522
	g_CurMsgHandle = handlesys->CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), pCtx->GetIdentity(), g_pCoreIdent, NULL);
skamonkey@3743
   523
#else
skamonkey@3743
   524
	bf_write *pBitBuf = g_UserMsgs.StartBitBufMessage(msgid, cl_array, numClients, params[4]);
faluco@593
   525
	if (!pBitBuf)
faluco@593
   526
	{
faluco@593
   527
		return pCtx->ThrowNativeError("Unable to execute a new message while in hook");
faluco@593
   528
	}
faluco@505
   529
dvander@3872
   530
	g_CurMsgHandle = handlesys->CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL);
skamonkey@3743
   531
#endif
faluco@505
   532
	g_IsMsgInExec = true;
faluco@505
   533
faluco@505
   534
	return g_CurMsgHandle;
faluco@505
   535
}
faluco@505
   536
faluco@505
   537
static cell_t smn_EndMessage(IPluginContext *pCtx, const cell_t *params)
faluco@505
   538
{
faluco@505
   539
	HandleSecurity sec;
faluco@505
   540
faluco@505
   541
	if (!g_IsMsgInExec)
faluco@505
   542
	{
faluco@505
   543
		return pCtx->ThrowNativeError("Unable to end message, no message is in progress");
faluco@505
   544
	}
faluco@505
   545
faluco@552
   546
	g_UserMsgs.EndMessage();
faluco@505
   547
faluco@505
   548
	sec.pOwner = pCtx->GetIdentity();
faluco@505
   549
	sec.pIdentity = g_pCoreIdent;
dvander@3872
   550
	handlesys->FreeHandle(g_CurMsgHandle, &sec);
faluco@505
   551
faluco@505
   552
	g_IsMsgInExec = false;
faluco@552
   553
faluco@552
   554
	return 1;
faluco@552
   555
}
faluco@552
   556
faluco@552
   557
static cell_t smn_HookUserMessage(IPluginContext *pCtx, const cell_t *params)
faluco@552
   558
{
faluco@552
   559
	IPluginFunction *pHook, *pNotify;
faluco@593
   560
	MsgListenerWrapper *pListener;
faluco@552
   561
	bool intercept;
faluco@552
   562
	int msgid = params[1];
faluco@552
   563
faluco@552
   564
	if (msgid < 0 || msgid >= 255)
faluco@552
   565
	{
faluco@552
   566
		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
faluco@552
   567
	}
faluco@552
   568
faluco@552
   569
	pHook = pCtx->GetFunctionById(params[2]);
faluco@552
   570
	if (!pHook)
faluco@552
   571
	{
faluco@552
   572
		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
faluco@552
   573
	}
faluco@552
   574
	pNotify = pCtx->GetFunctionById(params[4]);
faluco@593
   575
	intercept = (params[3]) ? true : false;
faluco@552
   576
faluco@593
   577
	pListener = s_UsrMessageNatives.CreateListener(pCtx);
faluco@593
   578
	pListener->Initialize(msgid, pHook, pNotify, intercept);
faluco@553
   579
dvander@2636
   580
	g_UserMsgs.HookUserMessage2(msgid, pListener, intercept);
faluco@505
   581
faluco@505
   582
	return 1;
faluco@505
   583
}
faluco@505
   584
ds@626
   585
static cell_t smn_UnhookUserMessage(IPluginContext *pCtx, const cell_t *params)
faluco@552
   586
{
faluco@552
   587
	IPluginFunction *pFunc;
faluco@593
   588
	MsgListenerWrapper *pListener;
faluco@593
   589
	MsgWrapperIter iter;
faluco@552
   590
	bool intercept;
faluco@552
   591
	int msgid = params[1];
faluco@552
   592
faluco@552
   593
	if (msgid < 0 || msgid >= 255)
faluco@552
   594
	{
faluco@552
   595
		return pCtx->ThrowNativeError("Invalid message id supplied (%d)", msgid);
faluco@552
   596
	}
faluco@552
   597
faluco@552
   598
	pFunc = pCtx->GetFunctionById(params[2]);
faluco@552
   599
	if (!pFunc)
faluco@552
   600
	{
faluco@552
   601
		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
faluco@552
   602
	}
faluco@593
   603
	intercept = (params[3]) ? true : false;
faluco@552
   604
faluco@1541
   605
	if (!s_UsrMessageNatives.FindListener(msgid, pCtx, pFunc, intercept, &iter))
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
	pListener = (*iter);
dvander@2636
   611
	if (!g_UserMsgs.UnhookUserMessage2(msgid, pListener, intercept))
faluco@552
   612
	{
faluco@552
   613
		return pCtx->ThrowNativeError("Unable to unhook the current user message");
faluco@552
   614
	}
faluco@552
   615
faluco@593
   616
	s_UsrMessageNatives.DeleteListener(pCtx, iter);
faluco@552
   617
faluco@552
   618
	return 1;
faluco@552
   619
}
faluco@505
   620
faluco@505
   621
REGISTER_NATIVES(usrmsgnatives)
faluco@505
   622
{
skamonkey@3743
   623
	{"GetUserMessageType",			smn_GetUserMessageType},
faluco@505
   624
	{"GetUserMessageId",			smn_GetUserMessageId},
faluco@553
   625
	{"GetUserMessageName",			smn_GetUserMessageName},
faluco@505
   626
	{"StartMessage",				smn_StartMessage},
faluco@505
   627
	{"StartMessageEx",				smn_StartMessageEx},
faluco@505
   628
	{"EndMessage",					smn_EndMessage},
faluco@552
   629
	{"HookUserMessage",				smn_HookUserMessage},
ds@626
   630
	{"UnhookUserMessage",			smn_UnhookUserMessage},
faluco@505
   631
	{NULL,							NULL}
faluco@505
   632
};