extensions/sdktools/vhelpers.cpp
author Asher Baker <asherkin@gmail.com>
Wed Aug 22 23:23:31 2012 +0100 (2012-08-22)
changeset 3623 3fd87cb487f8
parent 3333 e247490894a1
child 3686 d7954e074526
permissions -rw-r--r--
Updated cstrike gamedata.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod SDKTools Extension
     5  * Copyright (C) 2004-2010 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 "extension.h"
    33 #include "util.h"
    34 #include "vhelpers.h"
    35 #include "vglobals.h"
    36 
    37 CallHelper s_Teleport;
    38 CallHelper s_GetVelocity;
    39 CallHelper s_EyeAngles;
    40 
    41 class CTraceFilterSimple : public CTraceFilterEntitiesOnly
    42 {
    43 public:
    44 	CTraceFilterSimple(const IHandleEntity *passentity): m_pPassEnt(passentity)
    45 	{
    46 	}
    47 	virtual bool ShouldHitEntity(IHandleEntity *pServerEntity, int contentsMask)
    48 	{
    49 		if (pServerEntity == m_pPassEnt)
    50 		{
    51 			return false;
    52 		}
    53 		return true;
    54 	}
    55 private:
    56 	const IHandleEntity *m_pPassEnt;
    57 };
    58 
    59 bool SetupTeleport()
    60 {
    61 	if (s_Teleport.setup)
    62 	{
    63 		return s_Teleport.supported;
    64 	}
    65 
    66 	/* Setup Teleport */
    67 	int offset;
    68 	if (g_pGameConf->GetOffset("Teleport", &offset))
    69 	{
    70 		PassInfo info[3];
    71 		info[0].flags = info[1].flags = info[2].flags = PASSFLAG_BYVAL;
    72 		info[0].size = info[1].size = info[2].size = sizeof(void *);
    73 		info[0].type = info[1].type = info[2].type = PassType_Basic;
    74 
    75 		s_Teleport.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 3);
    76 
    77 		if (s_Teleport.call != NULL)
    78 		{
    79 			s_Teleport.supported = true;
    80 		}
    81 	}
    82 
    83 	s_Teleport.setup = true;
    84 
    85 	return s_Teleport.supported;
    86 }
    87 
    88 void Teleport(CBaseEntity *pEntity, Vector *origin, QAngle *ang, Vector *velocity)
    89 {
    90 	unsigned char params[sizeof(void *) * 4];
    91 	unsigned char *vptr = params;
    92 	*(CBaseEntity **)vptr = pEntity;
    93 	vptr += sizeof(CBaseEntity *);
    94 	*(Vector **)vptr = origin;
    95 	vptr += sizeof(Vector *);
    96 	*(QAngle **)vptr = ang;
    97 	vptr += sizeof(QAngle *);
    98 	*(Vector **)vptr = velocity;
    99 	
   100 	s_Teleport.call->Execute(params, NULL);
   101 }
   102 
   103 bool IsTeleportSupported()
   104 {
   105 	return SetupTeleport();
   106 }
   107 
   108 bool SetupGetVelocity()
   109 {
   110 	if (s_GetVelocity.setup)
   111 	{
   112 		return s_GetVelocity.supported;
   113 	}
   114 
   115 	int offset;
   116 	if (g_pGameConf->GetOffset("GetVelocity", &offset))
   117 	{
   118 		PassInfo info[2];
   119 		info[0].flags = info[1].flags = PASSFLAG_BYVAL;
   120 		info[0].size = info[1].size = sizeof(void *);
   121 		info[0].type = info[1].type = PassType_Basic;
   122 
   123 		s_GetVelocity.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 2);
   124 
   125 		if (s_GetVelocity.call != NULL)
   126 		{
   127 			s_GetVelocity.supported = true;
   128 		}
   129 	}
   130 
   131 	s_GetVelocity.setup = true;
   132 
   133 	return s_GetVelocity.supported;
   134 }
   135 
   136 void GetVelocity(CBaseEntity *pEntity, Vector *velocity, AngularImpulse *angvelocity)
   137 {
   138 	unsigned char params[sizeof(void *) * 3];
   139 	unsigned char *vptr = params;
   140 	*(CBaseEntity **)vptr = pEntity;
   141 	vptr += sizeof(CBaseEntity *);
   142 	*(Vector **)vptr = velocity;
   143 	vptr += sizeof(Vector *);
   144 	*(AngularImpulse **)vptr = angvelocity;
   145 
   146 	s_GetVelocity.call->Execute(params, NULL);
   147 }
   148 
   149 bool IsGetVelocitySupported()
   150 {
   151 	return SetupGetVelocity();
   152 }
   153 
   154 bool SetupGetEyeAngles()
   155 {
   156 	if (s_EyeAngles.setup)
   157 	{
   158 		return s_EyeAngles.supported;
   159 	}
   160 
   161 	int offset;
   162 	if (g_pGameConf->GetOffset("EyeAngles", &offset))
   163 	{
   164 		PassInfo info[1];
   165 		info[0].flags = PASSFLAG_BYVAL;
   166 		info[0].size = sizeof(void *);
   167 		info[0].type = PassType_Basic;
   168 
   169 		s_EyeAngles.call = g_pBinTools->CreateVCall(offset, 0, 0, info, NULL, 0);
   170 
   171 		if (s_EyeAngles.call != NULL)
   172 		{
   173 			s_EyeAngles.supported = true;
   174 		}
   175 	}
   176 
   177 	s_EyeAngles.setup = true;
   178 
   179 	return s_EyeAngles.supported;
   180 }
   181 
   182 bool GetEyeAngles(CBaseEntity *pEntity, QAngle *pAngles)
   183 {
   184 	if (!IsEyeAnglesSupported())
   185 	{
   186 		return false;
   187 	}
   188 
   189 	QAngle *pRetAngle = NULL;
   190 	unsigned char params[sizeof(void *)];
   191 	unsigned char *vptr = params;
   192 
   193 	*(CBaseEntity **)vptr = pEntity;
   194 
   195 	s_EyeAngles.call->Execute(params, &pRetAngle);
   196 
   197 	if (pRetAngle == NULL)
   198 	{
   199 		return false;
   200 	}
   201 
   202 	*pAngles = *pRetAngle;
   203 
   204 	return true;
   205 }
   206 
   207 int GetClientAimTarget(edict_t *pEdict, bool only_players)
   208 {
   209 	CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL;
   210 
   211 	if (pEntity == NULL)
   212 	{
   213 		return -1;
   214 	}
   215 
   216 	Vector eye_position;
   217 	QAngle eye_angles;
   218 
   219 	/* Get the private information we need */
   220 	serverClients->ClientEarPosition(pEdict, &eye_position);
   221 	if (!GetEyeAngles(pEntity, &eye_angles))
   222 	{
   223 		return -2;
   224 	}
   225 
   226 	Vector aim_dir;
   227 	AngleVectors(eye_angles, &aim_dir);
   228 	VectorNormalize(aim_dir);
   229 
   230 	Vector vec_end = eye_position + aim_dir * 8000;
   231 
   232 	Ray_t ray;
   233 	ray.Init(eye_position, vec_end);
   234 
   235 	trace_t tr;
   236 	CTraceFilterSimple simple(pEdict->GetIServerEntity());
   237 
   238 	enginetrace->TraceRay(ray, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, &simple, &tr);
   239 
   240 	if (tr.fraction == 1.0f || tr.m_pEnt == NULL)
   241 	{
   242 		return -1;
   243 	}
   244 
   245 	int ent_ref = gamehelpers->EntityToBCompatRef(tr.m_pEnt);
   246 	int ent_index = gamehelpers->ReferenceToIndex(ent_ref);
   247 
   248 	IGamePlayer *pTargetPlayer = playerhelpers->GetGamePlayer(ent_index);
   249 	if (pTargetPlayer != NULL && !pTargetPlayer->IsInGame())
   250 	{
   251 		return -1;
   252 	}
   253 	else if (only_players && pTargetPlayer == NULL)
   254 	{
   255 		return -1;
   256 	}
   257 
   258 	return ent_ref;
   259 }
   260 
   261 bool IsEyeAnglesSupported()
   262 {
   263 	return SetupGetEyeAngles();
   264 }
   265 
   266 bool GetPlayerInfo(int client, player_info_t *info)
   267 {
   268 #if SOURCE_ENGINE >= SE_ORANGEBOX
   269 	return engine->GetPlayerInfo(client, info);
   270 #else
   271 	return (iserver) ? iserver->GetPlayerInfo(client-1, info) : false;
   272 #endif
   273 }
   274 
   275 void ShutdownHelpers()
   276 {
   277 	s_Teleport.Shutdown();
   278 	s_GetVelocity.Shutdown();
   279 	s_EyeAngles.Shutdown();
   280 }
   281 
   282 void UTIL_DrawSendTable_XML(FILE *fp, SendTable *pTable, int space_count)
   283 {
   284 	char spaces[255];
   285 
   286 	for (int i = 0; i < space_count; i++)
   287 	{
   288 		spaces[i] = ' ';
   289 	}
   290 	spaces[space_count] = '\0';
   291 
   292 	const char *type_name;
   293 	SendTable *pOtherTable;
   294 	SendProp *pProp;
   295 
   296 	fprintf(fp, " %s<sendtable name=\"%s\">\n", spaces, pTable->GetName());
   297 	for (int i = 0; i < pTable->GetNumProps(); i++)
   298 	{
   299 		pProp = pTable->GetProp(i);
   300 
   301 		fprintf(fp, "  %s<property name=\"%s\">\n", spaces, pProp->GetName());
   302 
   303 		if ((type_name = GetDTTypeName(pProp->GetType())) != NULL)
   304 		{
   305 			fprintf(fp, "   %s<type>%s</type>\n", spaces, type_name);
   306 		}
   307 		else
   308 		{
   309 			fprintf(fp, "   %s<type>%d</type>\n", spaces, pProp->GetType());
   310 		}
   311 
   312 		fprintf(fp, "   %s<offset>%d</offset>\n", spaces, pProp->GetOffset());
   313 		fprintf(fp, "   %s<bits>%d</bits>\n", spaces, pProp->m_nBits);
   314 
   315 		if ((pOtherTable = pTable->GetProp(i)->GetDataTable()) != NULL)
   316 		{
   317 			UTIL_DrawSendTable_XML(fp, pOtherTable, space_count + 3);
   318 		}
   319 
   320 		fprintf(fp, "  %s</property>\n", spaces);
   321 	}
   322 	fprintf(fp, " %s</sendtable>\n", spaces);
   323 }
   324 
   325 void UTIL_DrawServerClass_XML(FILE *fp, ServerClass *sc)
   326 {
   327 	fprintf(fp, "<serverclass name=\"%s\">\n", sc->GetName());
   328 	UTIL_DrawSendTable_XML(fp, sc->m_pTable, 0);
   329 	fprintf(fp, "</serverclass>\n");
   330 }
   331 
   332 void UTIL_DrawSendTable(FILE *fp, SendTable *pTable, int level)
   333 {
   334 	char spaces[255];
   335 	for (int i=0; i<level; i++)
   336 		spaces[i] = ' ';
   337 	spaces[level] = '\0';
   338 
   339 	const char *name, *type;
   340 	SendProp *pProp;
   341 
   342 	fprintf(fp, "%sSub-Class Table (%d Deep): %s\n", spaces, level, pTable->GetName());
   343 
   344 	for (int i=0; i<pTable->GetNumProps(); i++)
   345 	{
   346 		pProp = pTable->GetProp(i);
   347 		name = pProp->GetName();
   348 		if (pProp->GetDataTable())
   349 		{
   350 			UTIL_DrawSendTable(fp, pProp->GetDataTable(), level + 1);
   351 		}
   352 		else
   353 		{
   354 			type = GetDTTypeName(pProp->GetType());
   355 
   356 			if (type != NULL)
   357 			{
   358 				fprintf(fp,
   359 					"%s-Member: %s (offset %d) (type %s) (bits %d)\n", 
   360 					spaces, 
   361 					pProp->GetName(),
   362 					pProp->GetOffset(),
   363 					type,
   364 					pProp->m_nBits);
   365 			}
   366 			else
   367 			{
   368 				fprintf(fp,
   369 					"%s-Member: %s (offset %d) (type %d) (bits %d)\n", 
   370 					spaces, 
   371 					pProp->GetName(),
   372 					pProp->GetOffset(),
   373 					pProp->GetType(),
   374 					pProp->m_nBits);
   375 			}
   376 		}
   377 	}
   378 }
   379 
   380 CON_COMMAND(sm_dump_netprops_xml, "Dumps the networkable property table as an XML file")
   381 {
   382 #if SOURCE_ENGINE <= SE_DARKMESSIAH
   383 	CCommand args;
   384 #endif
   385 
   386 	if (args.ArgC() < 2)
   387 	{
   388 		META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
   389 		return;
   390 	}
   391 
   392 	const char *file = args.Arg(1);
   393 	if (!file || file[0] == '\0')
   394 	{
   395 		META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
   396 		return;
   397 	}
   398 
   399 	char path[PLATFORM_MAX_PATH];
   400 	g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
   401 
   402 	FILE *fp = NULL;
   403 	if ((fp = fopen(path, "wt")) == NULL)
   404 	{
   405 		META_CONPRINTF("Could not open file \"%s\"\n", path);
   406 		return;
   407 	}
   408 
   409 	fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
   410 	fprintf(fp, "<!-- Dump of all network properties for \"%s\" follows -->\n\n", g_pSM->GetGameFolderName());
   411 
   412 	ServerClass *pBase = gamedll->GetAllServerClasses();
   413 	while (pBase != NULL)
   414 	{
   415 		UTIL_DrawServerClass_XML(fp, pBase);
   416 		pBase = pBase->m_pNext;
   417 	}
   418 
   419 	fclose(fp);
   420 }
   421 
   422 CON_COMMAND(sm_dump_netprops, "Dumps the networkable property table as a text file")
   423 {
   424 #if SOURCE_ENGINE <= SE_DARKMESSIAH
   425 	CCommand args;
   426 #endif
   427 
   428 	if (args.ArgC() < 2)
   429 	{
   430 		META_CONPRINT("Usage: sm_dump_netprops <file>\n");
   431 		return;
   432 	}
   433 
   434 	const char *file = args.Arg(1);
   435 	if (!file || file[0] == '\0')
   436 	{
   437 		META_CONPRINT("Usage: sm_dump_netprops <file>\n");
   438 		return;
   439 	}
   440 
   441 	char path[PLATFORM_MAX_PATH];
   442 	g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
   443 
   444 	FILE *fp = NULL;
   445 	if ((fp = fopen(path, "wt")) == NULL)
   446 	{
   447 		META_CONPRINTF("Could not open file \"%s\"\n", path);
   448 		return;
   449 	}
   450 
   451 	fprintf(fp, "// Dump of all network properties for \"%s\" follows\n//\n\n", g_pSM->GetGameFolderName());
   452 
   453 	ServerClass *pBase = gamedll->GetAllServerClasses();
   454 	while (pBase != NULL)
   455 	{
   456 		fprintf(fp, "%s:\n", pBase->GetName());
   457 		UTIL_DrawSendTable(fp, pBase->m_pTable, 1);
   458 		pBase = pBase->m_pNext;
   459 	}
   460 
   461 	fclose(fp);
   462 }
   463 
   464 #if defined SUBPLATFORM_SECURECRT
   465 void _ignore_invalid_parameter(
   466 						const wchar_t * expression,
   467 						const wchar_t * function, 
   468 						const wchar_t * file, 
   469 						unsigned int line,
   470 						uintptr_t pReserved
   471 						)
   472 {
   473 	/* Wow we don't care, thanks Microsoft. */
   474 }
   475 #endif
   476 
   477 CON_COMMAND(sm_dump_classes, "Dumps the class list as a text file")
   478 {
   479 #if SOURCE_ENGINE <= SE_DARKMESSIAH
   480 	CCommand args;
   481 #endif
   482 
   483 	if (args.ArgC() < 2)
   484 	{
   485 		META_CONPRINT("Usage: sm_dump_classes <file>\n");
   486 		return;
   487 	}
   488 
   489 	const char *file = args.Arg(1);
   490 	if (!file || file[0] == '\0')
   491 	{
   492 		META_CONPRINT("Usage: sm_dump_classes <file>\n");
   493 		return;
   494 	}
   495 
   496 	ICallWrapper *pWrapper = NULL;
   497 
   498 	if (!pWrapper)
   499 	{
   500 		PassInfo retData;
   501 		retData.flags = PASSFLAG_BYVAL;
   502 		retData.size = sizeof(void *);
   503 		retData.type = PassType_Basic;
   504 
   505 		void *addr;
   506 		if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || addr == NULL)
   507 		{
   508 			META_CONPRINT("Failed to locate function\n");
   509 			return;
   510 		}
   511 
   512 		pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0);
   513 	}
   514 
   515 
   516 	void *returnData = NULL;
   517 
   518 	pWrapper->Execute(NULL, &returnData);
   519 
   520 	pWrapper->Destroy();
   521 
   522 	if (returnData == NULL)
   523 	{
   524 		return;
   525 	}
   526 
   527 	CEntityFactoryDictionary *dict = ( CEntityFactoryDictionary * )returnData;
   528 
   529 	if ( !dict )
   530 	{
   531 		return;
   532 	}
   533 
   534 	char path[PLATFORM_MAX_PATH];
   535 	g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
   536 
   537 	FILE *fp = NULL;
   538 	if ((fp = fopen(path, "wt")) == NULL)
   539 	{
   540 		META_CONPRINTF("Could not open file \"%s\"\n", path);
   541 		return;
   542 	}
   543 
   544 	char buffer[80];
   545 	buffer[0] = 0;
   546 
   547 #if defined SUBPLATFORM_SECURECRT
   548 	_invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
   549 #endif
   550 
   551 	time_t t = g_pSM->GetAdjustedTime();
   552 	size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t));
   553 
   554 #if defined SUBPLATFORM_SECURECRT
   555 	_set_invalid_parameter_handler(handler);
   556 #endif
   557 
   558 	fprintf(fp, "// Dump of all classes for \"%s\" as at %s\n//\n\n", g_pSM->GetGameFolderName(), buffer);
   559 
   560 	for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) )
   561 	{
   562 		IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i));
   563 		ServerClass *sclass = entity->GetServerClass();
   564 		fprintf(fp,"%s - %s\n",sclass->GetName(), dict->m_Factories.GetElementName(i));
   565 
   566 		typedescription_t *datamap = gamehelpers->FindInDataMap(gamehelpers->GetDataMap(entity->GetBaseEntity()), "m_iEFlags");
   567 		int *eflags = (int *)((char *)entity->GetBaseEntity() + GetTypeDescOffs(datamap));
   568 		*eflags |= (1<<0); // EFL_KILLME
   569 	}
   570 
   571 	fclose(fp);
   572 
   573 }
   574 
   575 char *UTIL_FlagsToString(int flags)
   576 {
   577 	static char str[1024];
   578 	str[0] = 0;
   579 
   580 	if (flags & FTYPEDESC_GLOBAL)
   581 	{
   582 		strcat(str,	"Global|");
   583 	}
   584 	if (flags & FTYPEDESC_SAVE)
   585 	{
   586 		strcat(str,	"Save|");
   587 	}
   588 	if (flags & FTYPEDESC_KEY)
   589 	{
   590 		strcat(str,	"Key|");
   591 	}
   592 	if (flags & FTYPEDESC_INPUT)
   593 	{
   594 		strcat(str,	"Input|");
   595 	}
   596 	if (flags & FTYPEDESC_OUTPUT)
   597 	{
   598 		strcat(str,	"Output|");
   599 	}
   600 	if (flags & FTYPEDESC_FUNCTIONTABLE)
   601 	{
   602 		strcat(str,	"FunctionTable|");
   603 	}
   604 	if (flags & FTYPEDESC_PTR)
   605 	{
   606 		strcat(str,	"Ptr|");
   607 	}
   608 	if (flags & FTYPEDESC_OVERRIDE)
   609 	{
   610 		strcat(str,	"Override|");
   611 	}
   612 
   613 	int len = strlen(str) - 1;
   614 	if (len > 0)
   615 	{
   616 		str[len] = 0; // Strip the final '|'
   617 	}
   618 
   619 	return str;
   620 }
   621 
   622 void UTIL_DrawDataTable(FILE *fp, datamap_t *pMap, int level)
   623 {
   624 	char spaces[255];
   625 
   626 	for (int i=0; i<level; i++)
   627 	{
   628 		spaces[i] = ' ';
   629 	}
   630 
   631 	spaces[level] = '\0';
   632 
   633 	const char *externalname;
   634 	char *flags;
   635 
   636 	while (pMap)
   637 	{
   638 		for (int i=0; i<pMap->dataNumFields; i++)
   639 		{
   640 			if (pMap->dataDesc[i].fieldName == NULL)
   641 			{
   642 				continue;
   643 			}
   644 
   645 			if (pMap->dataDesc[i].td)
   646 			{
   647 				fprintf(fp, " %sSub-Class Table (%d Deep): %s - %s\n", spaces, level+1, pMap->dataDesc[i].fieldName, pMap->dataDesc[i].td->dataClassName);
   648 				UTIL_DrawDataTable(fp, pMap->dataDesc[i].td, level+1);
   649 			}
   650 			else
   651 			{
   652 				externalname  = pMap->dataDesc[i].externalName;
   653 				flags = UTIL_FlagsToString(pMap->dataDesc[i].flags);
   654 
   655 				if (externalname == NULL)
   656 				{
   657 					fprintf(fp,"%s- %s (%s)(%i Bytes)\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes);
   658 				}
   659 				else
   660 				{
   661 					fprintf(fp,"%s- %s (%s)(%i Bytes) - %s\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes, externalname);
   662 				}
   663 			}
   664 		}
   665 		pMap = pMap->baseMap;
   666 	}
   667 }
   668 
   669 CON_COMMAND(sm_dump_datamaps, "Dumps the data map list as a text file")
   670 {
   671 #if SOURCE_ENGINE <= SE_DARKMESSIAH
   672 	CCommand args;
   673 #endif
   674 
   675 	if (args.ArgC() < 2)
   676 	{
   677 		META_CONPRINT("Usage: sm_dump_datamaps <file>\n");
   678 		return;
   679 	}
   680 
   681 	const char *file = args.Arg(1);
   682 	if (!file || file[0] == '\0')
   683 	{
   684 		META_CONPRINT("Usage: sm_dump_datamaps <file>\n");
   685 		return;
   686 	}
   687 
   688 	ICallWrapper *pWrapper = NULL;
   689 
   690 	if (!pWrapper)
   691 	{
   692 		PassInfo retData;
   693 		retData.flags = PASSFLAG_BYVAL;
   694 		retData.size = sizeof(void *);
   695 		retData.type = PassType_Basic;
   696 
   697 		void *addr;
   698 		if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || addr == NULL)
   699 		{
   700 			META_CONPRINT("Failed to locate function\n");
   701 			return;
   702 		}
   703 
   704 		pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0);
   705 	}
   706 
   707 
   708 	void *returnData = NULL;
   709 
   710 	pWrapper->Execute(NULL, &returnData);
   711 
   712 	pWrapper->Destroy();
   713 
   714 	if (returnData == NULL)
   715 	{
   716 		return;
   717 	}
   718 
   719 	CEntityFactoryDictionary *dict = ( CEntityFactoryDictionary * )returnData;
   720 
   721 	if ( !dict )
   722 	{
   723 		return;
   724 	}
   725 
   726 	char path[PLATFORM_MAX_PATH];
   727 	g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
   728 
   729 	FILE *fp = NULL;
   730 	if ((fp = fopen(path, "wt")) == NULL)
   731 	{
   732 		META_CONPRINTF("Could not open file \"%s\"\n", path);
   733 		return;
   734 	}
   735 
   736 	char buffer[80];
   737 	buffer[0] = 0;
   738 
   739 #if defined SUBPLATFORM_SECURECRT
   740 	_invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
   741 #endif
   742 
   743 	time_t t = g_pSM->GetAdjustedTime();
   744 	size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t));
   745 
   746 #if defined SUBPLATFORM_SECURECRT
   747 	_set_invalid_parameter_handler(handler);
   748 #endif
   749 
   750 	fprintf(fp, "// Dump of all datamaps for \"%s\" as at %s\n//\n//\n", g_pSM->GetGameFolderName(), buffer);
   751 
   752 
   753 	fprintf(fp, "// Flag Details:\n//\n");
   754 
   755 	fprintf(fp, "// Global: This field is masked for global entity save/restore\n");
   756 	fprintf(fp, "// Save: This field is saved to disk\n");
   757 	fprintf(fp, "// Key: This field can be requested and written to by string name at load time\n");
   758 	fprintf(fp, "// Input: This field can be written to by string name at run time, and a function called\n");
   759 	fprintf(fp, "// Output: This field propogates it's value to all targets whenever it changes\n");
   760 	fprintf(fp, "// FunctionTable: This is a table entry for a member function pointer\n");
   761 	fprintf(fp, "// Ptr: This field is a pointer, not an embedded object\n");
   762 	fprintf(fp, "// Override: The field is an override for one in a base class (only used by prediction system for now)\n");
   763 
   764 	fprintf(fp, "//\n\n");
   765 
   766 	for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) )
   767 	{
   768 		IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i));
   769 		ServerClass *sclass = entity->GetServerClass();
   770 		datamap_t *pMap = gamehelpers->GetDataMap(entity->GetBaseEntity());
   771 
   772 		fprintf(fp,"%s - %s\n", sclass->GetName(), dict->m_Factories.GetElementName(i));
   773 
   774 		UTIL_DrawDataTable(fp, pMap, 0);
   775 
   776 		typedescription_t *datamap = gamehelpers->FindInDataMap(pMap, "m_iEFlags");
   777 		
   778 		if (!datamap)
   779 		{
   780 			continue;
   781 		}
   782 		
   783 		int *eflags = (int *)((char *)entity->GetBaseEntity() + GetTypeDescOffs(datamap));
   784 		*eflags |= (1<<0); // EFL_KILLME
   785 	}
   786 
   787 	fclose(fp);
   788 
   789 }