fixed a compat regression, forgot msvc does funky things with overloaded virtual calls
3 * =============================================================================
4 * SourceMod SDKTools Extension
5 * Copyright (C) 2004-2008 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"
36 CallHelper s_Teleport;
37 CallHelper s_GetVelocity;
38 CallHelper s_EyeAngles;
40 class CTraceFilterSimple : public CTraceFilterEntitiesOnly
43 CTraceFilterSimple(const IHandleEntity *passentity): m_pPassEnt(passentity)
46 virtual bool ShouldHitEntity(IHandleEntity *pServerEntity, int contentsMask)
48 if (pServerEntity == m_pPassEnt)
55 const IHandleEntity *m_pPassEnt;
62 return s_Teleport.supported;
67 if (g_pGameConf->GetOffset("Teleport", &offset))
70 info[0].flags = info[1].flags = info[2].flags = PASSFLAG_BYVAL;
71 info[0].size = info[1].size = info[2].size = sizeof(void *);
72 info[0].type = info[1].type = info[2].type = PassType_Basic;
74 s_Teleport.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 3);
76 if (s_Teleport.call != NULL)
78 s_Teleport.supported = true;
82 s_Teleport.setup = true;
84 return s_Teleport.supported;
87 void Teleport(CBaseEntity *pEntity, Vector *origin, QAngle *ang, Vector *velocity)
89 unsigned char params[sizeof(void *) * 4];
90 unsigned char *vptr = params;
91 *(CBaseEntity **)vptr = pEntity;
92 vptr += sizeof(CBaseEntity *);
93 *(Vector **)vptr = origin;
94 vptr += sizeof(Vector *);
95 *(QAngle **)vptr = ang;
96 vptr += sizeof(QAngle *);
97 *(Vector **)vptr = velocity;
99 s_Teleport.call->Execute(params, NULL);
102 bool IsTeleportSupported()
104 return SetupTeleport();
107 bool SetupGetVelocity()
109 if (s_GetVelocity.setup)
111 return s_GetVelocity.supported;
115 if (g_pGameConf->GetOffset("GetVelocity", &offset))
118 info[0].flags = info[1].flags = PASSFLAG_BYVAL;
119 info[0].size = info[1].size = sizeof(void *);
120 info[0].type = info[1].type = PassType_Basic;
122 s_GetVelocity.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 2);
124 if (s_GetVelocity.call != NULL)
126 s_GetVelocity.supported = true;
130 s_GetVelocity.setup = true;
132 return s_GetVelocity.supported;
135 void GetVelocity(CBaseEntity *pEntity, Vector *velocity, AngularImpulse *angvelocity)
137 unsigned char params[sizeof(void *) * 3];
138 unsigned char *vptr = params;
139 *(CBaseEntity **)vptr = pEntity;
140 vptr += sizeof(CBaseEntity *);
141 *(Vector **)vptr = velocity;
142 vptr += sizeof(Vector *);
143 *(AngularImpulse **)vptr = angvelocity;
145 s_GetVelocity.call->Execute(params, NULL);
148 bool IsGetVelocitySupported()
150 return SetupGetVelocity();
153 bool SetupGetEyeAngles()
155 if (s_EyeAngles.setup)
157 return s_EyeAngles.supported;
161 if (g_pGameConf->GetOffset("EyeAngles", &offset))
164 info[0].flags = PASSFLAG_BYVAL;
165 info[0].size = sizeof(void *);
166 info[0].type = PassType_Basic;
168 s_EyeAngles.call = g_pBinTools->CreateVCall(offset, 0, 0, info, NULL, 0);
170 if (s_EyeAngles.call != NULL)
172 s_EyeAngles.supported = true;
176 s_EyeAngles.setup = true;
178 return s_EyeAngles.supported;
181 bool GetEyeAngles(CBaseEntity *pEntity, QAngle *pAngles)
183 if (!IsEyeAnglesSupported())
188 QAngle *pRetAngle = NULL;
189 unsigned char params[sizeof(void *)];
190 unsigned char *vptr = params;
192 *(CBaseEntity **)vptr = pEntity;
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 bool GetPlayerInfo(int client, player_info_t *info)
272 #if defined ORANGEBOX_BUILD
273 return engine->GetPlayerInfo(client, info);
275 return (iserver) ? iserver->GetPlayerInfo(client-1, info) : false;
279 void ShutdownHelpers()
281 s_Teleport.Shutdown();
282 s_GetVelocity.Shutdown();
283 s_EyeAngles.Shutdown();
286 const char *GetDTTypeName(int type)
323 void UTIL_DrawSendTable_XML(FILE *fp, SendTable *pTable, int space_count)
327 for (int i = 0; i < space_count; i++)
331 spaces[space_count] = '\0';
333 const char *type_name;
334 SendTable *pOtherTable;
337 fprintf(fp, " %s<sendtable name=\"%s\">\n", spaces, pTable->GetName());
338 for (int i = 0; i < pTable->GetNumProps(); i++)
340 pProp = pTable->GetProp(i);
342 fprintf(fp, " %s<property name=\"%s\">\n", spaces, pProp->GetName());
344 if ((type_name = GetDTTypeName(pProp->GetType())) != NULL)
346 fprintf(fp, " %s<type>%s</type>\n", spaces, type_name);
350 fprintf(fp, " %s<type>%d</type>\n", spaces, pProp->GetType());
353 fprintf(fp, " %s<offset>%d</offset>\n", spaces, pProp->GetOffset());
354 fprintf(fp, " %s<bits>%d</bits>\n", spaces, pProp->m_nBits);
356 if ((pOtherTable = pTable->GetProp(i)->GetDataTable()) != NULL)
358 UTIL_DrawSendTable_XML(fp, pOtherTable, space_count + 3);
361 fprintf(fp, " %s</property>\n", spaces);
363 fprintf(fp, " %s</sendtable>\n", spaces);
366 void UTIL_DrawServerClass_XML(FILE *fp, ServerClass *sc)
368 fprintf(fp, "<serverclass name=\"%s\">\n", sc->GetName());
369 UTIL_DrawSendTable_XML(fp, sc->m_pTable, 0);
370 fprintf(fp, "</serverclass>\n");
373 void UTIL_DrawSendTable(FILE *fp, SendTable *pTable, int level)
376 for (int i=0; i<level; i++)
378 spaces[level] = '\0';
380 const char *name, *type;
383 fprintf(fp, "%sSub-Class Table (%d Deep): %s\n", spaces, level, pTable->GetName());
385 for (int i=0; i<pTable->GetNumProps(); i++)
387 pProp = pTable->GetProp(i);
388 name = pProp->GetName();
389 if (pProp->GetDataTable())
391 UTIL_DrawSendTable(fp, pProp->GetDataTable(), level + 1);
395 type = GetDTTypeName(pProp->GetType());
400 "%s-Member: %s (offset %d) (type %s) (bits %d)\n",
410 "%s-Member: %s (offset %d) (type %d) (bits %d)\n",
421 CON_COMMAND(sm_dump_netprops_xml, "Dumps the networkable property table as an XML file")
423 #if !defined ORANGEBOX_BUILD
429 META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
433 const char *file = args.Arg(1);
434 if (!file || file[0] == '\0')
436 META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
440 char path[PLATFORM_MAX_PATH];
441 g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
444 if ((fp = fopen(path, "wt")) == NULL)
446 META_CONPRINTF("Could not open file \"%s\"\n", path);
450 fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
451 fprintf(fp, "<!-- Dump of all network properties for \"%s\" follows -->\n\n", g_pSM->GetGameFolderName());
453 ServerClass *pBase = gamedll->GetAllServerClasses();
454 while (pBase != NULL)
456 UTIL_DrawServerClass_XML(fp, pBase);
457 pBase = pBase->m_pNext;
463 CON_COMMAND(sm_dump_netprops, "Dumps the networkable property table as a text file")
465 #if !defined ORANGEBOX_BUILD
471 META_CONPRINT("Usage: sm_dump_netprops <file>\n");
475 const char *file = args.Arg(1);
476 if (!file || file[0] == '\0')
478 META_CONPRINT("Usage: sm_dump_netprops <file>\n");
482 char path[PLATFORM_MAX_PATH];
483 g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
486 if ((fp = fopen(path, "wt")) == NULL)
488 META_CONPRINTF("Could not open file \"%s\"\n", path);
492 fprintf(fp, "// Dump of all network properties for \"%s\" follows\n//\n\n", g_pSM->GetGameFolderName());
494 ServerClass *pBase = gamedll->GetAllServerClasses();
495 while (pBase != NULL)
497 fprintf(fp, "%s:\n", pBase->GetName());
498 UTIL_DrawSendTable(fp, pBase->m_pTable, 1);
499 pBase = pBase->m_pNext;
505 #if defined SUBPLATFORM_SECURECRT
506 void _ignore_invalid_parameter(
507 const wchar_t * expression,
508 const wchar_t * function,
509 const wchar_t * file,
514 /* Wow we don't care, thanks Microsoft. */
518 CON_COMMAND(sm_dump_classes, "Dumps the class list as a text file")
520 #if !defined ORANGEBOX_BUILD
526 META_CONPRINT("Usage: sm_dump_classes <file>\n");
530 const char *file = args.Arg(1);
531 if (!file || file[0] == '\0')
533 META_CONPRINT("Usage: sm_dump_classes <file>\n");
537 ICallWrapper *pWrapper = NULL;
542 retData.flags = PASSFLAG_BYVAL;
543 retData.size = sizeof(void *);
544 retData.type = PassType_Basic;
547 if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || addr == NULL)
549 META_CONPRINT("Failed to locate function\n");
553 pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0);
557 void *returnData = NULL;
559 pWrapper->Execute(NULL, &returnData);
563 if (returnData == NULL)
568 CEntityFactoryDictionary *dict = ( CEntityFactoryDictionary * )returnData;
575 char path[PLATFORM_MAX_PATH];
576 g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
579 if ((fp = fopen(path, "wt")) == NULL)
581 META_CONPRINTF("Could not open file \"%s\"\n", path);
588 #if defined SUBPLATFORM_SECURECRT
589 _invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
592 time_t t = g_pSM->GetAdjustedTime();
593 size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t));
595 #if defined SUBPLATFORM_SECURECRT
596 _set_invalid_parameter_handler(handler);
599 fprintf(fp, "// Dump of all classes for \"%s\" as at %s\n//\n\n", g_pSM->GetGameFolderName(), buffer);
601 for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) )
603 IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i));
604 ServerClass *sclass = entity->GetServerClass();
605 fprintf(fp,"%s - %s\n",sclass->GetName(), dict->m_Factories.GetElementName(i));
607 typedescription_t *datamap = gamehelpers->FindInDataMap(gamehelpers->GetDataMap(entity->GetBaseEntity()), "m_iEFlags");
609 int *eflags = (int *)((char *)entity->GetBaseEntity() + datamap->fieldOffset[TD_OFFSET_NORMAL]);
610 *eflags |= (1<<0); // EFL_KILLME
617 char *UTIL_FlagsToString(int flags)
619 static char str[1024];
622 if (flags & FTYPEDESC_GLOBAL)
624 strcat(str, "Global|");
626 if (flags & FTYPEDESC_SAVE)
628 strcat(str, "Save|");
630 if (flags & FTYPEDESC_KEY)
634 if (flags & FTYPEDESC_INPUT)
636 strcat(str, "Input|");
638 if (flags & FTYPEDESC_OUTPUT)
640 strcat(str, "Output|");
642 if (flags & FTYPEDESC_FUNCTIONTABLE)
644 strcat(str, "FunctionTable|");
646 if (flags & FTYPEDESC_PTR)
650 if (flags & FTYPEDESC_OVERRIDE)
652 strcat(str, "Override|");
655 int len = strlen(str) - 1;
658 str[len] = 0; // Strip the final '|'
664 void UTIL_DrawDataTable(FILE *fp, datamap_t *pMap, int level)
668 for (int i=0; i<level; i++)
673 spaces[level] = '\0';
675 const char *externalname;
680 for (int i=0; i<pMap->dataNumFields; i++)
682 if (pMap->dataDesc[i].fieldName == NULL)
687 if (pMap->dataDesc[i].td)
689 fprintf(fp, " %sSub-Class Table (%d Deep): %s - %s\n", spaces, level+1, pMap->dataDesc[i].fieldName, pMap->dataDesc[i].td->dataClassName);
690 UTIL_DrawDataTable(fp, pMap->dataDesc[i].td, level+1);
694 externalname = pMap->dataDesc[i].externalName;
695 flags = UTIL_FlagsToString(pMap->dataDesc[i].flags);
697 if (externalname == NULL)
699 fprintf(fp,"%s- %s (%s)(%i Bytes)\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes);
703 fprintf(fp,"%s- %s (%s)(%i Bytes) - %s\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes, externalname);
707 pMap = pMap->baseMap;
711 CON_COMMAND(sm_dump_datamaps, "Dumps the data map list as a text file")
713 #if !defined ORANGEBOX_BUILD
719 META_CONPRINT("Usage: sm_dump_datamaps <file>\n");
723 const char *file = args.Arg(1);
724 if (!file || file[0] == '\0')
726 META_CONPRINT("Usage: sm_dump_datamaps <file>\n");
730 ICallWrapper *pWrapper = NULL;
735 retData.flags = PASSFLAG_BYVAL;
736 retData.size = sizeof(void *);
737 retData.type = PassType_Basic;
740 if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || addr == NULL)
742 META_CONPRINT("Failed to locate function\n");
746 pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0);
750 void *returnData = NULL;
752 pWrapper->Execute(NULL, &returnData);
756 if (returnData == NULL)
761 CEntityFactoryDictionary *dict = ( CEntityFactoryDictionary * )returnData;
768 char path[PLATFORM_MAX_PATH];
769 g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
772 if ((fp = fopen(path, "wt")) == NULL)
774 META_CONPRINTF("Could not open file \"%s\"\n", path);
781 #if defined SUBPLATFORM_SECURECRT
782 _invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
785 time_t t = g_pSM->GetAdjustedTime();
786 size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t));
788 #if defined SUBPLATFORM_SECURECRT
789 _set_invalid_parameter_handler(handler);
792 fprintf(fp, "// Dump of all datamaps for \"%s\" as at %s\n//\n//\n", g_pSM->GetGameFolderName(), buffer);
795 fprintf(fp, "// Flag Details:\n//\n");
797 fprintf(fp, "// Global: This field is masked for global entity save/restore\n");
798 fprintf(fp, "// Save: This field is saved to disk\n");
799 fprintf(fp, "// Key: This field can be requested and written to by string name at load time\n");
800 fprintf(fp, "// Input: This field can be written to by string name at run time, and a function called\n");
801 fprintf(fp, "// Output: This field propogates it's value to all targets whenever it changes\n");
802 fprintf(fp, "// FunctionTable: This is a table entry for a member function pointer\n");
803 fprintf(fp, "// Ptr: This field is a pointer, not an embedded object\n");
804 fprintf(fp, "// Override: The field is an override for one in a base class (only used by prediction system for now)\n");
806 fprintf(fp, "//\n\n");
808 for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) )
810 IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i));
811 ServerClass *sclass = entity->GetServerClass();
812 datamap_t *pMap = gamehelpers->GetDataMap(entity->GetBaseEntity());
814 fprintf(fp,"%s - %s\n", sclass->GetName(), dict->m_Factories.GetElementName(i));
816 UTIL_DrawDataTable(fp, pMap, 0);
818 typedescription_t *datamap = gamehelpers->FindInDataMap(pMap, "m_iEFlags");
820 int *eflags = (int *)((char *)entity->GetBaseEntity() + datamap->fieldOffset[TD_OFFSET_NORMAL]);
821 *eflags |= (1<<0); // EFL_KILLME