extensions/sdktools/vhelpers.cpp
author David Anderson <dvander@alliedmods.net>
Mon Oct 22 22:57:08 2007 +0000 (2007-10-22)
changeset 1640 a644ed81b457
parent 1636 c13834955093
child 1769 7a3f09643820
permissions -rw-r--r--
sm_dump_netprops now shows classnames
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod SDKTools Extension
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "extension.h"
    33 #include "vhelpers.h"
    34 
    35 CallHelper s_Teleport;
    36 CallHelper s_GetVelocity;
    37 CallHelper s_EyeAngles;
    38 
    39 class CTraceFilterSimple : public CTraceFilterEntitiesOnly
    40 {
    41 public:
    42 	CTraceFilterSimple(const IHandleEntity *passentity): m_pPassEnt(passentity)
    43 	{
    44 	}
    45 	virtual bool ShouldHitEntity(IHandleEntity *pServerEntity, int contentsMask)
    46 	{
    47 		if (pServerEntity == m_pPassEnt)
    48 		{
    49 			return false;
    50 		}
    51 		return true;
    52 	}
    53 private:
    54 	const IHandleEntity *m_pPassEnt;
    55 };
    56 
    57 bool SetupTeleport()
    58 {
    59 	if (s_Teleport.setup)
    60 	{
    61 		return s_Teleport.supported;
    62 	}
    63 
    64 	/* Setup Teleport */
    65 	int offset;
    66 	if (g_pGameConf->GetOffset("Teleport", &offset))
    67 	{
    68 		PassInfo info[3];
    69 		info[0].flags = info[1].flags = info[2].flags = PASSFLAG_BYVAL;
    70 		info[0].size = info[1].size = info[2].size = sizeof(void *);
    71 		info[0].type = info[1].type = info[2].type = PassType_Basic;
    72 
    73 		s_Teleport.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 3);
    74 
    75 		if (s_Teleport.call != NULL)
    76 		{
    77 			s_Teleport.supported = true;
    78 		}
    79 	}
    80 
    81 	s_Teleport.setup = true;
    82 
    83 	return s_Teleport.supported;
    84 }
    85 
    86 void Teleport(CBaseEntity *pEntity, Vector *origin, QAngle *ang, Vector *velocity)
    87 {
    88 	unsigned char params[sizeof(void *) * 4];
    89 	unsigned char *vptr = params;
    90 	*(CBaseEntity **)vptr = pEntity;
    91 	vptr += sizeof(CBaseEntity *);
    92 	*(Vector **)vptr = origin;
    93 	vptr += sizeof(Vector *);
    94 	*(QAngle **)vptr = ang;
    95 	vptr += sizeof(QAngle *);
    96 	*(Vector **)vptr = velocity;
    97 	
    98 	s_Teleport.call->Execute(params, NULL);
    99 }
   100 
   101 bool IsTeleportSupported()
   102 {
   103 	return SetupTeleport();
   104 }
   105 
   106 bool SetupGetVelocity()
   107 {
   108 	if (s_GetVelocity.setup)
   109 	{
   110 		return s_GetVelocity.supported;
   111 	}
   112 
   113 	int offset;
   114 	if (g_pGameConf->GetOffset("GetVelocity", &offset))
   115 	{
   116 		PassInfo info[2];
   117 		info[0].flags = info[1].flags = PASSFLAG_BYVAL;
   118 		info[0].size = info[1].size = sizeof(void *);
   119 		info[0].type = info[1].type = PassType_Basic;
   120 
   121 		s_GetVelocity.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 2);
   122 
   123 		if (s_GetVelocity.call != NULL)
   124 		{
   125 			s_GetVelocity.supported = true;
   126 		}
   127 	}
   128 
   129 	s_GetVelocity.setup = true;
   130 
   131 	return s_GetVelocity.supported;
   132 }
   133 
   134 void GetVelocity(CBaseEntity *pEntity, Vector *velocity, AngularImpulse *angvelocity)
   135 {
   136 	unsigned char params[sizeof(void *) * 3];
   137 	unsigned char *vptr = params;
   138 	*(CBaseEntity **)vptr = pEntity;
   139 	vptr += sizeof(CBaseEntity *);
   140 	*(Vector **)vptr = velocity;
   141 	vptr += sizeof(Vector *);
   142 	*(AngularImpulse **)vptr = angvelocity;
   143 
   144 	s_GetVelocity.call->Execute(params, NULL);
   145 }
   146 
   147 bool IsGetVelocitySupported()
   148 {
   149 	return SetupGetVelocity();
   150 }
   151 
   152 bool SetupGetEyeAngles()
   153 {
   154 	if (s_EyeAngles.setup)
   155 	{
   156 		return s_EyeAngles.supported;
   157 	}
   158 
   159 	int offset;
   160 	if (g_pGameConf->GetOffset("EyeAngles", &offset))
   161 	{
   162 		PassInfo info[2];
   163 		info[0].flags = info[1].flags = PASSFLAG_BYVAL;
   164 		info[0].size = info[1].size = sizeof(void *);
   165 		info[0].type = info[1].type = PassType_Basic;
   166 
   167 		s_EyeAngles.call = g_pBinTools->CreateVCall(offset, 0, 0, &info[0], &info[1], 1);
   168 
   169 		if (s_EyeAngles.call != NULL)
   170 		{
   171 			s_EyeAngles.supported = true;
   172 		}
   173 	}
   174 
   175 	s_EyeAngles.setup = true;
   176 
   177 	return s_EyeAngles.supported;
   178 }
   179 
   180 bool GetEyeAngles(CBaseEntity *pEntity, QAngle *pAngles)
   181 {
   182 	if (!IsEyeAnglesSupported())
   183 	{
   184 		return false;
   185 	}
   186 
   187 	QAngle *pRetAngle = NULL;
   188 	unsigned char params[sizeof(void *)];
   189 	unsigned char *vptr = params;
   190 
   191 	*(CBaseEntity **)vptr = pEntity;
   192 	vptr += sizeof(CBaseEntity *);
   193 
   194 	s_EyeAngles.call->Execute(params, &pRetAngle);
   195 
   196 	if (pRetAngle == NULL)
   197 	{
   198 		return false;
   199 	}
   200 
   201 	*pAngles = *pRetAngle;
   202 
   203 	return true;
   204 }
   205 
   206 int GetClientAimTarget(edict_t *pEdict, bool only_players)
   207 {
   208 	CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL;
   209 
   210 	if (pEntity == NULL)
   211 	{
   212 		return -1;
   213 	}
   214 
   215 	Vector eye_position;
   216 	QAngle eye_angles;
   217 
   218 	/* Get the private information we need */
   219 	serverClients->ClientEarPosition(pEdict, &eye_position);
   220 	if (!GetEyeAngles(pEntity, &eye_angles))
   221 	{
   222 		return -2;
   223 	}
   224 
   225 	Vector aim_dir;
   226 	AngleVectors(eye_angles, &aim_dir);
   227 	VectorNormalize(aim_dir);
   228 
   229 	Vector vec_end = eye_position + aim_dir * 8000;
   230 
   231 	Ray_t ray;
   232 	ray.Init(eye_position, vec_end);
   233 
   234 	trace_t tr;
   235 	CTraceFilterSimple simple(pEdict->GetIServerEntity());
   236 
   237 	enginetrace->TraceRay(ray, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, &simple, &tr);
   238 
   239 	if (tr.fraction == 1.0f || tr.m_pEnt == NULL)
   240 	{
   241 		return -1;
   242 	}
   243 
   244 	edict_t *pTarget = gameents->BaseEntityToEdict(tr.m_pEnt);
   245 	if (pTarget == NULL)
   246 	{
   247 		return -1;
   248 	}
   249 
   250 	int ent_index = engine->IndexOfEdict(pTarget);
   251 
   252 	IGamePlayer *pTargetPlayer = playerhelpers->GetGamePlayer(ent_index);
   253 	if (pTargetPlayer != NULL && !pTargetPlayer->IsInGame())
   254 	{
   255 		return -1;
   256 	}
   257 	else if (only_players && pTargetPlayer == NULL)
   258 	{
   259 		return -1;
   260 	}
   261 
   262 	return ent_index;
   263 }
   264 
   265 bool IsEyeAnglesSupported()
   266 {
   267 	return SetupGetEyeAngles();
   268 }
   269 
   270 void ShutdownHelpers()
   271 {
   272 	s_Teleport.Shutdown();
   273 	s_GetVelocity.Shutdown();
   274 }
   275 
   276 const char *GetDTTypeName(int type)
   277 {
   278 	switch (type)
   279 	{
   280 	case DPT_Int:
   281 		{
   282 			return "integer";
   283 		}
   284 	case DPT_Float:
   285 		{
   286 			return "float";
   287 		}
   288 	case DPT_Vector:
   289 		{
   290 			return "vector";
   291 		}
   292 	case DPT_String:
   293 		{
   294 			return "string";
   295 		}
   296 	case DPT_Array:
   297 		{
   298 			return "array";
   299 		}
   300 	case DPT_DataTable:
   301 		{
   302 			return "datatable";
   303 		}
   304 	default:
   305 		{
   306 			return NULL;
   307 		}
   308 	}
   309 
   310 	return NULL;
   311 }
   312 
   313 void UTIL_DrawSendTable_XML(FILE *fp, SendTable *pTable, int space_count)
   314 {
   315 	char spaces[255];
   316 
   317 	for (int i = 0; i < space_count; i++)
   318 	{
   319 		spaces[i] = ' ';
   320 	}
   321 	spaces[space_count] = '\0';
   322 
   323 	const char *type_name;
   324 	SendTable *pOtherTable;
   325 	SendProp *pProp;
   326 
   327 	fprintf(fp, " %s<sendtable name=\"%s\">\n", spaces, pTable->GetName());
   328 	for (int i = 0; i < pTable->GetNumProps(); i++)
   329 	{
   330 		pProp = pTable->GetProp(i);
   331 
   332 		fprintf(fp, "  %s<property name=\"%s\">\n", spaces, pProp->GetName());
   333 
   334 		if ((type_name = GetDTTypeName(pProp->GetType())) != NULL)
   335 		{
   336 			fprintf(fp, "   %s<type>%s</type>\n", spaces, type_name);
   337 		}
   338 		else
   339 		{
   340 			fprintf(fp, "   %s<type>%d</type>\n", spaces, pProp->GetType());
   341 		}
   342 
   343 		fprintf(fp, "   %s<offset>%d</offset>\n", spaces, pProp->GetOffset());
   344 		fprintf(fp, "   %s<bits>%d</bits>\n", spaces, pProp->m_nBits);
   345 
   346 		if ((pOtherTable = pTable->GetProp(i)->GetDataTable()) != NULL)
   347 		{
   348 			UTIL_DrawSendTable_XML(fp, pOtherTable, space_count + 3);
   349 		}
   350 
   351 		fprintf(fp, "  %s</property>\n", spaces);
   352 	}
   353 	fprintf(fp, " %s</sendtable>\n", spaces);
   354 }
   355 
   356 void UTIL_DrawServerClass_XML(FILE *fp, ServerClass *sc)
   357 {
   358 	fprintf(fp, "<serverclass name=\"%s\">\n", sc->GetName());
   359 	UTIL_DrawSendTable_XML(fp, sc->m_pTable, 0);
   360 	fprintf(fp, "</serverclass>\n");
   361 }
   362 
   363 void UTIL_DrawSendTable(FILE *fp, SendTable *pTable, int level)
   364 {
   365 	char spaces[255];
   366 	for (int i=0; i<level; i++)
   367 		spaces[i] = ' ';
   368 	spaces[level] = '\0';
   369 
   370 	const char *name, *type;
   371 	SendProp *pProp;
   372 
   373 	fprintf(fp, "%sSub-Class Table (%d Deep): %s\n", spaces, level, pTable->GetName());
   374 
   375 	for (int i=0; i<pTable->GetNumProps(); i++)
   376 	{
   377 		pProp = pTable->GetProp(i);
   378 		name = pProp->GetName();
   379 		if (pProp->GetDataTable())
   380 		{
   381 			UTIL_DrawSendTable(fp, pProp->GetDataTable(), level + 1);
   382 		}
   383 		else
   384 		{
   385 			type = GetDTTypeName(pProp->GetType());
   386 
   387 			if (type != NULL)
   388 			{
   389 				fprintf(fp,
   390 					"%s-Member: %s (offset %d) (type %s) (bits %d)\n", 
   391 					spaces, 
   392 					pProp->GetName(),
   393 					pProp->GetOffset(),
   394 					type,
   395 					pProp->m_nBits);
   396 			}
   397 			else
   398 			{
   399 				fprintf(fp,
   400 					"%s-Member: %s (offset %d) (type %d) (bits %d)\n", 
   401 					spaces, 
   402 					pProp->GetName(),
   403 					pProp->GetOffset(),
   404 					pProp->GetType(),
   405 					pProp->m_nBits);
   406 			}
   407 		}
   408 	}
   409 }
   410 
   411 CON_COMMAND(sm_dump_netprops_xml, "Dumps the networkable property table as an XML file")
   412 {
   413 #if !defined ORANGEBOX_BUILD
   414 	CCommand args;
   415 #endif
   416 
   417 	if (args.ArgC() < 2)
   418 	{
   419 		META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
   420 		return;
   421 	}
   422 
   423 	const char *file = args.Arg(1);
   424 	if (!file || file[0] == '\0')
   425 	{
   426 		META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
   427 		return;
   428 	}
   429 
   430 	char path[PLATFORM_MAX_PATH];
   431 	g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
   432 
   433 	FILE *fp = NULL;
   434 	if ((fp = fopen(path, "wt")) == NULL)
   435 	{
   436 		META_CONPRINTF("Could not open file \"%s\"\n", path);
   437 		return;
   438 	}
   439 
   440 	fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
   441 	fprintf(fp, "<!-- Dump of all network properties for \"%s\" follows -->\n\n", g_pSM->GetGameFolderName());
   442 
   443 	ServerClass *pBase = gamedll->GetAllServerClasses();
   444 	while (pBase != NULL)
   445 	{
   446 		UTIL_DrawServerClass_XML(fp, pBase);
   447 		pBase = pBase->m_pNext;
   448 	}
   449 
   450 	fclose(fp);
   451 }
   452 
   453 CON_COMMAND(sm_dump_netprops, "Dumps the networkable property table as a text file")
   454 {
   455 #if !defined ORANGEBOX_BUILD
   456 	CCommand args;
   457 #endif
   458 
   459 	if (args.ArgC() < 2)
   460 	{
   461 		META_CONPRINT("Usage: sm_dump_netprops <file>\n");
   462 		return;
   463 	}
   464 
   465 	const char *file = args.Arg(1);
   466 	if (!file || file[0] == '\0')
   467 	{
   468 		META_CONPRINT("Usage: sm_dump_netprops <file>\n");
   469 		return;
   470 	}
   471 
   472 	char path[PLATFORM_MAX_PATH];
   473 	g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
   474 
   475 	FILE *fp = NULL;
   476 	if ((fp = fopen(path, "wt")) == NULL)
   477 	{
   478 		META_CONPRINTF("Could not open file \"%s\"\n", path);
   479 		return;
   480 	}
   481 
   482 	fprintf(fp, "// Dump of all network properties for \"%s\" follows\n//\n\n", g_pSM->GetGameFolderName());
   483 
   484 	ServerClass *pBase = gamedll->GetAllServerClasses();
   485 	while (pBase != NULL)
   486 	{
   487 		fprintf(fp, "%s:\n", pBase->GetName());
   488 		UTIL_DrawSendTable(fp, pBase->m_pTable, 1);
   489 		pBase = pBase->m_pNext;
   490 	}
   491 
   492 	fclose(fp);
   493 }
   494