core/HalfLife2.cpp
author David Anderson <dvander@alliedmods.net>
Wed Feb 27 13:49:57 2008 +0000 (2008-02-27)
changeset 1900 457329ae65bd
parent 1848 6214ae913a8a
child 1943 3bc85e217519
permissions -rw-r--r--
fixed amb1483 - GetEntPropString() rejected FIELD_MODELNAME/FIELD_SOUNDNAME
dvander@592
     1
/**
ds@653
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
dvander@1231
     5
 * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@592
     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@592
    28
 *
dvander@592
    29
 * Version: $Id$
dvander@592
    30
 */
dvander@592
    31
dvander@592
    32
#include "HalfLife2.h"
ds@696
    33
#include "sourcemod.h"
dvander@592
    34
#include "sourcemm_api.h"
ds@873
    35
#include "UserMessages.h"
dvander@1338
    36
#include "PlayerManager.h"
dvander@1547
    37
#include "sm_stringutil.h"
dvander@1690
    38
#include "GameConfigs.h"
dvander@1547
    39
#include <compat_wrappers.h>
dvander@592
    40
dvander@592
    41
CHalfLife2 g_HL2;
dvander@1423
    42
ConVar *sv_lan = NULL;
dvander@592
    43
faluco@682
    44
namespace SourceHook
faluco@682
    45
{
faluco@682
    46
	template<>
faluco@682
    47
	int HashFunction<datamap_t *>(datamap_t * const &k)
faluco@682
    48
	{
faluco@682
    49
		return reinterpret_cast<int>(k);
faluco@682
    50
	}
faluco@682
    51
faluco@682
    52
	template<>
faluco@682
    53
	int Compare<datamap_t *>(datamap_t * const &k1, datamap_t * const &k2)
faluco@682
    54
	{
faluco@682
    55
		return (k1-k2);
faluco@682
    56
	}
faluco@682
    57
}
faluco@682
    58
dvander@592
    59
CHalfLife2::CHalfLife2()
dvander@592
    60
{
dvander@592
    61
	m_pClasses = sm_trie_create();
dvander@592
    62
}
dvander@592
    63
dvander@592
    64
CHalfLife2::~CHalfLife2()
dvander@592
    65
{
dvander@592
    66
	sm_trie_destroy(m_pClasses);
dvander@592
    67
dvander@592
    68
	List<DataTableInfo *>::iterator iter;
dvander@592
    69
	DataTableInfo *pInfo;
dvander@592
    70
	for (iter=m_Tables.begin(); iter!=m_Tables.end(); iter++)
dvander@592
    71
	{
dvander@592
    72
		pInfo = (*iter);
dvander@592
    73
		delete pInfo;
dvander@592
    74
	}
dvander@592
    75
dvander@592
    76
	m_Tables.clear();
faluco@682
    77
faluco@682
    78
	THash<datamap_t *, DataMapTrie>::iterator h_iter;
faluco@682
    79
	for (h_iter=m_Maps.begin(); h_iter!=m_Maps.end(); h_iter++)
faluco@682
    80
	{
faluco@682
    81
		if (h_iter->val.trie)
faluco@682
    82
		{
faluco@682
    83
			sm_trie_destroy(h_iter->val.trie);
faluco@682
    84
			h_iter->val.trie = NULL;
faluco@682
    85
		}
faluco@682
    86
	}
faluco@682
    87
faluco@682
    88
	m_Maps.clear();
dvander@592
    89
}
dvander@592
    90
dvander@677
    91
CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL;
dvander@1581
    92
bool is_original_engine = false;
dvander@677
    93
dvander@592
    94
void CHalfLife2::OnSourceModStartup(bool late)
dvander@592
    95
{
ds@696
    96
	/* The Ship currently is the only known game to use an older version of the engine */
dvander@1581
    97
#if defined METAMOD_PLAPI_VERSION
dvander@1581
    98
	if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL)
dvander@1581
    99
#else
ds@729
   100
	if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
dvander@1581
   101
#endif
dvander@677
   102
	{
dvander@1581
   103
		is_original_engine = true;
dvander@1581
   104
	}
dvander@1581
   105
	else if (g_pSharedChangeInfo == NULL)
dvander@1581
   106
	{
dvander@677
   107
		g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo();
dvander@677
   108
	}
dvander@592
   109
}
dvander@592
   110
ds@873
   111
void CHalfLife2::OnSourceModAllInitialized()
ds@873
   112
{
ds@873
   113
	m_MsgTextMsg = g_UserMsgs.GetMessageIndex("TextMsg");
faluco@1218
   114
	m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText");
faluco@1218
   115
	m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu");
dvander@965
   116
	g_ShareSys.AddInterface(NULL, this);
dvander@1847
   117
dvander@1847
   118
	FindInSendTable("CTFPlayer", "m_nDisguiseClass");
ds@873
   119
}
ds@873
   120
dvander@1581
   121
#if !defined METAMOD_PLAPI_VERSION
dvander@1581
   122
bool CHalfLife2::IsOriginalEngine()
dvander@1581
   123
{
dvander@1581
   124
	return is_original_engine;
dvander@1581
   125
}
dvander@1581
   126
#endif
dvander@1581
   127
dvander@678
   128
IChangeInfoAccessor *CBaseEdict::GetChangeAccessor()
dvander@678
   129
{
dvander@678
   130
	return engine->GetChangeAccessor( (const edict_t *)this );
dvander@678
   131
}
dvander@678
   132
dvander@1847
   133
bool UTIL_FindInSendTable(SendTable *pTable, 
dvander@1847
   134
						  const char *name,
dvander@1847
   135
						  sm_sendprop_info_t *info,
dvander@1847
   136
						  unsigned int offset)
dvander@592
   137
{
dvander@592
   138
	const char *pname;
dvander@592
   139
	int props = pTable->GetNumProps();
dvander@592
   140
	SendProp *prop;
dvander@592
   141
dvander@592
   142
	for (int i=0; i<props; i++)
dvander@592
   143
	{
dvander@592
   144
		prop = pTable->GetProp(i);
dvander@592
   145
		pname = prop->GetName();
dvander@592
   146
		if (pname && strcmp(name, pname) == 0)
dvander@592
   147
		{
dvander@1847
   148
			info->prop = prop;
dvander@1847
   149
			info->actual_offset = offset + info->prop->GetOffset();
dvander@1847
   150
			return true;
dvander@592
   151
		}
dvander@592
   152
		if (prop->GetDataTable())
dvander@592
   153
		{
dvander@1847
   154
			if (UTIL_FindInSendTable(prop->GetDataTable(), 
dvander@1847
   155
				name,
dvander@1847
   156
				info,
dvander@1847
   157
				offset + prop->GetOffset())
dvander@1847
   158
				)
dvander@592
   159
			{
dvander@1847
   160
				return true;
dvander@592
   161
			}
dvander@592
   162
		}
dvander@592
   163
	}
dvander@592
   164
dvander@1848
   165
	return false;
dvander@592
   166
}
dvander@592
   167
faluco@682
   168
typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name)
faluco@682
   169
{
faluco@682
   170
	while (pMap)
faluco@682
   171
	{
faluco@682
   172
		for (int i=0; i<pMap->dataNumFields; i++)
faluco@682
   173
		{
dvander@709
   174
			if (pMap->dataDesc[i].fieldName == NULL)
dvander@709
   175
			{
dvander@709
   176
				continue;
dvander@709
   177
			}
faluco@682
   178
			if (strcmp(name, pMap->dataDesc[i].fieldName) == 0)
faluco@682
   179
			{
faluco@682
   180
				return &(pMap->dataDesc[i]);
faluco@682
   181
			}
faluco@682
   182
			if (pMap->dataDesc[i].td)
faluco@682
   183
			{
faluco@682
   184
				typedescription_t *_td;
faluco@682
   185
				if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name)) != NULL)
faluco@682
   186
				{
faluco@682
   187
					return _td;
faluco@682
   188
				}
faluco@682
   189
			}
faluco@682
   190
		}
faluco@682
   191
		pMap = pMap->baseMap;
faluco@682
   192
	}
faluco@682
   193
faluco@682
   194
	return NULL; 
faluco@682
   195
}
faluco@682
   196
dvander@592
   197
ServerClass *CHalfLife2::FindServerClass(const char *classname)
dvander@592
   198
{
dvander@592
   199
	DataTableInfo *pInfo = _FindServerClass(classname);
dvander@1847
   200
dvander@592
   201
	if (!pInfo)
dvander@592
   202
	{
dvander@592
   203
		return NULL;
dvander@592
   204
	}
dvander@592
   205
dvander@592
   206
	return pInfo->sc;
dvander@592
   207
}
dvander@592
   208
dvander@592
   209
DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
dvander@592
   210
{
dvander@592
   211
	DataTableInfo *pInfo = NULL;
dvander@592
   212
dvander@592
   213
	if (!sm_trie_retrieve(m_pClasses, classname, (void **)&pInfo))
dvander@592
   214
	{
dvander@592
   215
		ServerClass *sc = gamedll->GetAllServerClasses();
dvander@592
   216
		while (sc)
dvander@592
   217
		{
dvander@592
   218
			if (strcmp(classname, sc->GetName()) == 0)
dvander@592
   219
			{
dvander@592
   220
				pInfo = new DataTableInfo;
dvander@592
   221
				pInfo->sc = sc;
dvander@592
   222
				sm_trie_insert(m_pClasses, classname, pInfo);
faluco@682
   223
				m_Tables.push_back(pInfo);
dvander@592
   224
				break;
dvander@592
   225
			}
dvander@592
   226
			sc = sc->m_pNext;
dvander@592
   227
		}
dvander@592
   228
		if (!pInfo)
dvander@592
   229
		{
dvander@592
   230
			return NULL;
dvander@592
   231
		}
dvander@592
   232
	}
dvander@592
   233
dvander@592
   234
	return pInfo;
dvander@592
   235
}
dvander@592
   236
dvander@1847
   237
bool CHalfLife2::FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info)
dvander@1847
   238
{
dvander@1847
   239
	DataTableInfo *pInfo;
dvander@1847
   240
	sm_sendprop_info_t *prop;
dvander@1847
   241
dvander@1847
   242
	if ((pInfo = _FindServerClass(classname)) == NULL)
dvander@1847
   243
	{
dvander@1847
   244
		return false;
dvander@1847
   245
	}
dvander@1847
   246
dvander@1847
   247
	if ((prop = pInfo->lookup.retrieve(offset)) == NULL)
dvander@1847
   248
	{
dvander@1847
   249
		sm_sendprop_info_t temp_info;
dvander@1847
   250
dvander@1847
   251
		if (!UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp_info, 0))
dvander@1847
   252
		{
dvander@1847
   253
			return false;
dvander@1847
   254
		}
dvander@1847
   255
dvander@1847
   256
		pInfo->lookup.insert(offset, temp_info);
dvander@1847
   257
		*info = temp_info;
dvander@1847
   258
	}
dvander@1847
   259
	else
dvander@1847
   260
	{
dvander@1847
   261
		*info = *prop;
dvander@1847
   262
	}
dvander@1847
   263
	
dvander@1847
   264
	return true;
dvander@1847
   265
}
dvander@1847
   266
dvander@592
   267
SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
dvander@592
   268
{
dvander@1847
   269
	sm_sendprop_info_t info;
dvander@592
   270
dvander@1847
   271
	if (!FindSendPropInfo(classname, offset, &info))
dvander@592
   272
	{
dvander@592
   273
		return NULL;
dvander@592
   274
	}
dvander@592
   275
dvander@1847
   276
	return info.prop;
dvander@592
   277
}
faluco@682
   278
faluco@682
   279
typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset)
faluco@682
   280
{
faluco@682
   281
	typedescription_t *td = NULL;
faluco@682
   282
	DataMapTrie &val = m_Maps[pMap];
faluco@682
   283
faluco@682
   284
	if (!val.trie)
faluco@682
   285
	{
faluco@682
   286
		val.trie = sm_trie_create();
faluco@682
   287
	}
faluco@682
   288
	if (!sm_trie_retrieve(val.trie, offset, (void **)&td))
faluco@682
   289
	{
faluco@682
   290
		if ((td = UTIL_FindInDataMap(pMap, offset)) != NULL)
faluco@682
   291
		{
faluco@682
   292
			sm_trie_insert(val.trie, offset, td);
faluco@682
   293
		}
faluco@682
   294
	}
faluco@682
   295
faluco@682
   296
	return td;
faluco@682
   297
}
dvander@685
   298
dvander@685
   299
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
dvander@685
   300
{
dvander@1581
   301
	if (g_pSharedChangeInfo != NULL)
dvander@685
   302
	{
dvander@685
   303
		if (offset)
dvander@685
   304
		{
dvander@685
   305
			pEdict->StateChanged(offset);
dvander@1847
   306
		}
dvander@1847
   307
		else
dvander@1847
   308
		{
dvander@685
   309
			pEdict->StateChanged();
dvander@685
   310
		}
dvander@1581
   311
	}
dvander@1581
   312
	else
dvander@1581
   313
	{
dvander@685
   314
		pEdict->m_fStateFlags |= FL_EDICT_CHANGED;
dvander@685
   315
	}
dvander@685
   316
}
ds@873
   317
dvander@1132
   318
bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
ds@873
   319
{
ds@873
   320
	bf_write *pBitBuf = NULL;
ds@873
   321
	cell_t players[] = {client};
ds@873
   322
dvander@1132
   323
	if ((pBitBuf = g_UserMsgs.StartMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
dvander@1132
   324
	{
dvander@1132
   325
		return false;
dvander@1132
   326
	}
dvander@1132
   327
ds@873
   328
	pBitBuf->WriteByte(dest);
ds@873
   329
	pBitBuf->WriteString(msg);
ds@873
   330
	g_UserMsgs.EndMessage();
dvander@1132
   331
dvander@1132
   332
	return true;
ds@873
   333
}
faluco@1218
   334
teame06@1264
   335
bool CHalfLife2::HintTextMsg(int client, const char *msg)
faluco@1218
   336
{
faluco@1218
   337
	bf_write *pBitBuf = NULL;
faluco@1218
   338
	cell_t players[] = {client};
faluco@1218
   339
faluco@1218
   340
	if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
faluco@1218
   341
	{
faluco@1218
   342
		return false;
faluco@1218
   343
	}
faluco@1218
   344
dvander@1690
   345
	const char *pre_byte = g_pGameConf->GetKeyValue("HintTextPreByte");
dvander@1690
   346
	if (pre_byte != NULL && strcmp(pre_byte, "yes") == 0)
dvander@1690
   347
	{
dvander@1690
   348
		pBitBuf->WriteByte(1);
dvander@1690
   349
	}
faluco@1218
   350
	pBitBuf->WriteString(msg);
faluco@1218
   351
	g_UserMsgs.EndMessage();
faluco@1218
   352
faluco@1218
   353
	return true;
faluco@1218
   354
}
faluco@1218
   355
faluco@1218
   356
bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show)
faluco@1218
   357
{
faluco@1218
   358
	bf_write *pBitBuf = NULL;
faluco@1218
   359
	KeyValues *SubKey = NULL;
faluco@1218
   360
	int count = 0;
faluco@1218
   361
	cell_t players[] = {client};
faluco@1218
   362
faluco@1218
   363
	if ((pBitBuf = g_UserMsgs.StartMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
faluco@1218
   364
	{
faluco@1218
   365
		return false;
faluco@1218
   366
	}
faluco@1218
   367
faluco@1218
   368
	if (data)
faluco@1218
   369
	{
faluco@1218
   370
		SubKey = data->GetFirstSubKey();
faluco@1218
   371
		while (SubKey)
faluco@1218
   372
		{
faluco@1218
   373
			count++;
faluco@1218
   374
			SubKey = SubKey->GetNextKey();
faluco@1218
   375
		}
faluco@1218
   376
		SubKey = data->GetFirstSubKey();
faluco@1218
   377
	}
faluco@1218
   378
faluco@1218
   379
	pBitBuf->WriteString(name);
faluco@1218
   380
	pBitBuf->WriteByte((show) ? 1 : 0);
faluco@1218
   381
	pBitBuf->WriteByte(count);
faluco@1218
   382
	while (SubKey)
faluco@1218
   383
	{
faluco@1218
   384
		pBitBuf->WriteString(SubKey->GetName());
faluco@1218
   385
		pBitBuf->WriteString(SubKey->GetString());
faluco@1218
   386
		SubKey = SubKey->GetNextKey();
faluco@1218
   387
	}
faluco@1218
   388
	g_UserMsgs.EndMessage();
faluco@1218
   389
faluco@1218
   390
	return true;
faluco@1218
   391
}
dvander@1338
   392
dvander@1338
   393
void CHalfLife2::AddToFakeCliCmdQueue(int client, int userid, const char *cmd)
dvander@1338
   394
{
dvander@1338
   395
	DelayedFakeCliCmd *pFake;
dvander@1338
   396
dvander@1338
   397
	if (m_FreeCmds.empty())
dvander@1338
   398
	{
dvander@1338
   399
		pFake = new DelayedFakeCliCmd;
dvander@1338
   400
	} else {
dvander@1338
   401
		pFake = m_FreeCmds.front();
dvander@1338
   402
		m_FreeCmds.pop();
dvander@1338
   403
	}
dvander@1338
   404
dvander@1338
   405
	pFake->client = client;
dvander@1338
   406
	pFake->userid = userid;
dvander@1338
   407
	pFake->cmd.assign(cmd);
dvander@1338
   408
dvander@1338
   409
	m_CmdQueue.push(pFake);
dvander@1338
   410
}
dvander@1338
   411
dvander@1338
   412
void CHalfLife2::ProcessFakeCliCmdQueue()
dvander@1338
   413
{
dvander@1338
   414
	while (!m_CmdQueue.empty())
dvander@1338
   415
	{
dvander@1338
   416
		DelayedFakeCliCmd *pFake = m_CmdQueue.first();
dvander@1338
   417
dvander@1338
   418
		if (g_Players.GetClientOfUserId(pFake->userid) == pFake->client)
dvander@1338
   419
		{
dvander@1338
   420
			CPlayer *pPlayer = g_Players.GetPlayerByIndex(pFake->client);
dvander@1338
   421
			serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), pFake->cmd.c_str());
dvander@1338
   422
		}
dvander@1338
   423
dvander@1338
   424
		m_CmdQueue.pop();
dvander@1338
   425
	}
dvander@1338
   426
}
dvander@1423
   427
dvander@1423
   428
bool CHalfLife2::IsLANServer()
dvander@1423
   429
{
dvander@1423
   430
	sv_lan = icvar->FindVar("sv_lan");
dvander@1423
   431
dvander@1423
   432
	if (!sv_lan)
dvander@1423
   433
	{
dvander@1423
   434
		return false;
dvander@1423
   435
	}
dvander@1423
   436
dvander@1423
   437
	return (sv_lan->GetInt() != 0);
dvander@1423
   438
}
dvander@1544
   439
dvander@1544
   440
void CHalfLife2::PushCommandStack(const CCommand *cmd)
dvander@1544
   441
{
dvander@1544
   442
	CachedCommandInfo info;
dvander@1544
   443
dvander@1544
   444
	info.args = cmd;
dvander@1544
   445
#if !defined ORANGEBOX_BUILD
dvander@1544
   446
	strncopy(info.cmd, cmd->Arg(0), sizeof(info.cmd));
dvander@1544
   447
#endif
dvander@1544
   448
dvander@1544
   449
	m_CommandStack.push(info);
dvander@1544
   450
}
dvander@1544
   451
dvander@1544
   452
const CCommand *CHalfLife2::PeekCommandStack()
dvander@1544
   453
{
dvander@1544
   454
	if (m_CommandStack.empty())
dvander@1544
   455
	{
dvander@1544
   456
		return NULL;
dvander@1544
   457
	}
dvander@1544
   458
dvander@1544
   459
	return m_CommandStack.front().args;
dvander@1544
   460
}
dvander@1544
   461
dvander@1544
   462
void CHalfLife2::PopCommandStack()
dvander@1544
   463
{
dvander@1544
   464
	m_CommandStack.pop();
dvander@1544
   465
}
dvander@1544
   466
dvander@1544
   467
const char *CHalfLife2::CurrentCommandName()
dvander@1544
   468
{
dvander@1544
   469
#if defined ORANGEBOX_BUILD
dvander@1544
   470
	return m_CommandStack.front().args->Arg(0);
dvander@1544
   471
#else
dvander@1544
   472
	return m_CommandStack.front().cmd;
dvander@1544
   473
#endif
dvander@1544
   474
}