extensions/sdktools/tempents.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Mar 30 07:00:22 2008 +0000 (2008-03-30)
changeset 1952 b7aa2b626807
child 2289 44045ead61cd
permissions -rw-r--r--
Spring Cleaning, Part Ichi (1)
Various minor things done to project files
Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way)
Updated regex project file and makefile
     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 !defined ORANGEBOX_BUILD
    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 }