extensions/sdktools/tempents.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 4279 07c27b13d08b
permissions -rw-r--r--
Update CS:GO team score gamedata.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod SDKTools Extension
     5  * Copyright (C) 2004-2008 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 "tempents.h"
    33 
    34 TempEntityManager g_TEManager;
    35 ICallWrapper *g_GetServerClass = NULL;
    36 
    37 CON_COMMAND(sm_print_telist, "Prints the temp entity list")
    38 {
    39 	if (!g_TEManager.IsAvailable())
    40 	{
    41 		META_CONPRINT("The tempent portion of SDKTools failed to load.\n");
    42 		META_CONPRINT("Check that you have the latest sdktools.games.txt file!\n");
    43 		return;
    44 	}
    45 	g_TEManager.DumpList();
    46 }
    47 
    48 CON_COMMAND(sm_dump_teprops, "Dumps tempentity props to a file")
    49 {
    50 #if SOURCE_ENGINE <= SE_DARKMESSIAH
    51 	CCommand args;
    52 #endif
    53 	if (!g_TEManager.IsAvailable())
    54 	{
    55 		META_CONPRINT("The tempent portion of SDKTools failed to load.\n");
    56 		META_CONPRINT("Check that you have the latest sdktools.games.txt file!\n");
    57 		return;
    58 	}
    59 	int argc = args.ArgC();
    60 	if (argc < 2)
    61 	{
    62 		META_CONPRINT("Usage: sm_dump_teprops <file>\n");
    63 		return;
    64 	}
    65 
    66 	const char *arg = args.Arg(1);
    67 
    68 	if (!arg || arg[0] == '\0')
    69 	{
    70 		META_CONPRINTF("Usage: sm_dump_teprops <file>\n");
    71 		return;
    72 	}
    73 
    74 	char path[PLATFORM_MAX_PATH];
    75 	g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", arg);
    76 
    77 	FILE *fp = NULL;
    78 	if ((fp = fopen(path, "wt")) == NULL)
    79 	{
    80 		META_CONPRINTF("Could not open file \"%s\"\n", path);
    81 		return;
    82 	}
    83 
    84 	g_TEManager.DumpProps(fp);
    85 
    86 	fclose(fp);
    87 }
    88 
    89 /*************************
    90 *                        *
    91 * Temp Entities Wrappers *
    92 *                        *
    93 **************************/
    94 
    95 TempEntityInfo::TempEntityInfo(const char *name, void *me)
    96 {
    97 	m_Name.assign(name);
    98 	m_Me = me;
    99 	g_GetServerClass->Execute(&m_Me, &m_Sc);
   100 }
   101 
   102 const char *TempEntityInfo::GetName()
   103 {
   104 	return m_Name.c_str();
   105 }
   106 
   107 ServerClass *TempEntityInfo::GetServerClass()
   108 {
   109 	return m_Sc;
   110 }
   111 
   112 bool TempEntityInfo::IsValidProp(const char *name)
   113 {
   114 	return (g_pGameHelpers->FindInSendTable(m_Sc->GetName(), name)) ? true : false;
   115 }
   116 
   117 int TempEntityInfo::_FindOffset(const char *name, int *size)
   118 {
   119 	int offset;
   120 
   121 	sm_sendprop_info_t info;
   122 	if (!g_pGameHelpers->FindSendPropInfo(m_Sc->GetName(), name, &info))
   123 	{
   124 		return -1;
   125 	}
   126 
   127 	offset = info.actual_offset;
   128 	if (size)
   129 	{
   130 		*size = info.prop->m_nBits;
   131 	}
   132 
   133 	return offset;
   134 }
   135 
   136 bool TempEntityInfo::TE_SetEntData(const char *name, int value)
   137 {
   138 	/* Search for our offset */
   139 	int size;
   140 	int offset = _FindOffset(name, &size);
   141 
   142 	if (offset < 0)
   143 	{
   144 		return false;
   145 	}
   146 
   147 	if (size <= 8)
   148 	{
   149 		*((uint8_t *)m_Me + offset) = value;
   150 	} else if (size <= 16) {
   151 		*(short *)((uint8_t *)m_Me + offset) = value;
   152 	} else if (size <= 32) {
   153 		*(int *)((uint8_t *)m_Me + offset) = value;
   154 	} else {
   155 		return false;
   156 	}
   157 
   158 	return true;
   159 }
   160 
   161 bool TempEntityInfo::TE_GetEntData(const char *name, int *value)
   162 {
   163 	/* Search for our offset */
   164 	int size;
   165 	int offset = _FindOffset(name, &size);
   166 
   167 	if (offset < 0)
   168 	{
   169 		return false;
   170 	}
   171 
   172 	if (size <= 8)
   173 	{
   174 		*value = *((uint8_t *)m_Me + offset);
   175 	} else if (size <= 16) {
   176 		*value = *(short *)((uint8_t *)m_Me + offset);
   177 	} else if (size <= 32) {
   178 		*value = *(int *)((uint8_t *)m_Me + offset);
   179 	} else {
   180 		return false;
   181 	}
   182 
   183 	return true;
   184 }
   185 
   186 bool TempEntityInfo::TE_SetEntDataFloat(const char *name, float value)
   187 {
   188 	/* Search for our offset */
   189 	int offset = _FindOffset(name);
   190 
   191 	if (offset < 0)
   192 	{
   193 		return false;
   194 	}
   195 
   196 	*(float *)((uint8_t *)m_Me + offset) = value;
   197 
   198 	return true;
   199 }
   200 
   201 bool TempEntityInfo::TE_GetEntDataFloat(const char *name, float *value)
   202 {
   203 	/* Search for our offset */
   204 	int offset = _FindOffset(name);
   205 
   206 	if (offset < 0)
   207 	{
   208 		return false;
   209 	}
   210 
   211 	*value = *(float *)((uint8_t *)m_Me + offset);
   212 
   213 	return true;
   214 }
   215 
   216 bool TempEntityInfo::TE_SetEntDataVector(const char *name, float vector[3])
   217 {
   218 	/* Search for our offset */
   219 	int offset = _FindOffset(name);
   220 
   221 	if (offset < 0)
   222 	{
   223 		return false;
   224 	}
   225 
   226 	Vector *v = (Vector *)((uint8_t *)m_Me + offset);
   227 	v->x = vector[0];
   228 	v->y = vector[1];
   229 	v->z = vector[2];
   230 
   231 	return true;
   232 }
   233 
   234 bool TempEntityInfo::TE_GetEntDataVector(const char *name, float vector[3])
   235 {
   236 	/* Search for our offset */
   237 	int offset = _FindOffset(name);
   238 
   239 	if (offset < 0)
   240 	{
   241 		return false;
   242 	}
   243 
   244 	Vector *v = (Vector *)((uint8_t *)m_Me + offset);
   245 	vector[0] = v->x;
   246 	vector[1] = v->y;
   247 	vector[2] = v->z;
   248 
   249 	return true;
   250 }
   251 
   252 bool TempEntityInfo::TE_SetEntDataFloatArray(const char *name, cell_t *array, int size)
   253 {
   254 	/* Search for our offset */
   255 	int offset = _FindOffset(name);
   256 
   257 	if (offset < 0)
   258 	{
   259 		return false;
   260 	}
   261 
   262 	float *base = (float *)((uint8_t *)m_Me + offset);
   263 	for (int i=0; i<size; i++)
   264 	{
   265 		base[i] = sp_ctof(array[i]);
   266 	}
   267 
   268 	return true;
   269 }
   270 
   271 void TempEntityInfo::Send(IRecipientFilter &filter, float delay)
   272 {
   273 	engine->PlaybackTempEntity(filter, delay, m_Me, m_Sc->m_pTable, m_Sc->m_ClassID);
   274 }
   275 
   276 /**********************
   277 *                     *
   278 * Temp Entity Manager *
   279 *                     *
   280 ***********************/
   281 
   282 void TempEntityManager::Initialize()
   283 {
   284 	void *addr;
   285 	int offset;
   286 	m_Loaded = false;
   287 
   288 	/*
   289 	 * First try to lookup s_pTempEntities directly for platforms with symbols.
   290 	 * If symbols aren't present (Windows or stripped Linux/Mac), 
   291 	 * attempt find via CBaseTempEntity ctor + offset
   292 	 */
   293 
   294 	/* Read our sigs and offsets from the config file */
   295 	if (g_pGameConf->GetMemSig("s_pTempEntities", &addr) && addr)
   296 	{
   297 		
   298 		/* Store the head of the TE linked list */
   299 		m_ListHead = *(void **)addr;
   300 	}
   301 	else if (g_pGameConf->GetMemSig("CBaseTempEntity", &addr) && addr)
   302 	{
   303 		if (!g_pGameConf->GetOffset("s_pTempEntities", &offset))
   304 		{
   305 			return;
   306 		}
   307 		/* Store the head of the TE linked list */
   308 		m_ListHead = **(void ***)((unsigned char *)addr + offset);
   309 	}
   310 	else
   311 	{
   312 		return;
   313 	}
   314 
   315 	if (!g_pGameConf->GetOffset("GetTEName", &m_NameOffs))
   316 	{
   317 		return;
   318 	}
   319 	if (!g_pGameConf->GetOffset("GetTENext", &m_NextOffs))
   320 	{
   321 		return;
   322 	}
   323 	if (!g_pGameConf->GetOffset("TE_GetServerClass", &m_GetClassNameOffs))
   324 	{
   325 		return;
   326 	}
   327 
   328 	/* Create our trie */
   329 	m_TempEntInfo = adtfactory->CreateBasicTrie();
   330 
   331 	/* Create the GetServerClass call */
   332 	PassInfo retinfo;
   333 	retinfo.flags = PASSFLAG_BYVAL;
   334 	retinfo.type = PassType_Basic;
   335 	retinfo.size = sizeof(ServerClass *);
   336 	g_GetServerClass = g_pBinTools->CreateVCall(m_GetClassNameOffs, 0, 0, &retinfo, NULL, 0);
   337 
   338 	/* We're done */
   339 	m_Loaded = true;
   340 }
   341 
   342 bool TempEntityManager::IsAvailable()
   343 {
   344 	return m_Loaded;
   345 }
   346 
   347 void TempEntityManager::Shutdown()
   348 {
   349 	if (!IsAvailable())
   350 	{
   351 		return;
   352 	}
   353 
   354 	SourceHook::List<TempEntityInfo *>::iterator iter;
   355 	for (iter=m_TEList.begin(); iter!=m_TEList.end(); iter++)
   356 	{
   357 		delete (*iter);
   358 	}
   359 	m_TEList.clear();
   360 
   361 	m_TempEntInfo->Destroy();
   362 	g_GetServerClass->Destroy();
   363 	g_GetServerClass = NULL;
   364 	m_ListHead = NULL;
   365 	m_NextOffs = m_NameOffs = m_GetClassNameOffs = 0;
   366 	m_Loaded = false;
   367 }
   368 
   369 TempEntityInfo *TempEntityManager::GetTempEntityInfo(const char *name)
   370 {
   371 	/* If the system is unloaded skip the search */
   372 	if (!IsAvailable())
   373 	{
   374 		return NULL;
   375 	}
   376 
   377 	TempEntityInfo *te = NULL;
   378 
   379 	/* Start searching for the TE inside the engine */
   380 	if (!m_TempEntInfo->Retrieve(name, reinterpret_cast<void **>(&te)))
   381 	{
   382 		void *iter = m_ListHead;
   383 		while (iter)
   384 		{
   385 			const char *realname = *(const char **)((unsigned char *)iter + m_NameOffs);
   386 			if (!realname)
   387 			{
   388 				continue;
   389 			}
   390 			if (strcmp(name, realname) == 0)
   391 			{
   392 				te = new TempEntityInfo(name, iter);
   393 				m_TempEntInfo->Insert(name, (void *)te);
   394 				m_TEList.push_back(te);
   395 				return te;
   396 			}
   397 			iter = *(void **)((unsigned char *)iter + m_NextOffs);
   398 		}
   399 		return NULL;
   400 	}
   401 
   402 	return te;
   403 }
   404 
   405 const char *TempEntityManager::GetNameFromThisPtr(void *me)
   406 {
   407 	return *(const char **)((unsigned char *)me + m_NameOffs);
   408 }
   409 
   410 void TempEntityManager::DumpList()
   411 {
   412 	unsigned int index = 0;
   413 	META_CONPRINT("Listing temp entities:\n");
   414 	void *iter = m_ListHead;
   415 	while (iter)
   416 	{
   417 		const char *realname = *(const char **)((unsigned char *)iter + m_NameOffs);
   418 		if (!realname)
   419 		{
   420 			break;
   421 		}
   422 		TempEntityInfo *info = GetTempEntityInfo(realname);
   423 		if (!info)
   424 		{
   425 			continue;
   426 		}
   427 		ServerClass *sc = info->GetServerClass();
   428 		META_CONPRINTF("[%02d] %s (%s)\n", index++, realname, sc->GetName());
   429 		iter = *(void **)((unsigned char *)iter + m_NextOffs);
   430 	}
   431 	META_CONPRINTF("%d tempent%s found.\n", index, (index == 1) ? " was" : "s were");
   432 }
   433 
   434 const char *SendPropTypeToString(SendPropType type)
   435 {
   436 	if (type == DPT_Int)
   437 	{
   438 		return "int";
   439 	} else if (type == DPT_Float) {
   440 		return "float";
   441 	} else if (type == DPT_Vector) {
   442 		return "vector";
   443 	} else if (type == DPT_String) {
   444 		return "string";
   445 	} else if (type == DPT_Array) {
   446 		return "array";
   447 	} else if (type == DPT_DataTable) {
   448 		return "datatable";
   449 	} else {
   450 		return "unknown";
   451 	}
   452 }
   453 
   454 void _DumpProps(FILE *fp, SendTable *pTable)
   455 {
   456 	SendTable *pOther;
   457 	for (int i=0; i<pTable->GetNumProps(); i++)
   458 	{
   459 		SendProp *prop = pTable->GetProp(i);
   460 		if ((pOther = prop->GetDataTable()) != NULL)
   461 		{
   462 			_DumpProps(fp, pOther);
   463 		} else {
   464 			fprintf(fp, "\t\t\t\"%s\"\t\t\"%s\"\n", 
   465 				prop->GetName() ? prop->GetName() : "unknown",
   466 				SendPropTypeToString(prop->GetType()));
   467 		}
   468 	}
   469 }
   470 
   471 void TempEntityManager::DumpProps(FILE *fp)
   472 {
   473 	unsigned int index = 0;
   474 	void *iter = m_ListHead;
   475 	fprintf(fp, "\"TempEnts\"\n{\n");
   476 	while (iter)
   477 	{
   478 		const char *realname = *(const char **)((unsigned char *)iter + m_NameOffs);
   479 		if (!realname)
   480 		{
   481 			break;
   482 		}
   483 		TempEntityInfo *info = GetTempEntityInfo(realname);
   484 		if (!info)
   485 		{
   486 			continue;
   487 		}
   488 		ServerClass *sc = info->GetServerClass();
   489 		fprintf(fp, "\t\"%s\"\n", sc->GetName());
   490 		fprintf(fp, "\t{\n");
   491 		fprintf(fp, "\t\t\"name\"\t\t\"%s\"\n", realname);
   492 		fprintf(fp, "\t\t\"index\"\t\t\"%d\"\n", index++);
   493 		fprintf(fp, "\t\t\"SendTable\"\n\t\t{\n");
   494 		_DumpProps(fp, sc->m_pTable);
   495 		fprintf(fp, "\t\t}\n\t}\n");
   496 		iter = *(void **)((unsigned char *)iter + m_NextOffs);
   497 	}
   498 	fprintf(fp, "}\n");
   499 	META_CONPRINTF("%d tempent%s written to file.\n", index, (index == 1) ? " was" : "s were");
   500 }