core/HalfLife2.cpp
author Borja Ferrer <faluco@alliedmods.net>
Fri Nov 16 21:34:29 2007 +0000 (2007-11-16)
changeset 1686 185cac1820fe
parent 1581 2562512b4a44
child 1690 7cc4f79a0416
permissions -rw-r--r--
fixed amb1164, SM was crashing due to interface changes from valve (this change is just to make the build update using the latest sdk)
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "HalfLife2.h"
    33 #include "sourcemod.h"
    34 #include "sourcemm_api.h"
    35 #include "UserMessages.h"
    36 #include "PlayerManager.h"
    37 #include "sm_stringutil.h"
    38 #include <compat_wrappers.h>
    39 
    40 CHalfLife2 g_HL2;
    41 ConVar *sv_lan = NULL;
    42 
    43 namespace SourceHook
    44 {
    45 	template<>
    46 	int HashFunction<datamap_t *>(datamap_t * const &k)
    47 	{
    48 		return reinterpret_cast<int>(k);
    49 	}
    50 
    51 	template<>
    52 	int Compare<datamap_t *>(datamap_t * const &k1, datamap_t * const &k2)
    53 	{
    54 		return (k1-k2);
    55 	}
    56 }
    57 
    58 CHalfLife2::CHalfLife2()
    59 {
    60 	m_pClasses = sm_trie_create();
    61 }
    62 
    63 CHalfLife2::~CHalfLife2()
    64 {
    65 	sm_trie_destroy(m_pClasses);
    66 
    67 	List<DataTableInfo *>::iterator iter;
    68 	DataTableInfo *pInfo;
    69 	for (iter=m_Tables.begin(); iter!=m_Tables.end(); iter++)
    70 	{
    71 		pInfo = (*iter);
    72 		sm_trie_destroy(pInfo->lookup);
    73 		delete pInfo;
    74 	}
    75 
    76 	m_Tables.clear();
    77 
    78 	THash<datamap_t *, DataMapTrie>::iterator h_iter;
    79 	for (h_iter=m_Maps.begin(); h_iter!=m_Maps.end(); h_iter++)
    80 	{
    81 		if (h_iter->val.trie)
    82 		{
    83 			sm_trie_destroy(h_iter->val.trie);
    84 			h_iter->val.trie = NULL;
    85 		}
    86 	}
    87 
    88 	m_Maps.clear();
    89 }
    90 
    91 CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL;
    92 bool is_original_engine = false;
    93 
    94 void CHalfLife2::OnSourceModStartup(bool late)
    95 {
    96 	/* The Ship currently is the only known game to use an older version of the engine */
    97 #if defined METAMOD_PLAPI_VERSION
    98 	if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL)
    99 #else
   100 	if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
   101 #endif
   102 	{
   103 		is_original_engine = true;
   104 	}
   105 	else if (g_pSharedChangeInfo == NULL)
   106 	{
   107 		g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo();
   108 	}
   109 }
   110 
   111 void CHalfLife2::OnSourceModAllInitialized()
   112 {
   113 	m_MsgTextMsg = g_UserMsgs.GetMessageIndex("TextMsg");
   114 	m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText");
   115 	m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu");
   116 	g_ShareSys.AddInterface(NULL, this);
   117 }
   118 
   119 #if !defined METAMOD_PLAPI_VERSION
   120 bool CHalfLife2::IsOriginalEngine()
   121 {
   122 	return is_original_engine;
   123 }
   124 #endif
   125 
   126 IChangeInfoAccessor *CBaseEdict::GetChangeAccessor()
   127 {
   128 	return engine->GetChangeAccessor( (const edict_t *)this );
   129 }
   130 
   131 SendProp *UTIL_FindInSendTable(SendTable *pTable, const char *name)
   132 {
   133 	const char *pname;
   134 	int props = pTable->GetNumProps();
   135 	SendProp *prop;
   136 
   137 	for (int i=0; i<props; i++)
   138 	{
   139 		prop = pTable->GetProp(i);
   140 		pname = prop->GetName();
   141 		if (pname && strcmp(name, pname) == 0)
   142 		{
   143 			return prop;
   144 		}
   145 		if (prop->GetDataTable())
   146 		{
   147 			if ((prop=UTIL_FindInSendTable(prop->GetDataTable(), name)) != NULL)
   148 			{
   149 				return prop;
   150 			}
   151 		}
   152 	}
   153 
   154 	return NULL;
   155 }
   156 
   157 typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name)
   158 {
   159 	while (pMap)
   160 	{
   161 		for (int i=0; i<pMap->dataNumFields; i++)
   162 		{
   163 			if (pMap->dataDesc[i].fieldName == NULL)
   164 			{
   165 				continue;
   166 			}
   167 			if (strcmp(name, pMap->dataDesc[i].fieldName) == 0)
   168 			{
   169 				return &(pMap->dataDesc[i]);
   170 			}
   171 			if (pMap->dataDesc[i].td)
   172 			{
   173 				typedescription_t *_td;
   174 				if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name)) != NULL)
   175 				{
   176 					return _td;
   177 				}
   178 			}
   179 		}
   180 		pMap = pMap->baseMap;
   181 	}
   182 
   183 	return NULL; 
   184 }
   185 
   186 ServerClass *CHalfLife2::FindServerClass(const char *classname)
   187 {
   188 	DataTableInfo *pInfo = _FindServerClass(classname);
   189 	if (!pInfo)
   190 	{
   191 		return NULL;
   192 	}
   193 
   194 	return pInfo->sc;
   195 }
   196 
   197 DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
   198 {
   199 	DataTableInfo *pInfo = NULL;
   200 
   201 	if (!sm_trie_retrieve(m_pClasses, classname, (void **)&pInfo))
   202 	{
   203 		ServerClass *sc = gamedll->GetAllServerClasses();
   204 		while (sc)
   205 		{
   206 			if (strcmp(classname, sc->GetName()) == 0)
   207 			{
   208 				pInfo = new DataTableInfo;
   209 				pInfo->lookup = sm_trie_create();
   210 				pInfo->sc = sc;
   211 				sm_trie_insert(m_pClasses, classname, pInfo);
   212 				m_Tables.push_back(pInfo);
   213 				break;
   214 			}
   215 			sc = sc->m_pNext;
   216 		}
   217 		if (!pInfo)
   218 		{
   219 			return NULL;
   220 		}
   221 	}
   222 
   223 	return pInfo;
   224 }
   225 
   226 SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
   227 {
   228 	DataTableInfo *pInfo = _FindServerClass(classname);
   229 
   230 	if (!pInfo)
   231 	{
   232 		return NULL;
   233 	}
   234 
   235 	SendProp *pProp = NULL;
   236 	if (!sm_trie_retrieve(pInfo->lookup, offset, (void **)&pProp))
   237 	{
   238 		if ((pProp = UTIL_FindInSendTable(pInfo->sc->m_pTable, offset)) != NULL)
   239 		{
   240 			sm_trie_insert(pInfo->lookup, offset, pProp);
   241 		}
   242 	}
   243 
   244 	return pProp;
   245 }
   246 
   247 typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset)
   248 {
   249 	typedescription_t *td = NULL;
   250 	DataMapTrie &val = m_Maps[pMap];
   251 
   252 	if (!val.trie)
   253 	{
   254 		val.trie = sm_trie_create();
   255 	}
   256 	if (!sm_trie_retrieve(val.trie, offset, (void **)&td))
   257 	{
   258 		if ((td = UTIL_FindInDataMap(pMap, offset)) != NULL)
   259 		{
   260 			sm_trie_insert(val.trie, offset, td);
   261 		}
   262 	}
   263 
   264 	return td;
   265 }
   266 
   267 void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
   268 {
   269 	if (g_pSharedChangeInfo != NULL)
   270 	{
   271 		if (offset)
   272 		{
   273 			pEdict->StateChanged(offset);
   274 		} else {
   275 			pEdict->StateChanged();
   276 		}
   277 	}
   278 	else
   279 	{
   280 		pEdict->m_fStateFlags |= FL_EDICT_CHANGED;
   281 	}
   282 }
   283 
   284 bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
   285 {
   286 	bf_write *pBitBuf = NULL;
   287 	cell_t players[] = {client};
   288 
   289 	if ((pBitBuf = g_UserMsgs.StartMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
   290 	{
   291 		return false;
   292 	}
   293 
   294 	pBitBuf->WriteByte(dest);
   295 	pBitBuf->WriteString(msg);
   296 	g_UserMsgs.EndMessage();
   297 
   298 	return true;
   299 }
   300 
   301 bool CHalfLife2::HintTextMsg(int client, const char *msg)
   302 {
   303 	bf_write *pBitBuf = NULL;
   304 	cell_t players[] = {client};
   305 
   306 	if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
   307 	{
   308 		return false;
   309 	}
   310 
   311 	pBitBuf->WriteByte(1);
   312 	pBitBuf->WriteString(msg);
   313 	g_UserMsgs.EndMessage();
   314 
   315 	return true;
   316 }
   317 
   318 bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show)
   319 {
   320 	bf_write *pBitBuf = NULL;
   321 	KeyValues *SubKey = NULL;
   322 	int count = 0;
   323 	cell_t players[] = {client};
   324 
   325 	if ((pBitBuf = g_UserMsgs.StartMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
   326 	{
   327 		return false;
   328 	}
   329 
   330 	if (data)
   331 	{
   332 		SubKey = data->GetFirstSubKey();
   333 		while (SubKey)
   334 		{
   335 			count++;
   336 			SubKey = SubKey->GetNextKey();
   337 		}
   338 		SubKey = data->GetFirstSubKey();
   339 	}
   340 
   341 	pBitBuf->WriteString(name);
   342 	pBitBuf->WriteByte((show) ? 1 : 0);
   343 	pBitBuf->WriteByte(count);
   344 	while (SubKey)
   345 	{
   346 		pBitBuf->WriteString(SubKey->GetName());
   347 		pBitBuf->WriteString(SubKey->GetString());
   348 		SubKey = SubKey->GetNextKey();
   349 	}
   350 	g_UserMsgs.EndMessage();
   351 
   352 	return true;
   353 }
   354 
   355 void CHalfLife2::AddToFakeCliCmdQueue(int client, int userid, const char *cmd)
   356 {
   357 	DelayedFakeCliCmd *pFake;
   358 
   359 	if (m_FreeCmds.empty())
   360 	{
   361 		pFake = new DelayedFakeCliCmd;
   362 	} else {
   363 		pFake = m_FreeCmds.front();
   364 		m_FreeCmds.pop();
   365 	}
   366 
   367 	pFake->client = client;
   368 	pFake->userid = userid;
   369 	pFake->cmd.assign(cmd);
   370 
   371 	m_CmdQueue.push(pFake);
   372 }
   373 
   374 void CHalfLife2::ProcessFakeCliCmdQueue()
   375 {
   376 	while (!m_CmdQueue.empty())
   377 	{
   378 		DelayedFakeCliCmd *pFake = m_CmdQueue.first();
   379 
   380 		if (g_Players.GetClientOfUserId(pFake->userid) == pFake->client)
   381 		{
   382 			CPlayer *pPlayer = g_Players.GetPlayerByIndex(pFake->client);
   383 			serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), pFake->cmd.c_str());
   384 		}
   385 
   386 		m_CmdQueue.pop();
   387 	}
   388 }
   389 
   390 bool CHalfLife2::IsLANServer()
   391 {
   392 	sv_lan = icvar->FindVar("sv_lan");
   393 
   394 	if (!sv_lan)
   395 	{
   396 		return false;
   397 	}
   398 
   399 	return (sv_lan->GetInt() != 0);
   400 }
   401 
   402 void CHalfLife2::PushCommandStack(const CCommand *cmd)
   403 {
   404 	CachedCommandInfo info;
   405 
   406 	info.args = cmd;
   407 #if !defined ORANGEBOX_BUILD
   408 	strncopy(info.cmd, cmd->Arg(0), sizeof(info.cmd));
   409 #endif
   410 
   411 	m_CommandStack.push(info);
   412 }
   413 
   414 const CCommand *CHalfLife2::PeekCommandStack()
   415 {
   416 	if (m_CommandStack.empty())
   417 	{
   418 		return NULL;
   419 	}
   420 
   421 	return m_CommandStack.front().args;
   422 }
   423 
   424 void CHalfLife2::PopCommandStack()
   425 {
   426 	m_CommandStack.pop();
   427 }
   428 
   429 const char *CHalfLife2::CurrentCommandName()
   430 {
   431 #if defined ORANGEBOX_BUILD
   432 	return m_CommandStack.front().args->Arg(0);
   433 #else
   434 	return m_CommandStack.front().cmd;
   435 #endif
   436 }