core/HalfLife2.cpp
author David Anderson <dvander@alliedmods.net>
Mon Oct 15 00:38:25 2007 +0000 (2007-10-15)
changeset 1568 ecbaee393b0b
parent 1547 78abc407c8a3
child 1581 2562512b4a44
permissions -rw-r--r--
extensions can now be built for multiple engines, and will autoload from auto.X.Y folders
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@1547
    38
#include <compat_wrappers.h>
dvander@592
    39
dvander@592
    40
CHalfLife2 g_HL2;
dvander@685
    41
bool g_IsOriginalEngine = false;
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
		sm_trie_destroy(pInfo->lookup);
dvander@592
    74
		delete pInfo;
dvander@592
    75
	}
dvander@592
    76
dvander@592
    77
	m_Tables.clear();
faluco@682
    78
faluco@682
    79
	THash<datamap_t *, DataMapTrie>::iterator h_iter;
faluco@682
    80
	for (h_iter=m_Maps.begin(); h_iter!=m_Maps.end(); h_iter++)
faluco@682
    81
	{
faluco@682
    82
		if (h_iter->val.trie)
faluco@682
    83
		{
faluco@682
    84
			sm_trie_destroy(h_iter->val.trie);
faluco@682
    85
			h_iter->val.trie = NULL;
faluco@682
    86
		}
faluco@682
    87
	}
faluco@682
    88
faluco@682
    89
	m_Maps.clear();
dvander@592
    90
}
dvander@592
    91
dvander@677
    92
CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL;
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 */
ds@729
    97
	if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
dvander@677
    98
	{
ds@696
    99
		/* :TODO: Better engine versioning - perhaps something added to SourceMM? */
ds@696
   100
		g_IsOriginalEngine = true;
ds@696
   101
	} else if (!g_pSharedChangeInfo) {
dvander@677
   102
		g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo();
dvander@677
   103
	}
dvander@592
   104
}
dvander@592
   105
ds@873
   106
void CHalfLife2::OnSourceModAllInitialized()
ds@873
   107
{
ds@873
   108
	m_MsgTextMsg = g_UserMsgs.GetMessageIndex("TextMsg");
faluco@1218
   109
	m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText");
faluco@1218
   110
	m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu");
dvander@965
   111
	g_ShareSys.AddInterface(NULL, this);
ds@873
   112
}
ds@873
   113
dvander@678
   114
IChangeInfoAccessor *CBaseEdict::GetChangeAccessor()
dvander@678
   115
{
dvander@678
   116
	return engine->GetChangeAccessor( (const edict_t *)this );
dvander@678
   117
}
dvander@678
   118
dvander@592
   119
SendProp *UTIL_FindInSendTable(SendTable *pTable, const char *name)
dvander@592
   120
{
dvander@592
   121
	const char *pname;
dvander@592
   122
	int props = pTable->GetNumProps();
dvander@592
   123
	SendProp *prop;
dvander@592
   124
dvander@592
   125
	for (int i=0; i<props; i++)
dvander@592
   126
	{
dvander@592
   127
		prop = pTable->GetProp(i);
dvander@592
   128
		pname = prop->GetName();
dvander@592
   129
		if (pname && strcmp(name, pname) == 0)
dvander@592
   130
		{
dvander@592
   131
			return prop;
dvander@592
   132
		}
dvander@592
   133
		if (prop->GetDataTable())
dvander@592
   134
		{
dvander@592
   135
			if ((prop=UTIL_FindInSendTable(prop->GetDataTable(), name)) != NULL)
dvander@592
   136
			{
dvander@592
   137
				return prop;
dvander@592
   138
			}
dvander@592
   139
		}
dvander@592
   140
	}
dvander@592
   141
dvander@592
   142
	return NULL;
dvander@592
   143
}
dvander@592
   144
faluco@682
   145
typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name)
faluco@682
   146
{
faluco@682
   147
	while (pMap)
faluco@682
   148
	{
faluco@682
   149
		for (int i=0; i<pMap->dataNumFields; i++)
faluco@682
   150
		{
dvander@709
   151
			if (pMap->dataDesc[i].fieldName == NULL)
dvander@709
   152
			{
dvander@709
   153
				continue;
dvander@709
   154
			}
faluco@682
   155
			if (strcmp(name, pMap->dataDesc[i].fieldName) == 0)
faluco@682
   156
			{
faluco@682
   157
				return &(pMap->dataDesc[i]);
faluco@682
   158
			}
faluco@682
   159
			if (pMap->dataDesc[i].td)
faluco@682
   160
			{
faluco@682
   161
				typedescription_t *_td;
faluco@682
   162
				if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name)) != NULL)
faluco@682
   163
				{
faluco@682
   164
					return _td;
faluco@682
   165
				}
faluco@682
   166
			}
faluco@682
   167
		}
faluco@682
   168
		pMap = pMap->baseMap;
faluco@682
   169
	}
faluco@682
   170
faluco@682
   171
	return NULL; 
faluco@682
   172
}
faluco@682
   173
dvander@592
   174
ServerClass *CHalfLife2::FindServerClass(const char *classname)
dvander@592
   175
{
dvander@592
   176
	DataTableInfo *pInfo = _FindServerClass(classname);
dvander@592
   177
	if (!pInfo)
dvander@592
   178
	{
dvander@592
   179
		return NULL;
dvander@592
   180
	}
dvander@592
   181
dvander@592
   182
	return pInfo->sc;
dvander@592
   183
}
dvander@592
   184
dvander@592
   185
DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
dvander@592
   186
{
dvander@592
   187
	DataTableInfo *pInfo = NULL;
dvander@592
   188
dvander@592
   189
	if (!sm_trie_retrieve(m_pClasses, classname, (void **)&pInfo))
dvander@592
   190
	{
dvander@592
   191
		ServerClass *sc = gamedll->GetAllServerClasses();
dvander@592
   192
		while (sc)
dvander@592
   193
		{
dvander@592
   194
			if (strcmp(classname, sc->GetName()) == 0)
dvander@592
   195
			{
dvander@592
   196
				pInfo = new DataTableInfo;
dvander@592
   197
				pInfo->lookup = sm_trie_create();
dvander@592
   198
				pInfo->sc = sc;
dvander@592
   199
				sm_trie_insert(m_pClasses, classname, pInfo);
faluco@682
   200
				m_Tables.push_back(pInfo);
dvander@592
   201
				break;
dvander@592
   202
			}
dvander@592
   203
			sc = sc->m_pNext;
dvander@592
   204
		}
dvander@592
   205
		if (!pInfo)
dvander@592
   206
		{
dvander@592
   207
			return NULL;
dvander@592
   208
		}
dvander@592
   209
	}
dvander@592
   210
dvander@592
   211
	return pInfo;
dvander@592
   212
}
dvander@592
   213
dvander@592
   214
SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
dvander@592
   215
{
dvander@592
   216
	DataTableInfo *pInfo = _FindServerClass(classname);
dvander@592
   217
dvander@592
   218
	if (!pInfo)
dvander@592
   219
	{
dvander@592
   220
		return NULL;
dvander@592
   221
	}
dvander@592
   222
faluco@682
   223
	SendProp *pProp = NULL;
dvander@592
   224
	if (!sm_trie_retrieve(pInfo->lookup, offset, (void **)&pProp))
dvander@592
   225
	{
dvander@592
   226
		if ((pProp = UTIL_FindInSendTable(pInfo->sc->m_pTable, offset)) != NULL)
dvander@592
   227
		{
dvander@592
   228
			sm_trie_insert(pInfo->lookup, offset, pProp);
dvander@592
   229
		}
dvander@592
   230
	}
dvander@592
   231
dvander@592
   232
	return pProp;
dvander@592
   233
}
faluco@682
   234
faluco@682
   235
typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset)
faluco@682
   236
{
faluco@682
   237
	typedescription_t *td = NULL;
faluco@682
   238
	DataMapTrie &val = m_Maps[pMap];
faluco@682
   239
faluco@682
   240
	if (!val.trie)
faluco@682
   241
	{
faluco@682
   242
		val.trie = sm_trie_create();
faluco@682
   243
	}
faluco@682
   244
	if (!sm_trie_retrieve(val.trie, offset, (void **)&td))
faluco@682
   245
	{
faluco@682
   246
		if ((td = UTIL_FindInDataMap(pMap, offset)) != NULL)
faluco@682
   247
		{
faluco@682
   248
			sm_trie_insert(val.trie, offset, td);
faluco@682
   249
		}
faluco@682
   250
	}
faluco@682
   251
faluco@682
   252
	return td;
faluco@682
   253
}
dvander@685
   254
dvander@685
   255
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
dvander@685
   256
{
dvander@685
   257
	if (!g_IsOriginalEngine)
dvander@685
   258
	{
dvander@685
   259
		if (offset)
dvander@685
   260
		{
dvander@685
   261
			pEdict->StateChanged(offset);
dvander@685
   262
		} else {
dvander@685
   263
			pEdict->StateChanged();
dvander@685
   264
		}
dvander@685
   265
	} else {
dvander@685
   266
		pEdict->m_fStateFlags |= FL_EDICT_CHANGED;
dvander@685
   267
	}
dvander@685
   268
}
ds@873
   269
dvander@1132
   270
bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
ds@873
   271
{
ds@873
   272
	bf_write *pBitBuf = NULL;
ds@873
   273
	cell_t players[] = {client};
ds@873
   274
dvander@1132
   275
	if ((pBitBuf = g_UserMsgs.StartMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
dvander@1132
   276
	{
dvander@1132
   277
		return false;
dvander@1132
   278
	}
dvander@1132
   279
ds@873
   280
	pBitBuf->WriteByte(dest);
ds@873
   281
	pBitBuf->WriteString(msg);
ds@873
   282
	g_UserMsgs.EndMessage();
dvander@1132
   283
dvander@1132
   284
	return true;
ds@873
   285
}
faluco@1218
   286
teame06@1264
   287
bool CHalfLife2::HintTextMsg(int client, const char *msg)
faluco@1218
   288
{
faluco@1218
   289
	bf_write *pBitBuf = NULL;
faluco@1218
   290
	cell_t players[] = {client};
faluco@1218
   291
faluco@1218
   292
	if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
faluco@1218
   293
	{
faluco@1218
   294
		return false;
faluco@1218
   295
	}
faluco@1218
   296
faluco@1218
   297
	pBitBuf->WriteByte(1);
faluco@1218
   298
	pBitBuf->WriteString(msg);
faluco@1218
   299
	g_UserMsgs.EndMessage();
faluco@1218
   300
faluco@1218
   301
	return true;
faluco@1218
   302
}
faluco@1218
   303
faluco@1218
   304
bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show)
faluco@1218
   305
{
faluco@1218
   306
	bf_write *pBitBuf = NULL;
faluco@1218
   307
	KeyValues *SubKey = NULL;
faluco@1218
   308
	int count = 0;
faluco@1218
   309
	cell_t players[] = {client};
faluco@1218
   310
faluco@1218
   311
	if ((pBitBuf = g_UserMsgs.StartMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
faluco@1218
   312
	{
faluco@1218
   313
		return false;
faluco@1218
   314
	}
faluco@1218
   315
faluco@1218
   316
	if (data)
faluco@1218
   317
	{
faluco@1218
   318
		SubKey = data->GetFirstSubKey();
faluco@1218
   319
		while (SubKey)
faluco@1218
   320
		{
faluco@1218
   321
			count++;
faluco@1218
   322
			SubKey = SubKey->GetNextKey();
faluco@1218
   323
		}
faluco@1218
   324
		SubKey = data->GetFirstSubKey();
faluco@1218
   325
	}
faluco@1218
   326
faluco@1218
   327
	pBitBuf->WriteString(name);
faluco@1218
   328
	pBitBuf->WriteByte((show) ? 1 : 0);
faluco@1218
   329
	pBitBuf->WriteByte(count);
faluco@1218
   330
	while (SubKey)
faluco@1218
   331
	{
faluco@1218
   332
		pBitBuf->WriteString(SubKey->GetName());
faluco@1218
   333
		pBitBuf->WriteString(SubKey->GetString());
faluco@1218
   334
		SubKey = SubKey->GetNextKey();
faluco@1218
   335
	}
faluco@1218
   336
	g_UserMsgs.EndMessage();
faluco@1218
   337
faluco@1218
   338
	return true;
faluco@1218
   339
}
dvander@1338
   340
dvander@1338
   341
void CHalfLife2::AddToFakeCliCmdQueue(int client, int userid, const char *cmd)
dvander@1338
   342
{
dvander@1338
   343
	DelayedFakeCliCmd *pFake;
dvander@1338
   344
dvander@1338
   345
	if (m_FreeCmds.empty())
dvander@1338
   346
	{
dvander@1338
   347
		pFake = new DelayedFakeCliCmd;
dvander@1338
   348
	} else {
dvander@1338
   349
		pFake = m_FreeCmds.front();
dvander@1338
   350
		m_FreeCmds.pop();
dvander@1338
   351
	}
dvander@1338
   352
dvander@1338
   353
	pFake->client = client;
dvander@1338
   354
	pFake->userid = userid;
dvander@1338
   355
	pFake->cmd.assign(cmd);
dvander@1338
   356
dvander@1338
   357
	m_CmdQueue.push(pFake);
dvander@1338
   358
}
dvander@1338
   359
dvander@1338
   360
void CHalfLife2::ProcessFakeCliCmdQueue()
dvander@1338
   361
{
dvander@1338
   362
	while (!m_CmdQueue.empty())
dvander@1338
   363
	{
dvander@1338
   364
		DelayedFakeCliCmd *pFake = m_CmdQueue.first();
dvander@1338
   365
dvander@1338
   366
		if (g_Players.GetClientOfUserId(pFake->userid) == pFake->client)
dvander@1338
   367
		{
dvander@1338
   368
			CPlayer *pPlayer = g_Players.GetPlayerByIndex(pFake->client);
dvander@1338
   369
			serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), pFake->cmd.c_str());
dvander@1338
   370
		}
dvander@1338
   371
dvander@1338
   372
		m_CmdQueue.pop();
dvander@1338
   373
	}
dvander@1338
   374
}
dvander@1423
   375
dvander@1423
   376
bool CHalfLife2::IsLANServer()
dvander@1423
   377
{
dvander@1423
   378
	sv_lan = icvar->FindVar("sv_lan");
dvander@1423
   379
dvander@1423
   380
	if (!sv_lan)
dvander@1423
   381
	{
dvander@1423
   382
		return false;
dvander@1423
   383
	}
dvander@1423
   384
dvander@1423
   385
	return (sv_lan->GetInt() != 0);
dvander@1423
   386
}
dvander@1544
   387
dvander@1544
   388
void CHalfLife2::PushCommandStack(const CCommand *cmd)
dvander@1544
   389
{
dvander@1544
   390
	CachedCommandInfo info;
dvander@1544
   391
dvander@1544
   392
	info.args = cmd;
dvander@1544
   393
#if !defined ORANGEBOX_BUILD
dvander@1544
   394
	strncopy(info.cmd, cmd->Arg(0), sizeof(info.cmd));
dvander@1544
   395
#endif
dvander@1544
   396
dvander@1544
   397
	m_CommandStack.push(info);
dvander@1544
   398
}
dvander@1544
   399
dvander@1544
   400
const CCommand *CHalfLife2::PeekCommandStack()
dvander@1544
   401
{
dvander@1544
   402
	if (m_CommandStack.empty())
dvander@1544
   403
	{
dvander@1544
   404
		return NULL;
dvander@1544
   405
	}
dvander@1544
   406
dvander@1544
   407
	return m_CommandStack.front().args;
dvander@1544
   408
}
dvander@1544
   409
dvander@1544
   410
void CHalfLife2::PopCommandStack()
dvander@1544
   411
{
dvander@1544
   412
	m_CommandStack.pop();
dvander@1544
   413
}
dvander@1544
   414
dvander@1544
   415
const char *CHalfLife2::CurrentCommandName()
dvander@1544
   416
{
dvander@1544
   417
#if defined ORANGEBOX_BUILD
dvander@1544
   418
	return m_CommandStack.front().args->Arg(0);
dvander@1544
   419
#else
dvander@1544
   420
	return m_CommandStack.front().cmd;
dvander@1544
   421
#endif
dvander@1544
   422
}