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