core/HalfLife2.cpp
author Borja Ferrer <faluco@alliedmods.net>
Mon Jul 30 23:16:58 2007 +0000 (2007-07-30)
changeset 1218 a4e82ef4e7ef
parent 1132 e8d4e82e9541
child 1231 17badaf66ce4
permissions -rw-r--r--
added amb441, vguimenu and hinttext natives
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "HalfLife2.h"
    16 #include "sourcemod.h"
    17 #include "sourcemm_api.h"
    18 #include "UserMessages.h"
    19 
    20 CHalfLife2 g_HL2;
    21 bool g_IsOriginalEngine = false;
    22 
    23 namespace SourceHook
    24 {
    25 	template<>
    26 	int HashFunction<datamap_t *>(datamap_t * const &k)
    27 	{
    28 		return reinterpret_cast<int>(k);
    29 	}
    30 
    31 	template<>
    32 	int Compare<datamap_t *>(datamap_t * const &k1, datamap_t * const &k2)
    33 	{
    34 		return (k1-k2);
    35 	}
    36 }
    37 
    38 CHalfLife2::CHalfLife2()
    39 {
    40 	m_pClasses = sm_trie_create();
    41 }
    42 
    43 CHalfLife2::~CHalfLife2()
    44 {
    45 	sm_trie_destroy(m_pClasses);
    46 
    47 	List<DataTableInfo *>::iterator iter;
    48 	DataTableInfo *pInfo;
    49 	for (iter=m_Tables.begin(); iter!=m_Tables.end(); iter++)
    50 	{
    51 		pInfo = (*iter);
    52 		sm_trie_destroy(pInfo->lookup);
    53 		delete pInfo;
    54 	}
    55 
    56 	m_Tables.clear();
    57 
    58 	THash<datamap_t *, DataMapTrie>::iterator h_iter;
    59 	for (h_iter=m_Maps.begin(); h_iter!=m_Maps.end(); h_iter++)
    60 	{
    61 		if (h_iter->val.trie)
    62 		{
    63 			sm_trie_destroy(h_iter->val.trie);
    64 			h_iter->val.trie = NULL;
    65 		}
    66 	}
    67 
    68 	m_Maps.clear();
    69 }
    70 
    71 CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL;
    72 
    73 void CHalfLife2::OnSourceModStartup(bool late)
    74 {
    75 	/* The Ship currently is the only known game to use an older version of the engine */
    76 	if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
    77 	{
    78 		/* :TODO: Better engine versioning - perhaps something added to SourceMM? */
    79 		g_IsOriginalEngine = true;
    80 	} else if (!g_pSharedChangeInfo) {
    81 		g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo();
    82 	}
    83 }
    84 
    85 void CHalfLife2::OnSourceModAllInitialized()
    86 {
    87 	m_MsgTextMsg = g_UserMsgs.GetMessageIndex("TextMsg");
    88 	m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText");
    89 	m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu");
    90 	g_ShareSys.AddInterface(NULL, this);
    91 }
    92 
    93 IChangeInfoAccessor *CBaseEdict::GetChangeAccessor()
    94 {
    95 	return engine->GetChangeAccessor( (const edict_t *)this );
    96 }
    97 
    98 SendProp *UTIL_FindInSendTable(SendTable *pTable, const char *name)
    99 {
   100 	const char *pname;
   101 	int props = pTable->GetNumProps();
   102 	SendProp *prop;
   103 
   104 	for (int i=0; i<props; i++)
   105 	{
   106 		prop = pTable->GetProp(i);
   107 		pname = prop->GetName();
   108 		if (pname && strcmp(name, pname) == 0)
   109 		{
   110 			return prop;
   111 		}
   112 		if (prop->GetDataTable())
   113 		{
   114 			if ((prop=UTIL_FindInSendTable(prop->GetDataTable(), name)) != NULL)
   115 			{
   116 				return prop;
   117 			}
   118 		}
   119 	}
   120 
   121 	return NULL;
   122 }
   123 
   124 typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name)
   125 {
   126 	while (pMap)
   127 	{
   128 		for (int i=0; i<pMap->dataNumFields; i++)
   129 		{
   130 			if (pMap->dataDesc[i].fieldName == NULL)
   131 			{
   132 				continue;
   133 			}
   134 			if (strcmp(name, pMap->dataDesc[i].fieldName) == 0)
   135 			{
   136 				return &(pMap->dataDesc[i]);
   137 			}
   138 			if (pMap->dataDesc[i].td)
   139 			{
   140 				typedescription_t *_td;
   141 				if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name)) != NULL)
   142 				{
   143 					return _td;
   144 				}
   145 			}
   146 		}
   147 		pMap = pMap->baseMap;
   148 	}
   149 
   150 	return NULL; 
   151 }
   152 
   153 ServerClass *CHalfLife2::FindServerClass(const char *classname)
   154 {
   155 	DataTableInfo *pInfo = _FindServerClass(classname);
   156 	if (!pInfo)
   157 	{
   158 		return NULL;
   159 	}
   160 
   161 	return pInfo->sc;
   162 }
   163 
   164 DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
   165 {
   166 	DataTableInfo *pInfo = NULL;
   167 
   168 	if (!sm_trie_retrieve(m_pClasses, classname, (void **)&pInfo))
   169 	{
   170 		ServerClass *sc = gamedll->GetAllServerClasses();
   171 		while (sc)
   172 		{
   173 			if (strcmp(classname, sc->GetName()) == 0)
   174 			{
   175 				pInfo = new DataTableInfo;
   176 				pInfo->lookup = sm_trie_create();
   177 				pInfo->sc = sc;
   178 				sm_trie_insert(m_pClasses, classname, pInfo);
   179 				m_Tables.push_back(pInfo);
   180 				break;
   181 			}
   182 			sc = sc->m_pNext;
   183 		}
   184 		if (!pInfo)
   185 		{
   186 			return NULL;
   187 		}
   188 	}
   189 
   190 	return pInfo;
   191 }
   192 
   193 SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
   194 {
   195 	DataTableInfo *pInfo = _FindServerClass(classname);
   196 
   197 	if (!pInfo)
   198 	{
   199 		return NULL;
   200 	}
   201 
   202 	SendProp *pProp = NULL;
   203 	if (!sm_trie_retrieve(pInfo->lookup, offset, (void **)&pProp))
   204 	{
   205 		if ((pProp = UTIL_FindInSendTable(pInfo->sc->m_pTable, offset)) != NULL)
   206 		{
   207 			sm_trie_insert(pInfo->lookup, offset, pProp);
   208 		}
   209 	}
   210 
   211 	return pProp;
   212 }
   213 
   214 typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset)
   215 {
   216 	typedescription_t *td = NULL;
   217 	DataMapTrie &val = m_Maps[pMap];
   218 
   219 	if (!val.trie)
   220 	{
   221 		val.trie = sm_trie_create();
   222 	}
   223 	if (!sm_trie_retrieve(val.trie, offset, (void **)&td))
   224 	{
   225 		if ((td = UTIL_FindInDataMap(pMap, offset)) != NULL)
   226 		{
   227 			sm_trie_insert(val.trie, offset, td);
   228 		}
   229 	}
   230 
   231 	return td;
   232 }
   233 
   234 void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
   235 {
   236 	if (!g_IsOriginalEngine)
   237 	{
   238 		if (offset)
   239 		{
   240 			pEdict->StateChanged(offset);
   241 		} else {
   242 			pEdict->StateChanged();
   243 		}
   244 	} else {
   245 		pEdict->m_fStateFlags |= FL_EDICT_CHANGED;
   246 	}
   247 }
   248 
   249 bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
   250 {
   251 	bf_write *pBitBuf = NULL;
   252 	cell_t players[] = {client};
   253 
   254 	if ((pBitBuf = g_UserMsgs.StartMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
   255 	{
   256 		return false;
   257 	}
   258 
   259 	pBitBuf->WriteByte(dest);
   260 	pBitBuf->WriteString(msg);
   261 	g_UserMsgs.EndMessage();
   262 
   263 	return true;
   264 }
   265 
   266 bool CHalfLife2::HinTextMsg(int client, const char *msg)
   267 {
   268 	bf_write *pBitBuf = NULL;
   269 	cell_t players[] = {client};
   270 
   271 	if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
   272 	{
   273 		return false;
   274 	}
   275 
   276 	pBitBuf->WriteByte(1);
   277 	pBitBuf->WriteString(msg);
   278 	g_UserMsgs.EndMessage();
   279 
   280 	return true;
   281 }
   282 
   283 bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show)
   284 {
   285 	bf_write *pBitBuf = NULL;
   286 	KeyValues *SubKey = NULL;
   287 	int count = 0;
   288 	cell_t players[] = {client};
   289 
   290 	if ((pBitBuf = g_UserMsgs.StartMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
   291 	{
   292 		return false;
   293 	}
   294 
   295 	if (data)
   296 	{
   297 		SubKey = data->GetFirstSubKey();
   298 		while (SubKey)
   299 		{
   300 			count++;
   301 			SubKey = SubKey->GetNextKey();
   302 		}
   303 		SubKey = data->GetFirstSubKey();
   304 	}
   305 
   306 	pBitBuf->WriteString(name);
   307 	pBitBuf->WriteByte((show) ? 1 : 0);
   308 	pBitBuf->WriteByte(count);
   309 	while (SubKey)
   310 	{
   311 		pBitBuf->WriteString(SubKey->GetName());
   312 		pBitBuf->WriteString(SubKey->GetString());
   313 		SubKey = SubKey->GetNextKey();
   314 	}
   315 	g_UserMsgs.EndMessage();
   316 
   317 	return true;
   318 }