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