extensions/sdktools/tempents.cpp
author Fyren <fyrenmoo@gmail.com>
Mon May 11 18:46:19 2009 -0700 (2009-05-11)
changeset 2710 3bf47c5fa143
parent 2583 d3b2571c378b
child 3221 ca0e525dcf86
permissions -rw-r--r--
Some sdktools string and style changes (r=pred)
     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 	SendProp *prop = g_pGameHelpers->FindInSendTable(m_Sc->GetName(), name);
   122 	if (!prop)
   123 	{
   124 		return -1;
   125 	}
   126 
   127 	offset = prop->GetOffset();
   128 	if (size)
   129 	{
   130 		*size = 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 	/* Read our sigs and offsets from the config file */
   289 #if defined PLATFORM_WINDOWS
   290 	if (!g_pGameConf->GetMemSig("CBaseTempEntity", &addr) || !addr)
   291 	{
   292 		return;
   293 	}
   294 	if (!g_pGameConf->GetOffset("s_pTempEntities", &offset))
   295 	{
   296 		return;
   297 	}
   298 	/* Store the head of the TE linked list */
   299 	m_ListHead = **(void ***)((unsigned char *)addr + offset);
   300 #else
   301 	if (!g_pGameConf->GetMemSig("s_pTempEntities", &addr) || !addr)
   302 	{
   303 		return;
   304 	}
   305 	/* Store the head of the TE linked list */
   306 	m_ListHead = *(void **)addr;
   307 #endif
   308 	if (!g_pGameConf->GetOffset("GetTEName", &m_NameOffs))
   309 	{
   310 		return;
   311 	}
   312 	if (!g_pGameConf->GetOffset("GetTENext", &m_NextOffs))
   313 	{
   314 		return;
   315 	}
   316 	if (!g_pGameConf->GetOffset("TE_GetServerClass", &m_GetClassNameOffs))
   317 	{
   318 		return;
   319 	}
   320 
   321 	/* Create our trie */
   322 	m_TempEntInfo = adtfactory->CreateBasicTrie();
   323 
   324 	/* Create the GetServerClass call */
   325 	PassInfo retinfo;
   326 	retinfo.flags = PASSFLAG_BYVAL;
   327 	retinfo.type = PassType_Basic;
   328 	retinfo.size = sizeof(ServerClass *);
   329 	g_GetServerClass = g_pBinTools->CreateVCall(m_GetClassNameOffs, 0, 0, &retinfo, NULL, 0);
   330 
   331 	/* We're done */
   332 	m_Loaded = true;
   333 }
   334 
   335 bool TempEntityManager::IsAvailable()
   336 {
   337 	return m_Loaded;
   338 }
   339 
   340 void TempEntityManager::Shutdown()
   341 {
   342 	if (!IsAvailable())
   343 	{
   344 		return;
   345 	}
   346 
   347 	SourceHook::List<TempEntityInfo *>::iterator iter;
   348 	for (iter=m_TEList.begin(); iter!=m_TEList.end(); iter++)
   349 	{
   350 		delete (*iter);
   351 	}
   352 	m_TEList.clear();
   353 
   354 	m_TempEntInfo->Destroy();
   355 	g_GetServerClass->Destroy();
   356 	g_GetServerClass = NULL;
   357 	m_ListHead = NULL;
   358 	m_NextOffs = m_NameOffs = m_GetClassNameOffs = 0;
   359 	m_Loaded = false;
   360 }
   361 
   362 TempEntityInfo *TempEntityManager::GetTempEntityInfo(const char *name)
   363 {
   364 	/* If the system is unloaded skip the search */
   365 	if (!IsAvailable())
   366 	{
   367 		return NULL;
   368 	}
   369 
   370 	TempEntityInfo *te = NULL;
   371 
   372 	/* Start searching for the TE inside the engine */
   373 	if (!m_TempEntInfo->Retrieve(name, reinterpret_cast<void **>(&te)))
   374 	{
   375 		void *iter = m_ListHead;
   376 		while (iter)
   377 		{
   378 			const char *realname = *(const char **)((unsigned char *)iter + m_NameOffs);
   379 			if (!realname)
   380 			{
   381 				continue;
   382 			}
   383 			if (strcmp(name, realname) == 0)
   384 			{
   385 				te = new TempEntityInfo(name, iter);
   386 				m_TempEntInfo->Insert(name, (void *)te);
   387 				m_TEList.push_back(te);
   388 				return te;
   389 			}
   390 			iter = *(void **)((unsigned char *)iter + m_NextOffs);
   391 		}
   392 		return NULL;
   393 	}
   394 
   395 	return te;
   396 }
   397 
   398 const char *TempEntityManager::GetNameFromThisPtr(void *me)
   399 {
   400 	return *(const char **)((unsigned char *)me + m_NameOffs);
   401 }
   402 
   403 void TempEntityManager::DumpList()
   404 {
   405 	unsigned int index = 0;
   406 	META_CONPRINT("Listing temp entities:\n");
   407 	void *iter = m_ListHead;
   408 	while (iter)
   409 	{
   410 		const char *realname = *(const char **)((unsigned char *)iter + m_NameOffs);
   411 		if (!realname)
   412 		{
   413 			break;
   414 		}
   415 		TempEntityInfo *info = GetTempEntityInfo(realname);
   416 		if (!info)
   417 		{
   418 			continue;
   419 		}
   420 		ServerClass *sc = info->GetServerClass();
   421 		META_CONPRINTF("[%02d] %s (%s)\n", index++, realname, sc->GetName());
   422 		iter = *(void **)((unsigned char *)iter + m_NextOffs);
   423 	}
   424 	META_CONPRINTF("%d tempent%s found.\n", index, (index == 1) ? " was" : "s were");
   425 }
   426 
   427 const char *SendPropTypeToString(SendPropType type)
   428 {
   429 	if (type == DPT_Int)
   430 	{
   431 		return "int";
   432 	} else if (type == DPT_Float) {
   433 		return "float";
   434 	} else if (type == DPT_Vector) {
   435 		return "vector";
   436 	} else if (type == DPT_String) {
   437 		return "string";
   438 	} else if (type == DPT_Array) {
   439 		return "array";
   440 	} else if (type == DPT_DataTable) {
   441 		return "datatable";
   442 	} else {
   443 		return "unknown";
   444 	}
   445 }
   446 
   447 void _DumpProps(FILE *fp, SendTable *pTable)
   448 {
   449 	SendTable *pOther;
   450 	for (int i=0; i<pTable->GetNumProps(); i++)
   451 	{
   452 		SendProp *prop = pTable->GetProp(i);
   453 		if ((pOther = prop->GetDataTable()) != NULL)
   454 		{
   455 			_DumpProps(fp, pOther);
   456 		} else {
   457 			fprintf(fp, "\t\t\t\"%s\"\t\t\"%s\"\n", 
   458 				prop->GetName() ? prop->GetName() : "unknown",
   459 				SendPropTypeToString(prop->GetType()));
   460 		}
   461 	}
   462 }
   463 
   464 void TempEntityManager::DumpProps(FILE *fp)
   465 {
   466 	unsigned int index = 0;
   467 	void *iter = m_ListHead;
   468 	fprintf(fp, "\"TempEnts\"\n{\n");
   469 	while (iter)
   470 	{
   471 		const char *realname = *(const char **)((unsigned char *)iter + m_NameOffs);
   472 		if (!realname)
   473 		{
   474 			break;
   475 		}
   476 		TempEntityInfo *info = GetTempEntityInfo(realname);
   477 		if (!info)
   478 		{
   479 			continue;
   480 		}
   481 		ServerClass *sc = info->GetServerClass();
   482 		fprintf(fp, "\t\"%s\"\n", sc->GetName());
   483 		fprintf(fp, "\t{\n");
   484 		fprintf(fp, "\t\t\"name\"\t\t\"%s\"\n", realname);
   485 		fprintf(fp, "\t\t\"index\"\t\t\"%d\"\n", index++);
   486 		fprintf(fp, "\t\t\"SendTable\"\n\t\t{\n");
   487 		_DumpProps(fp, sc->m_pTable);
   488 		fprintf(fp, "\t\t}\n\t}\n");
   489 		iter = *(void **)((unsigned char *)iter + m_NextOffs);
   490 	}
   491 	fprintf(fp, "}\n");
   492 	META_CONPRINTF("%d tempent%s written to file.\n", index, (index == 1) ? " was" : "s were");
   493 }