core/HalfLife2.cpp
author David Anderson <dvander@alliedmods.net>
Sun Aug 19 18:34:36 2007 +0000 (2007-08-19)
changeset 1361 591f6d2fd11d
parent 1338 1ba17552b7b1
child 1423 e73b3563f254
permissions -rw-r--r--
added helper function for panel text
     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 
    38 CHalfLife2 g_HL2;
    39 bool g_IsOriginalEngine = false;
    40 
    41 namespace SourceHook
    42 {
    43 	template<>
    44 	int HashFunction<datamap_t *>(datamap_t * const &k)
    45 	{
    46 		return reinterpret_cast<int>(k);
    47 	}
    48 
    49 	template<>
    50 	int Compare<datamap_t *>(datamap_t * const &k1, datamap_t * const &k2)
    51 	{
    52 		return (k1-k2);
    53 	}
    54 }
    55 
    56 CHalfLife2::CHalfLife2()
    57 {
    58 	m_pClasses = sm_trie_create();
    59 }
    60 
    61 CHalfLife2::~CHalfLife2()
    62 {
    63 	sm_trie_destroy(m_pClasses);
    64 
    65 	List<DataTableInfo *>::iterator iter;
    66 	DataTableInfo *pInfo;
    67 	for (iter=m_Tables.begin(); iter!=m_Tables.end(); iter++)
    68 	{
    69 		pInfo = (*iter);
    70 		sm_trie_destroy(pInfo->lookup);
    71 		delete pInfo;
    72 	}
    73 
    74 	m_Tables.clear();
    75 
    76 	THash<datamap_t *, DataMapTrie>::iterator h_iter;
    77 	for (h_iter=m_Maps.begin(); h_iter!=m_Maps.end(); h_iter++)
    78 	{
    79 		if (h_iter->val.trie)
    80 		{
    81 			sm_trie_destroy(h_iter->val.trie);
    82 			h_iter->val.trie = NULL;
    83 		}
    84 	}
    85 
    86 	m_Maps.clear();
    87 }
    88 
    89 CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL;
    90 
    91 void CHalfLife2::OnSourceModStartup(bool late)
    92 {
    93 	/* The Ship currently is the only known game to use an older version of the engine */
    94 	if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
    95 	{
    96 		/* :TODO: Better engine versioning - perhaps something added to SourceMM? */
    97 		g_IsOriginalEngine = true;
    98 	} else if (!g_pSharedChangeInfo) {
    99 		g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo();
   100 	}
   101 }
   102 
   103 void CHalfLife2::OnSourceModAllInitialized()
   104 {
   105 	m_MsgTextMsg = g_UserMsgs.GetMessageIndex("TextMsg");
   106 	m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText");
   107 	m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu");
   108 	g_ShareSys.AddInterface(NULL, this);
   109 }
   110 
   111 IChangeInfoAccessor *CBaseEdict::GetChangeAccessor()
   112 {
   113 	return engine->GetChangeAccessor( (const edict_t *)this );
   114 }
   115 
   116 SendProp *UTIL_FindInSendTable(SendTable *pTable, const char *name)
   117 {
   118 	const char *pname;
   119 	int props = pTable->GetNumProps();
   120 	SendProp *prop;
   121 
   122 	for (int i=0; i<props; i++)
   123 	{
   124 		prop = pTable->GetProp(i);
   125 		pname = prop->GetName();
   126 		if (pname && strcmp(name, pname) == 0)
   127 		{
   128 			return prop;
   129 		}
   130 		if (prop->GetDataTable())
   131 		{
   132 			if ((prop=UTIL_FindInSendTable(prop->GetDataTable(), name)) != NULL)
   133 			{
   134 				return prop;
   135 			}
   136 		}
   137 	}
   138 
   139 	return NULL;
   140 }
   141 
   142 typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name)
   143 {
   144 	while (pMap)
   145 	{
   146 		for (int i=0; i<pMap->dataNumFields; i++)
   147 		{
   148 			if (pMap->dataDesc[i].fieldName == NULL)
   149 			{
   150 				continue;
   151 			}
   152 			if (strcmp(name, pMap->dataDesc[i].fieldName) == 0)
   153 			{
   154 				return &(pMap->dataDesc[i]);
   155 			}
   156 			if (pMap->dataDesc[i].td)
   157 			{
   158 				typedescription_t *_td;
   159 				if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name)) != NULL)
   160 				{
   161 					return _td;
   162 				}
   163 			}
   164 		}
   165 		pMap = pMap->baseMap;
   166 	}
   167 
   168 	return NULL; 
   169 }
   170 
   171 ServerClass *CHalfLife2::FindServerClass(const char *classname)
   172 {
   173 	DataTableInfo *pInfo = _FindServerClass(classname);
   174 	if (!pInfo)
   175 	{
   176 		return NULL;
   177 	}
   178 
   179 	return pInfo->sc;
   180 }
   181 
   182 DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
   183 {
   184 	DataTableInfo *pInfo = NULL;
   185 
   186 	if (!sm_trie_retrieve(m_pClasses, classname, (void **)&pInfo))
   187 	{
   188 		ServerClass *sc = gamedll->GetAllServerClasses();
   189 		while (sc)
   190 		{
   191 			if (strcmp(classname, sc->GetName()) == 0)
   192 			{
   193 				pInfo = new DataTableInfo;
   194 				pInfo->lookup = sm_trie_create();
   195 				pInfo->sc = sc;
   196 				sm_trie_insert(m_pClasses, classname, pInfo);
   197 				m_Tables.push_back(pInfo);
   198 				break;
   199 			}
   200 			sc = sc->m_pNext;
   201 		}
   202 		if (!pInfo)
   203 		{
   204 			return NULL;
   205 		}
   206 	}
   207 
   208 	return pInfo;
   209 }
   210 
   211 SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
   212 {
   213 	DataTableInfo *pInfo = _FindServerClass(classname);
   214 
   215 	if (!pInfo)
   216 	{
   217 		return NULL;
   218 	}
   219 
   220 	SendProp *pProp = NULL;
   221 	if (!sm_trie_retrieve(pInfo->lookup, offset, (void **)&pProp))
   222 	{
   223 		if ((pProp = UTIL_FindInSendTable(pInfo->sc->m_pTable, offset)) != NULL)
   224 		{
   225 			sm_trie_insert(pInfo->lookup, offset, pProp);
   226 		}
   227 	}
   228 
   229 	return pProp;
   230 }
   231 
   232 typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset)
   233 {
   234 	typedescription_t *td = NULL;
   235 	DataMapTrie &val = m_Maps[pMap];
   236 
   237 	if (!val.trie)
   238 	{
   239 		val.trie = sm_trie_create();
   240 	}
   241 	if (!sm_trie_retrieve(val.trie, offset, (void **)&td))
   242 	{
   243 		if ((td = UTIL_FindInDataMap(pMap, offset)) != NULL)
   244 		{
   245 			sm_trie_insert(val.trie, offset, td);
   246 		}
   247 	}
   248 
   249 	return td;
   250 }
   251 
   252 void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
   253 {
   254 	if (!g_IsOriginalEngine)
   255 	{
   256 		if (offset)
   257 		{
   258 			pEdict->StateChanged(offset);
   259 		} else {
   260 			pEdict->StateChanged();
   261 		}
   262 	} else {
   263 		pEdict->m_fStateFlags |= FL_EDICT_CHANGED;
   264 	}
   265 }
   266 
   267 bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
   268 {
   269 	bf_write *pBitBuf = NULL;
   270 	cell_t players[] = {client};
   271 
   272 	if ((pBitBuf = g_UserMsgs.StartMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
   273 	{
   274 		return false;
   275 	}
   276 
   277 	pBitBuf->WriteByte(dest);
   278 	pBitBuf->WriteString(msg);
   279 	g_UserMsgs.EndMessage();
   280 
   281 	return true;
   282 }
   283 
   284 bool CHalfLife2::HintTextMsg(int client, const char *msg)
   285 {
   286 	bf_write *pBitBuf = NULL;
   287 	cell_t players[] = {client};
   288 
   289 	if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
   290 	{
   291 		return false;
   292 	}
   293 
   294 	pBitBuf->WriteByte(1);
   295 	pBitBuf->WriteString(msg);
   296 	g_UserMsgs.EndMessage();
   297 
   298 	return true;
   299 }
   300 
   301 bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show)
   302 {
   303 	bf_write *pBitBuf = NULL;
   304 	KeyValues *SubKey = NULL;
   305 	int count = 0;
   306 	cell_t players[] = {client};
   307 
   308 	if ((pBitBuf = g_UserMsgs.StartMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
   309 	{
   310 		return false;
   311 	}
   312 
   313 	if (data)
   314 	{
   315 		SubKey = data->GetFirstSubKey();
   316 		while (SubKey)
   317 		{
   318 			count++;
   319 			SubKey = SubKey->GetNextKey();
   320 		}
   321 		SubKey = data->GetFirstSubKey();
   322 	}
   323 
   324 	pBitBuf->WriteString(name);
   325 	pBitBuf->WriteByte((show) ? 1 : 0);
   326 	pBitBuf->WriteByte(count);
   327 	while (SubKey)
   328 	{
   329 		pBitBuf->WriteString(SubKey->GetName());
   330 		pBitBuf->WriteString(SubKey->GetString());
   331 		SubKey = SubKey->GetNextKey();
   332 	}
   333 	g_UserMsgs.EndMessage();
   334 
   335 	return true;
   336 }
   337 
   338 void CHalfLife2::AddToFakeCliCmdQueue(int client, int userid, const char *cmd)
   339 {
   340 	DelayedFakeCliCmd *pFake;
   341 
   342 	if (m_FreeCmds.empty())
   343 	{
   344 		pFake = new DelayedFakeCliCmd;
   345 	} else {
   346 		pFake = m_FreeCmds.front();
   347 		m_FreeCmds.pop();
   348 	}
   349 
   350 	pFake->client = client;
   351 	pFake->userid = userid;
   352 	pFake->cmd.assign(cmd);
   353 
   354 	m_CmdQueue.push(pFake);
   355 }
   356 
   357 void CHalfLife2::ProcessFakeCliCmdQueue()
   358 {
   359 	while (!m_CmdQueue.empty())
   360 	{
   361 		DelayedFakeCliCmd *pFake = m_CmdQueue.first();
   362 
   363 		if (g_Players.GetClientOfUserId(pFake->userid) == pFake->client)
   364 		{
   365 			CPlayer *pPlayer = g_Players.GetPlayerByIndex(pFake->client);
   366 			serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), pFake->cmd.c_str());
   367 		}
   368 
   369 		m_CmdQueue.pop();
   370 	}
   371 }