3 * =============================================================================
4 * SourceMod SDKTools Extension
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * =============================================================================
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.
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
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/>.
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>.
32 #include "extension.h"
35 CallHelper s_Teleport;
36 CallHelper s_GetVelocity;
37 CallHelper s_EyeAngles;
39 class CTraceFilterSimple : public CTraceFilterEntitiesOnly
42 CTraceFilterSimple(const IHandleEntity *passentity): m_pPassEnt(passentity)
45 virtual bool ShouldHitEntity(IHandleEntity *pServerEntity, int contentsMask)
47 if (pServerEntity == m_pPassEnt)
54 const IHandleEntity *m_pPassEnt;
61 return s_Teleport.supported;
66 if (g_pGameConf->GetOffset("Teleport", &offset))
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;
73 s_Teleport.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 3);
75 if (s_Teleport.call != NULL)
77 s_Teleport.supported = true;
81 s_Teleport.setup = true;
83 return s_Teleport.supported;
86 void Teleport(CBaseEntity *pEntity, Vector *origin, QAngle *ang, Vector *velocity)
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;
98 s_Teleport.call->Execute(params, NULL);
101 bool IsTeleportSupported()
103 return SetupTeleport();
106 bool SetupGetVelocity()
108 if (s_GetVelocity.setup)
110 return s_GetVelocity.supported;
114 if (g_pGameConf->GetOffset("GetVelocity", &offset))
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;
121 s_GetVelocity.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 2);
123 if (s_GetVelocity.call != NULL)
125 s_GetVelocity.supported = true;
129 s_GetVelocity.setup = true;
131 return s_GetVelocity.supported;
134 void GetVelocity(CBaseEntity *pEntity, Vector *velocity, AngularImpulse *angvelocity)
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;
144 s_GetVelocity.call->Execute(params, NULL);
147 bool IsGetVelocitySupported()
149 return SetupGetVelocity();
152 bool SetupGetEyeAngles()
154 if (s_EyeAngles.setup)
156 return s_EyeAngles.supported;
160 if (g_pGameConf->GetOffset("EyeAngles", &offset))
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;
167 s_EyeAngles.call = g_pBinTools->CreateVCall(offset, 0, 0, &info[0], &info[1], 1);
169 if (s_EyeAngles.call != NULL)
171 s_EyeAngles.supported = true;
175 s_EyeAngles.setup = true;
177 return s_EyeAngles.supported;
180 bool GetEyeAngles(CBaseEntity *pEntity, QAngle *pAngles)
182 if (!IsEyeAnglesSupported())
187 QAngle *pRetAngle = NULL;
188 unsigned char params[sizeof(void *)];
189 unsigned char *vptr = params;
191 *(CBaseEntity **)vptr = pEntity;
192 vptr += sizeof(CBaseEntity *);
194 s_EyeAngles.call->Execute(params, &pRetAngle);
196 if (pRetAngle == NULL)
201 *pAngles = *pRetAngle;
206 int GetClientAimTarget(edict_t *pEdict, bool only_players)
208 CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL;
218 /* Get the private information we need */
219 serverClients->ClientEarPosition(pEdict, &eye_position);
220 if (!GetEyeAngles(pEntity, &eye_angles))
226 AngleVectors(eye_angles, &aim_dir);
227 VectorNormalize(aim_dir);
229 Vector vec_end = eye_position + aim_dir * 8000;
232 ray.Init(eye_position, vec_end);
235 CTraceFilterSimple simple(pEdict->GetIServerEntity());
237 enginetrace->TraceRay(ray, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, &simple, &tr);
239 if (tr.fraction == 1.0f || tr.m_pEnt == NULL)
244 edict_t *pTarget = gameents->BaseEntityToEdict(tr.m_pEnt);
250 int ent_index = engine->IndexOfEdict(pTarget);
252 IGamePlayer *pTargetPlayer = playerhelpers->GetGamePlayer(ent_index);
253 if (pTargetPlayer != NULL && !pTargetPlayer->IsInGame())
257 else if (only_players && pTargetPlayer == NULL)
265 bool IsEyeAnglesSupported()
267 return SetupGetEyeAngles();
270 void ShutdownHelpers()
272 s_Teleport.Shutdown();
273 s_GetVelocity.Shutdown();
276 const char *GetDTTypeName(int type)
313 void UTIL_DrawSendTable_XML(FILE *fp, SendTable *pTable, int space_count)
317 for (int i = 0; i < space_count; i++)
321 spaces[space_count] = '\0';
323 const char *type_name;
324 SendTable *pOtherTable;
327 fprintf(fp, " %s<sendtable name=\"%s\">\n", spaces, pTable->GetName());
328 for (int i = 0; i < pTable->GetNumProps(); i++)
330 pProp = pTable->GetProp(i);
332 fprintf(fp, " %s<property name=\"%s\">\n", spaces, pProp->GetName());
334 if ((type_name = GetDTTypeName(pProp->GetType())) != NULL)
336 fprintf(fp, " %s<type>%s</type>\n", spaces, type_name);
340 fprintf(fp, " %s<type>%d</type>\n", spaces, pProp->GetType());
343 fprintf(fp, " %s<offset>%d</offset>\n", spaces, pProp->GetOffset());
344 fprintf(fp, " %s<bits>%d</bits>\n", spaces, pProp->m_nBits);
346 if ((pOtherTable = pTable->GetProp(i)->GetDataTable()) != NULL)
348 UTIL_DrawSendTable_XML(fp, pOtherTable, space_count + 3);
351 fprintf(fp, " %s</property>\n", spaces);
353 fprintf(fp, " %s</sendtable>\n", spaces);
356 void UTIL_DrawServerClass_XML(FILE *fp, ServerClass *sc)
358 fprintf(fp, "<serverclass name=\"%s\">\n", sc->GetName());
359 UTIL_DrawSendTable_XML(fp, sc->m_pTable, 0);
360 fprintf(fp, "</serverclass>\n");
363 void UTIL_DrawSendTable(FILE *fp, SendTable *pTable, int level)
366 for (int i=0; i<level; i++)
368 spaces[level] = '\0';
370 const char *name, *type;
373 fprintf(fp, "%sSub-Class Table (%d Deep): %s\n", spaces, level, pTable->GetName());
375 for (int i=0; i<pTable->GetNumProps(); i++)
377 pProp = pTable->GetProp(i);
378 name = pProp->GetName();
379 if (pProp->GetDataTable())
381 UTIL_DrawSendTable(fp, pProp->GetDataTable(), level + 1);
385 type = GetDTTypeName(pProp->GetType());
390 "%s-Member: %s (offset %d) (type %s) (bits %d)\n",
400 "%s-Member: %s (offset %d) (type %d) (bits %d)\n",
411 CON_COMMAND(sm_dump_netprops_xml, "Dumps the networkable property table as an XML file")
413 #if !defined ORANGEBOX_BUILD
419 META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
423 const char *file = args.Arg(1);
424 if (!file || file[0] == '\0')
426 META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
430 char path[PLATFORM_MAX_PATH];
431 g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
434 if ((fp = fopen(path, "wt")) == NULL)
436 META_CONPRINTF("Could not open file \"%s\"\n", path);
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());
443 ServerClass *pBase = gamedll->GetAllServerClasses();
444 while (pBase != NULL)
446 UTIL_DrawServerClass_XML(fp, pBase);
447 pBase = pBase->m_pNext;
453 CON_COMMAND(sm_dump_netprops, "Dumps the networkable property table as a text file")
455 #if !defined ORANGEBOX_BUILD
461 META_CONPRINT("Usage: sm_dump_netprops <file>\n");
465 const char *file = args.Arg(1);
466 if (!file || file[0] == '\0')
468 META_CONPRINT("Usage: sm_dump_netprops <file>\n");
472 char path[PLATFORM_MAX_PATH];
473 g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
476 if ((fp = fopen(path, "wt")) == NULL)
478 META_CONPRINTF("Could not open file \"%s\"\n", path);
482 fprintf(fp, "// Dump of all network properties for \"%s\" follows\n//\n\n", g_pSM->GetGameFolderName());
484 ServerClass *pBase = gamedll->GetAllServerClasses();
485 while (pBase != NULL)
487 fprintf(fp, "%s:\n", pBase->GetName());
488 UTIL_DrawSendTable(fp, pBase->m_pTable, 1);
489 pBase = pBase->m_pNext;