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