extensions/sdktools/vhelpers.cpp
author David Anderson <dvander@alliedmods.net>
Tue Jan 22 17:18:15 2008 +0000 (2008-01-22)
changeset 1855 7871fb255eb5
parent 1773 d00a853ec547
child 1922 a8cff6b8ef64
permissions -rw-r--r--
added amb1383 - data value to filter functions
dvander@1169
     1
/**
dvander@1169
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1233
     4
 * SourceMod SDKTools Extension
dvander@1233
     5
 * Copyright (C) 2004-2007 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"
dvander@1169
    33
#include "vhelpers.h"
dvander@1169
    34
dvander@1169
    35
CallHelper s_Teleport;
dvander@1169
    36
CallHelper s_GetVelocity;
dvander@1611
    37
CallHelper s_EyeAngles;
dvander@1169
    38
dvander@1628
    39
class CTraceFilterSimple : public CTraceFilterEntitiesOnly
dvander@1628
    40
{
dvander@1628
    41
public:
dvander@1628
    42
	CTraceFilterSimple(const IHandleEntity *passentity): m_pPassEnt(passentity)
dvander@1628
    43
	{
dvander@1628
    44
	}
dvander@1628
    45
	virtual bool ShouldHitEntity(IHandleEntity *pServerEntity, int contentsMask)
dvander@1628
    46
	{
dvander@1628
    47
		if (pServerEntity == m_pPassEnt)
dvander@1628
    48
		{
dvander@1628
    49
			return false;
dvander@1628
    50
		}
dvander@1628
    51
		return true;
dvander@1628
    52
	}
dvander@1628
    53
private:
dvander@1628
    54
	const IHandleEntity *m_pPassEnt;
dvander@1628
    55
};
dvander@1628
    56
dvander@1169
    57
bool SetupTeleport()
dvander@1169
    58
{
dvander@1169
    59
	if (s_Teleport.setup)
dvander@1169
    60
	{
dvander@1169
    61
		return s_Teleport.supported;
dvander@1169
    62
	}
dvander@1169
    63
dvander@1169
    64
	/* Setup Teleport */
dvander@1169
    65
	int offset;
dvander@1169
    66
	if (g_pGameConf->GetOffset("Teleport", &offset))
dvander@1169
    67
	{
dvander@1169
    68
		PassInfo info[3];
dvander@1169
    69
		info[0].flags = info[1].flags = info[2].flags = PASSFLAG_BYVAL;
dvander@1169
    70
		info[0].size = info[1].size = info[2].size = sizeof(void *);
dvander@1169
    71
		info[0].type = info[1].type = info[2].type = PassType_Basic;
dvander@1169
    72
dvander@1169
    73
		s_Teleport.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 3);
dvander@1169
    74
dvander@1611
    75
		if (s_Teleport.call != NULL)
dvander@1169
    76
		{
dvander@1169
    77
			s_Teleport.supported = true;
dvander@1169
    78
		}
dvander@1169
    79
	}
dvander@1169
    80
dvander@1169
    81
	s_Teleport.setup = true;
dvander@1169
    82
dvander@1169
    83
	return s_Teleport.supported;
dvander@1169
    84
}
dvander@1169
    85
dvander@1169
    86
void Teleport(CBaseEntity *pEntity, Vector *origin, QAngle *ang, Vector *velocity)
dvander@1169
    87
{
dvander@1169
    88
	unsigned char params[sizeof(void *) * 4];
dvander@1169
    89
	unsigned char *vptr = params;
dvander@1169
    90
	*(CBaseEntity **)vptr = pEntity;
dvander@1169
    91
	vptr += sizeof(CBaseEntity *);
dvander@1169
    92
	*(Vector **)vptr = origin;
dvander@1169
    93
	vptr += sizeof(Vector *);
dvander@1169
    94
	*(QAngle **)vptr = ang;
dvander@1169
    95
	vptr += sizeof(QAngle *);
dvander@1169
    96
	*(Vector **)vptr = velocity;
dvander@1169
    97
	
dvander@1169
    98
	s_Teleport.call->Execute(params, NULL);
dvander@1169
    99
}
dvander@1169
   100
dvander@1169
   101
bool IsTeleportSupported()
dvander@1169
   102
{
dvander@1169
   103
	return SetupTeleport();
dvander@1169
   104
}
dvander@1169
   105
dvander@1169
   106
bool SetupGetVelocity()
dvander@1169
   107
{
dvander@1169
   108
	if (s_GetVelocity.setup)
dvander@1169
   109
	{
dvander@1169
   110
		return s_GetVelocity.supported;
dvander@1169
   111
	}
dvander@1169
   112
dvander@1169
   113
	int offset;
dvander@1169
   114
	if (g_pGameConf->GetOffset("GetVelocity", &offset))
dvander@1169
   115
	{
dvander@1169
   116
		PassInfo info[2];
dvander@1169
   117
		info[0].flags = info[1].flags = PASSFLAG_BYVAL;
dvander@1169
   118
		info[0].size = info[1].size = sizeof(void *);
dvander@1169
   119
		info[0].type = info[1].type = PassType_Basic;
dvander@1169
   120
dvander@1169
   121
		s_GetVelocity.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 2);
dvander@1169
   122
dvander@1611
   123
		if (s_GetVelocity.call != NULL)
dvander@1169
   124
		{
dvander@1169
   125
			s_GetVelocity.supported = true;
dvander@1169
   126
		}
dvander@1169
   127
	}
dvander@1169
   128
dvander@1169
   129
	s_GetVelocity.setup = true;
dvander@1169
   130
dvander@1169
   131
	return s_GetVelocity.supported;
dvander@1169
   132
}
dvander@1169
   133
dvander@1169
   134
void GetVelocity(CBaseEntity *pEntity, Vector *velocity, AngularImpulse *angvelocity)
dvander@1169
   135
{
dvander@1169
   136
	unsigned char params[sizeof(void *) * 3];
dvander@1169
   137
	unsigned char *vptr = params;
dvander@1169
   138
	*(CBaseEntity **)vptr = pEntity;
dvander@1169
   139
	vptr += sizeof(CBaseEntity *);
dvander@1169
   140
	*(Vector **)vptr = velocity;
dvander@1169
   141
	vptr += sizeof(Vector *);
dvander@1169
   142
	*(AngularImpulse **)vptr = angvelocity;
dvander@1169
   143
dvander@1169
   144
	s_GetVelocity.call->Execute(params, NULL);
dvander@1169
   145
}
dvander@1169
   146
dvander@1169
   147
bool IsGetVelocitySupported()
dvander@1169
   148
{
dvander@1169
   149
	return SetupGetVelocity();
dvander@1169
   150
}
dvander@1169
   151
dvander@1611
   152
bool SetupGetEyeAngles()
dvander@1611
   153
{
dvander@1611
   154
	if (s_EyeAngles.setup)
dvander@1611
   155
	{
dvander@1611
   156
		return s_EyeAngles.supported;
dvander@1611
   157
	}
dvander@1611
   158
dvander@1611
   159
	int offset;
dvander@1611
   160
	if (g_pGameConf->GetOffset("EyeAngles", &offset))
dvander@1611
   161
	{
dvander@1611
   162
		PassInfo info[2];
dvander@1611
   163
		info[0].flags = info[1].flags = PASSFLAG_BYVAL;
dvander@1611
   164
		info[0].size = info[1].size = sizeof(void *);
dvander@1611
   165
		info[0].type = info[1].type = PassType_Basic;
dvander@1611
   166
dvander@1611
   167
		s_EyeAngles.call = g_pBinTools->CreateVCall(offset, 0, 0, &info[0], &info[1], 1);
dvander@1611
   168
dvander@1611
   169
		if (s_EyeAngles.call != NULL)
dvander@1611
   170
		{
dvander@1611
   171
			s_EyeAngles.supported = true;
dvander@1611
   172
		}
dvander@1611
   173
	}
dvander@1611
   174
dvander@1611
   175
	s_EyeAngles.setup = true;
dvander@1611
   176
dvander@1611
   177
	return s_EyeAngles.supported;
dvander@1611
   178
}
dvander@1611
   179
dvander@1611
   180
bool GetEyeAngles(CBaseEntity *pEntity, QAngle *pAngles)
dvander@1611
   181
{
dvander@1611
   182
	if (!IsEyeAnglesSupported())
dvander@1611
   183
	{
dvander@1611
   184
		return false;
dvander@1611
   185
	}
dvander@1611
   186
dvander@1611
   187
	QAngle *pRetAngle = NULL;
dvander@1611
   188
	unsigned char params[sizeof(void *)];
dvander@1611
   189
	unsigned char *vptr = params;
dvander@1611
   190
dvander@1611
   191
	*(CBaseEntity **)vptr = pEntity;
dvander@1611
   192
	vptr += sizeof(CBaseEntity *);
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
dvander@1628
   244
	edict_t *pTarget = gameents->BaseEntityToEdict(tr.m_pEnt);
dvander@1628
   245
	if (pTarget == NULL)
dvander@1628
   246
	{
dvander@1628
   247
		return -1;
dvander@1628
   248
	}
dvander@1628
   249
dvander@1628
   250
	int ent_index = engine->IndexOfEdict(pTarget);
dvander@1628
   251
dvander@1628
   252
	IGamePlayer *pTargetPlayer = playerhelpers->GetGamePlayer(ent_index);
dvander@1628
   253
	if (pTargetPlayer != NULL && !pTargetPlayer->IsInGame())
dvander@1628
   254
	{
dvander@1628
   255
		return -1;
dvander@1628
   256
	}
dvander@1628
   257
	else if (only_players && pTargetPlayer == NULL)
dvander@1628
   258
	{
dvander@1628
   259
		return -1;
dvander@1628
   260
	}
dvander@1628
   261
dvander@1628
   262
	return ent_index;
dvander@1628
   263
}
dvander@1628
   264
dvander@1611
   265
bool IsEyeAnglesSupported()
dvander@1611
   266
{
dvander@1611
   267
	return SetupGetEyeAngles();
dvander@1611
   268
}
dvander@1611
   269
faluco@1769
   270
bool GetPlayerInfo(int client, player_info_t *info)
faluco@1769
   271
{
faluco@1769
   272
#if defined ORANGEBOX_BUILD
faluco@1769
   273
	return engine->GetPlayerInfo(client, info);
faluco@1769
   274
#else
faluco@1773
   275
	return (iserver) ? iserver->GetPlayerInfo(client-1, info) : false;
faluco@1769
   276
#endif
faluco@1769
   277
}
faluco@1769
   278
dvander@1169
   279
void ShutdownHelpers()
dvander@1169
   280
{
dvander@1169
   281
	s_Teleport.Shutdown();
dvander@1169
   282
	s_GetVelocity.Shutdown();
dvander@1169
   283
}
dvander@1636
   284
dvander@1636
   285
const char *GetDTTypeName(int type)
dvander@1636
   286
{
dvander@1636
   287
	switch (type)
dvander@1636
   288
	{
dvander@1636
   289
	case DPT_Int:
dvander@1636
   290
		{
dvander@1636
   291
			return "integer";
dvander@1636
   292
		}
dvander@1636
   293
	case DPT_Float:
dvander@1636
   294
		{
dvander@1636
   295
			return "float";
dvander@1636
   296
		}
dvander@1636
   297
	case DPT_Vector:
dvander@1636
   298
		{
dvander@1636
   299
			return "vector";
dvander@1636
   300
		}
dvander@1636
   301
	case DPT_String:
dvander@1636
   302
		{
dvander@1636
   303
			return "string";
dvander@1636
   304
		}
dvander@1636
   305
	case DPT_Array:
dvander@1636
   306
		{
dvander@1636
   307
			return "array";
dvander@1636
   308
		}
dvander@1636
   309
	case DPT_DataTable:
dvander@1636
   310
		{
dvander@1636
   311
			return "datatable";
dvander@1636
   312
		}
dvander@1636
   313
	default:
dvander@1636
   314
		{
dvander@1636
   315
			return NULL;
dvander@1636
   316
		}
dvander@1636
   317
	}
dvander@1636
   318
dvander@1636
   319
	return NULL;
dvander@1636
   320
}
dvander@1636
   321
dvander@1636
   322
void UTIL_DrawSendTable_XML(FILE *fp, SendTable *pTable, int space_count)
dvander@1636
   323
{
dvander@1636
   324
	char spaces[255];
dvander@1636
   325
dvander@1636
   326
	for (int i = 0; i < space_count; i++)
dvander@1636
   327
	{
dvander@1636
   328
		spaces[i] = ' ';
dvander@1636
   329
	}
dvander@1636
   330
	spaces[space_count] = '\0';
dvander@1636
   331
dvander@1636
   332
	const char *type_name;
dvander@1636
   333
	SendTable *pOtherTable;
dvander@1636
   334
	SendProp *pProp;
dvander@1636
   335
dvander@1636
   336
	fprintf(fp, " %s<sendtable name=\"%s\">\n", spaces, pTable->GetName());
dvander@1636
   337
	for (int i = 0; i < pTable->GetNumProps(); i++)
dvander@1636
   338
	{
dvander@1636
   339
		pProp = pTable->GetProp(i);
dvander@1636
   340
dvander@1636
   341
		fprintf(fp, "  %s<property name=\"%s\">\n", spaces, pProp->GetName());
dvander@1636
   342
dvander@1636
   343
		if ((type_name = GetDTTypeName(pProp->GetType())) != NULL)
dvander@1636
   344
		{
dvander@1636
   345
			fprintf(fp, "   %s<type>%s</type>\n", spaces, type_name);
dvander@1636
   346
		}
dvander@1636
   347
		else
dvander@1636
   348
		{
dvander@1636
   349
			fprintf(fp, "   %s<type>%d</type>\n", spaces, pProp->GetType());
dvander@1636
   350
		}
dvander@1636
   351
dvander@1636
   352
		fprintf(fp, "   %s<offset>%d</offset>\n", spaces, pProp->GetOffset());
dvander@1636
   353
		fprintf(fp, "   %s<bits>%d</bits>\n", spaces, pProp->m_nBits);
dvander@1636
   354
dvander@1636
   355
		if ((pOtherTable = pTable->GetProp(i)->GetDataTable()) != NULL)
dvander@1636
   356
		{
dvander@1636
   357
			UTIL_DrawSendTable_XML(fp, pOtherTable, space_count + 3);
dvander@1636
   358
		}
dvander@1636
   359
dvander@1636
   360
		fprintf(fp, "  %s</property>\n", spaces);
dvander@1636
   361
	}
dvander@1636
   362
	fprintf(fp, " %s</sendtable>\n", spaces);
dvander@1636
   363
}
dvander@1636
   364
dvander@1636
   365
void UTIL_DrawServerClass_XML(FILE *fp, ServerClass *sc)
dvander@1636
   366
{
dvander@1636
   367
	fprintf(fp, "<serverclass name=\"%s\">\n", sc->GetName());
dvander@1636
   368
	UTIL_DrawSendTable_XML(fp, sc->m_pTable, 0);
dvander@1636
   369
	fprintf(fp, "</serverclass>\n");
dvander@1636
   370
}
dvander@1636
   371
dvander@1636
   372
void UTIL_DrawSendTable(FILE *fp, SendTable *pTable, int level)
dvander@1636
   373
{
dvander@1636
   374
	char spaces[255];
dvander@1636
   375
	for (int i=0; i<level; i++)
dvander@1636
   376
		spaces[i] = ' ';
dvander@1636
   377
	spaces[level] = '\0';
dvander@1636
   378
dvander@1636
   379
	const char *name, *type;
dvander@1636
   380
	SendProp *pProp;
dvander@1636
   381
dvander@1636
   382
	fprintf(fp, "%sSub-Class Table (%d Deep): %s\n", spaces, level, pTable->GetName());
dvander@1636
   383
dvander@1636
   384
	for (int i=0; i<pTable->GetNumProps(); i++)
dvander@1636
   385
	{
dvander@1636
   386
		pProp = pTable->GetProp(i);
dvander@1636
   387
		name = pProp->GetName();
dvander@1636
   388
		if (pProp->GetDataTable())
dvander@1636
   389
		{
dvander@1636
   390
			UTIL_DrawSendTable(fp, pProp->GetDataTable(), level + 1);
dvander@1636
   391
		}
dvander@1636
   392
		else
dvander@1636
   393
		{
dvander@1636
   394
			type = GetDTTypeName(pProp->GetType());
dvander@1636
   395
dvander@1636
   396
			if (type != NULL)
dvander@1636
   397
			{
dvander@1636
   398
				fprintf(fp,
dvander@1636
   399
					"%s-Member: %s (offset %d) (type %s) (bits %d)\n", 
dvander@1636
   400
					spaces, 
dvander@1636
   401
					pProp->GetName(),
dvander@1636
   402
					pProp->GetOffset(),
dvander@1636
   403
					type,
dvander@1636
   404
					pProp->m_nBits);
dvander@1636
   405
			}
dvander@1636
   406
			else
dvander@1636
   407
			{
dvander@1636
   408
				fprintf(fp,
dvander@1636
   409
					"%s-Member: %s (offset %d) (type %d) (bits %d)\n", 
dvander@1636
   410
					spaces, 
dvander@1636
   411
					pProp->GetName(),
dvander@1636
   412
					pProp->GetOffset(),
dvander@1636
   413
					pProp->GetType(),
dvander@1636
   414
					pProp->m_nBits);
dvander@1636
   415
			}
dvander@1636
   416
		}
dvander@1636
   417
	}
dvander@1636
   418
}
dvander@1636
   419
dvander@1636
   420
CON_COMMAND(sm_dump_netprops_xml, "Dumps the networkable property table as an XML file")
dvander@1636
   421
{
dvander@1636
   422
#if !defined ORANGEBOX_BUILD
dvander@1636
   423
	CCommand args;
dvander@1636
   424
#endif
dvander@1636
   425
dvander@1636
   426
	if (args.ArgC() < 2)
dvander@1636
   427
	{
dvander@1636
   428
		META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
dvander@1636
   429
		return;
dvander@1636
   430
	}
dvander@1636
   431
dvander@1636
   432
	const char *file = args.Arg(1);
dvander@1636
   433
	if (!file || file[0] == '\0')
dvander@1636
   434
	{
dvander@1636
   435
		META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
dvander@1636
   436
		return;
dvander@1636
   437
	}
dvander@1636
   438
dvander@1636
   439
	char path[PLATFORM_MAX_PATH];
dvander@1636
   440
	g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
dvander@1636
   441
dvander@1636
   442
	FILE *fp = NULL;
dvander@1636
   443
	if ((fp = fopen(path, "wt")) == NULL)
dvander@1636
   444
	{
dvander@1636
   445
		META_CONPRINTF("Could not open file \"%s\"\n", path);
dvander@1636
   446
		return;
dvander@1636
   447
	}
dvander@1636
   448
dvander@1636
   449
	fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
dvander@1636
   450
	fprintf(fp, "<!-- Dump of all network properties for \"%s\" follows -->\n\n", g_pSM->GetGameFolderName());
dvander@1636
   451
dvander@1636
   452
	ServerClass *pBase = gamedll->GetAllServerClasses();
dvander@1636
   453
	while (pBase != NULL)
dvander@1636
   454
	{
dvander@1636
   455
		UTIL_DrawServerClass_XML(fp, pBase);
dvander@1636
   456
		pBase = pBase->m_pNext;
dvander@1636
   457
	}
dvander@1636
   458
dvander@1636
   459
	fclose(fp);
dvander@1636
   460
}
dvander@1636
   461
dvander@1636
   462
CON_COMMAND(sm_dump_netprops, "Dumps the networkable property table as a text file")
dvander@1636
   463
{
dvander@1636
   464
#if !defined ORANGEBOX_BUILD
dvander@1636
   465
	CCommand args;
dvander@1636
   466
#endif
dvander@1636
   467
dvander@1636
   468
	if (args.ArgC() < 2)
dvander@1636
   469
	{
dvander@1636
   470
		META_CONPRINT("Usage: sm_dump_netprops <file>\n");
dvander@1636
   471
		return;
dvander@1636
   472
	}
dvander@1636
   473
dvander@1636
   474
	const char *file = args.Arg(1);
dvander@1636
   475
	if (!file || file[0] == '\0')
dvander@1636
   476
	{
dvander@1636
   477
		META_CONPRINT("Usage: sm_dump_netprops <file>\n");
dvander@1636
   478
		return;
dvander@1636
   479
	}
dvander@1636
   480
dvander@1636
   481
	char path[PLATFORM_MAX_PATH];
dvander@1636
   482
	g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
dvander@1636
   483
dvander@1636
   484
	FILE *fp = NULL;
dvander@1636
   485
	if ((fp = fopen(path, "wt")) == NULL)
dvander@1636
   486
	{
dvander@1636
   487
		META_CONPRINTF("Could not open file \"%s\"\n", path);
dvander@1636
   488
		return;
dvander@1636
   489
	}
dvander@1636
   490
dvander@1636
   491
	fprintf(fp, "// Dump of all network properties for \"%s\" follows\n//\n\n", g_pSM->GetGameFolderName());
dvander@1636
   492
dvander@1636
   493
	ServerClass *pBase = gamedll->GetAllServerClasses();
dvander@1636
   494
	while (pBase != NULL)
dvander@1636
   495
	{
dvander@1640
   496
		fprintf(fp, "%s:\n", pBase->GetName());
dvander@1636
   497
		UTIL_DrawSendTable(fp, pBase->m_pTable, 1);
dvander@1636
   498
		pBase = pBase->m_pNext;
dvander@1636
   499
	}
dvander@1636
   500
dvander@1636
   501
	fclose(fp);
dvander@1636
   502
}
dvander@1636
   503