dvander@1169: /** dvander@1169: * vim: set ts=4 : ds@1330: * ============================================================================= dvander@1233: * SourceMod SDKTools Extension ds@3099: * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved. ds@1330: * ============================================================================= dvander@1169: * ds@1330: * This program is free software; you can redistribute it and/or modify it under ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the ds@1330: * Free Software Foundation. dvander@1233: * ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1330: * details. dvander@1233: * ds@1330: * You should have received a copy of the GNU General Public License along with ds@1330: * this program. If not, see . dvander@1233: * ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1330: * this exception to all derivative works. AlliedModders LLC defines further ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1330: * or . dvander@1169: * dvander@1169: * Version: $Id$ dvander@1169: */ dvander@1233: dvander@1169: #include "extension.h" pred@1922: #include "util.h" dvander@1169: #include "vhelpers.h" skamonkey@3333: #include "vglobals.h" dvander@1169: dvander@1169: CallHelper s_Teleport; dvander@1169: CallHelper s_GetVelocity; dvander@1611: CallHelper s_EyeAngles; dvander@1169: dvander@1628: class CTraceFilterSimple : public CTraceFilterEntitiesOnly dvander@1628: { dvander@1628: public: dvander@1628: CTraceFilterSimple(const IHandleEntity *passentity): m_pPassEnt(passentity) dvander@1628: { dvander@1628: } dvander@1628: virtual bool ShouldHitEntity(IHandleEntity *pServerEntity, int contentsMask) dvander@1628: { dvander@1628: if (pServerEntity == m_pPassEnt) dvander@1628: { dvander@1628: return false; dvander@1628: } dvander@1628: return true; dvander@1628: } dvander@1628: private: dvander@1628: const IHandleEntity *m_pPassEnt; dvander@1628: }; dvander@1628: dvander@1169: bool SetupTeleport() dvander@1169: { dvander@1169: if (s_Teleport.setup) dvander@1169: { dvander@1169: return s_Teleport.supported; dvander@1169: } dvander@1169: dvander@1169: /* Setup Teleport */ dvander@1169: int offset; dvander@1169: if (g_pGameConf->GetOffset("Teleport", &offset)) dvander@1169: { dvander@1169: PassInfo info[3]; dvander@1169: info[0].flags = info[1].flags = info[2].flags = PASSFLAG_BYVAL; dvander@1169: info[0].size = info[1].size = info[2].size = sizeof(void *); dvander@1169: info[0].type = info[1].type = info[2].type = PassType_Basic; dvander@1169: dvander@1169: s_Teleport.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 3); dvander@1169: dvander@1611: if (s_Teleport.call != NULL) dvander@1169: { dvander@1169: s_Teleport.supported = true; dvander@1169: } dvander@1169: } dvander@1169: dvander@1169: s_Teleport.setup = true; dvander@1169: dvander@1169: return s_Teleport.supported; dvander@1169: } dvander@1169: dvander@1169: void Teleport(CBaseEntity *pEntity, Vector *origin, QAngle *ang, Vector *velocity) dvander@1169: { dvander@1169: unsigned char params[sizeof(void *) * 4]; dvander@1169: unsigned char *vptr = params; dvander@1169: *(CBaseEntity **)vptr = pEntity; dvander@1169: vptr += sizeof(CBaseEntity *); dvander@1169: *(Vector **)vptr = origin; dvander@1169: vptr += sizeof(Vector *); dvander@1169: *(QAngle **)vptr = ang; dvander@1169: vptr += sizeof(QAngle *); dvander@1169: *(Vector **)vptr = velocity; dvander@1169: dvander@1169: s_Teleport.call->Execute(params, NULL); dvander@1169: } dvander@1169: dvander@1169: bool IsTeleportSupported() dvander@1169: { dvander@1169: return SetupTeleport(); dvander@1169: } dvander@1169: dvander@1169: bool SetupGetVelocity() dvander@1169: { dvander@1169: if (s_GetVelocity.setup) dvander@1169: { dvander@1169: return s_GetVelocity.supported; dvander@1169: } dvander@1169: dvander@1169: int offset; dvander@1169: if (g_pGameConf->GetOffset("GetVelocity", &offset)) dvander@1169: { dvander@1169: PassInfo info[2]; dvander@1169: info[0].flags = info[1].flags = PASSFLAG_BYVAL; dvander@1169: info[0].size = info[1].size = sizeof(void *); dvander@1169: info[0].type = info[1].type = PassType_Basic; dvander@1169: dvander@1169: s_GetVelocity.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 2); dvander@1169: dvander@1611: if (s_GetVelocity.call != NULL) dvander@1169: { dvander@1169: s_GetVelocity.supported = true; dvander@1169: } dvander@1169: } dvander@1169: dvander@1169: s_GetVelocity.setup = true; dvander@1169: dvander@1169: return s_GetVelocity.supported; dvander@1169: } dvander@1169: dvander@1169: void GetVelocity(CBaseEntity *pEntity, Vector *velocity, AngularImpulse *angvelocity) dvander@1169: { dvander@1169: unsigned char params[sizeof(void *) * 3]; dvander@1169: unsigned char *vptr = params; dvander@1169: *(CBaseEntity **)vptr = pEntity; dvander@1169: vptr += sizeof(CBaseEntity *); dvander@1169: *(Vector **)vptr = velocity; dvander@1169: vptr += sizeof(Vector *); dvander@1169: *(AngularImpulse **)vptr = angvelocity; dvander@1169: dvander@1169: s_GetVelocity.call->Execute(params, NULL); dvander@1169: } dvander@1169: dvander@1169: bool IsGetVelocitySupported() dvander@1169: { dvander@1169: return SetupGetVelocity(); dvander@1169: } dvander@1169: dvander@1611: bool SetupGetEyeAngles() dvander@1611: { dvander@1611: if (s_EyeAngles.setup) dvander@1611: { dvander@1611: return s_EyeAngles.supported; dvander@1611: } dvander@1611: dvander@1611: int offset; dvander@1611: if (g_pGameConf->GetOffset("EyeAngles", &offset)) dvander@1611: { ds@2037: PassInfo info[1]; ds@2037: info[0].flags = PASSFLAG_BYVAL; ds@2037: info[0].size = sizeof(void *); ds@2037: info[0].type = PassType_Basic; dvander@1611: ds@2037: s_EyeAngles.call = g_pBinTools->CreateVCall(offset, 0, 0, info, NULL, 0); dvander@1611: dvander@1611: if (s_EyeAngles.call != NULL) dvander@1611: { dvander@1611: s_EyeAngles.supported = true; dvander@1611: } dvander@1611: } dvander@1611: dvander@1611: s_EyeAngles.setup = true; dvander@1611: dvander@1611: return s_EyeAngles.supported; dvander@1611: } dvander@1611: dvander@1611: bool GetEyeAngles(CBaseEntity *pEntity, QAngle *pAngles) dvander@1611: { dvander@1611: if (!IsEyeAnglesSupported()) dvander@1611: { dvander@1611: return false; dvander@1611: } dvander@1611: dvander@1611: QAngle *pRetAngle = NULL; dvander@1611: unsigned char params[sizeof(void *)]; dvander@1611: unsigned char *vptr = params; dvander@1611: dvander@1611: *(CBaseEntity **)vptr = pEntity; dvander@1611: dvander@1611: s_EyeAngles.call->Execute(params, &pRetAngle); dvander@1611: dvander@1611: if (pRetAngle == NULL) dvander@1611: { dvander@1611: return false; dvander@1611: } dvander@1611: dvander@1611: *pAngles = *pRetAngle; dvander@1611: dvander@1611: return true; dvander@1611: } dvander@1611: dvander@1628: int GetClientAimTarget(edict_t *pEdict, bool only_players) dvander@1628: { dvander@1628: CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL; dvander@1628: dvander@1628: if (pEntity == NULL) dvander@1628: { dvander@1628: return -1; dvander@1628: } dvander@1628: dvander@1628: Vector eye_position; dvander@1628: QAngle eye_angles; dvander@1628: dvander@1628: /* Get the private information we need */ skamonkey@3913: #if SOURCE_ENGINE == SE_DOTA skamonkey@3913: serverClients->ClientEarPosition(IndexOfEdict(pEdict), &eye_position); skamonkey@3913: #else dvander@1628: serverClients->ClientEarPosition(pEdict, &eye_position); skamonkey@3913: #endif skamonkey@3913: dvander@1628: if (!GetEyeAngles(pEntity, &eye_angles)) dvander@1628: { dvander@1628: return -2; dvander@1628: } dvander@1628: dvander@1628: Vector aim_dir; dvander@1628: AngleVectors(eye_angles, &aim_dir); dvander@1628: VectorNormalize(aim_dir); dvander@1628: dvander@1628: Vector vec_end = eye_position + aim_dir * 8000; dvander@1628: dvander@1628: Ray_t ray; dvander@1628: ray.Init(eye_position, vec_end); dvander@1628: dvander@1628: trace_t tr; dvander@1628: CTraceFilterSimple simple(pEdict->GetIServerEntity()); dvander@1628: dvander@1628: enginetrace->TraceRay(ray, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, &simple, &tr); dvander@1628: dvander@1628: if (tr.fraction == 1.0f || tr.m_pEnt == NULL) dvander@1628: { dvander@1628: return -1; dvander@1628: } dvander@1628: pred@2746: int ent_ref = gamehelpers->EntityToBCompatRef(tr.m_pEnt); pred@2746: int ent_index = gamehelpers->ReferenceToIndex(ent_ref); dvander@1628: dvander@1628: IGamePlayer *pTargetPlayer = playerhelpers->GetGamePlayer(ent_index); dvander@1628: if (pTargetPlayer != NULL && !pTargetPlayer->IsInGame()) dvander@1628: { dvander@1628: return -1; dvander@1628: } dvander@1628: else if (only_players && pTargetPlayer == NULL) dvander@1628: { dvander@1628: return -1; dvander@1628: } dvander@1628: pred@2746: return ent_ref; dvander@1628: } dvander@1628: dvander@1611: bool IsEyeAnglesSupported() dvander@1611: { dvander@1611: return SetupGetEyeAngles(); dvander@1611: } dvander@1611: faluco@1769: bool GetPlayerInfo(int client, player_info_t *info) faluco@1769: { ds@2400: #if SOURCE_ENGINE >= SE_ORANGEBOX faluco@1769: return engine->GetPlayerInfo(client, info); faluco@1769: #else faluco@1773: return (iserver) ? iserver->GetPlayerInfo(client-1, info) : false; faluco@1769: #endif faluco@1769: } faluco@1769: dvander@1169: void ShutdownHelpers() dvander@1169: { dvander@1169: s_Teleport.Shutdown(); dvander@1169: s_GetVelocity.Shutdown(); faluco@2157: s_EyeAngles.Shutdown(); dvander@1169: } dvander@1636: skamonkey@3816: bool FindNestedDataTable(SendTable *pTable, const char *name) skamonkey@3816: { skamonkey@3816: if (strcmp(pTable->GetName(), name) == 0) skamonkey@3816: { skamonkey@3816: return true; skamonkey@3816: } skamonkey@3816: skamonkey@3816: int props = pTable->GetNumProps(); skamonkey@3816: SendProp *prop; skamonkey@3816: skamonkey@3816: for (int i=0; iGetProp(i); skamonkey@3816: if (prop->GetDataTable()) skamonkey@3816: { skamonkey@3816: if (FindNestedDataTable(prop->GetDataTable(), name)) skamonkey@3816: { skamonkey@3816: return true; skamonkey@3816: } skamonkey@3816: } skamonkey@3816: } skamonkey@3816: skamonkey@3816: return false; skamonkey@3816: } skamonkey@3816: dvander@1636: void UTIL_DrawSendTable_XML(FILE *fp, SendTable *pTable, int space_count) dvander@1636: { dvander@1636: char spaces[255]; dvander@1636: dvander@1636: for (int i = 0; i < space_count; i++) dvander@1636: { dvander@1636: spaces[i] = ' '; dvander@1636: } dvander@1636: spaces[space_count] = '\0'; dvander@1636: dvander@1636: const char *type_name; dvander@1636: SendTable *pOtherTable; dvander@1636: SendProp *pProp; dvander@1636: dvander@1636: fprintf(fp, " %s\n", spaces, pTable->GetName()); dvander@1636: for (int i = 0; i < pTable->GetNumProps(); i++) dvander@1636: { dvander@1636: pProp = pTable->GetProp(i); dvander@1636: dvander@1636: fprintf(fp, " %s\n", spaces, pProp->GetName()); dvander@1636: dvander@1636: if ((type_name = GetDTTypeName(pProp->GetType())) != NULL) dvander@1636: { dvander@1636: fprintf(fp, " %s%s\n", spaces, type_name); dvander@1636: } dvander@1636: else dvander@1636: { dvander@1636: fprintf(fp, " %s%d\n", spaces, pProp->GetType()); dvander@1636: } dvander@1636: dvander@1636: fprintf(fp, " %s%d\n", spaces, pProp->GetOffset()); dvander@1636: fprintf(fp, " %s%d\n", spaces, pProp->m_nBits); dvander@1636: dvander@1636: if ((pOtherTable = pTable->GetProp(i)->GetDataTable()) != NULL) dvander@1636: { dvander@1636: UTIL_DrawSendTable_XML(fp, pOtherTable, space_count + 3); dvander@1636: } dvander@1636: dvander@1636: fprintf(fp, " %s\n", spaces); dvander@1636: } dvander@1636: fprintf(fp, " %s\n", spaces); dvander@1636: } dvander@1636: dvander@1636: void UTIL_DrawServerClass_XML(FILE *fp, ServerClass *sc) dvander@1636: { dvander@1636: fprintf(fp, "\n", sc->GetName()); dvander@1636: UTIL_DrawSendTable_XML(fp, sc->m_pTable, 0); dvander@1636: fprintf(fp, "\n"); dvander@1636: } dvander@1636: asherkin@3686: void UTIL_DrawSendTable(FILE *fp, SendTable *pTable, int level = 1) dvander@1636: { asherkin@3686: SendProp *pProp; asherkin@3686: const char *type; dvander@1636: asherkin@3686: for (int i = 0; i < pTable->GetNumProps(); i++) dvander@1636: { dvander@1636: pProp = pTable->GetProp(i); dvander@1636: if (pProp->GetDataTable()) dvander@1636: { asherkin@3686: fprintf(fp, "%*sTable: %s (offset %d) (type %s)\n", asherkin@3686: level, "", asherkin@3686: pProp->GetName(), asherkin@3686: pProp->GetOffset(), asherkin@3686: pProp->GetDataTable()->GetName()); asherkin@3686: dvander@1636: UTIL_DrawSendTable(fp, pProp->GetDataTable(), level + 1); dvander@1636: } dvander@1636: else dvander@1636: { dvander@1636: type = GetDTTypeName(pProp->GetType()); dvander@1636: dvander@1636: if (type != NULL) dvander@1636: { dvander@1636: fprintf(fp, asherkin@3686: "%*sMember: %s (offset %d) (type %s) (bits %d)\n", asherkin@3686: level, "", dvander@1636: pProp->GetName(), dvander@1636: pProp->GetOffset(), dvander@1636: type, dvander@1636: pProp->m_nBits); dvander@1636: } dvander@1636: else dvander@1636: { dvander@1636: fprintf(fp, asherkin@3686: "%*sMember: %s (offset %d) (type %d) (bits %d)\n", asherkin@3686: level, "", dvander@1636: pProp->GetName(), dvander@1636: pProp->GetOffset(), dvander@1636: pProp->GetType(), dvander@1636: pProp->m_nBits); dvander@1636: } dvander@1636: } dvander@1636: } dvander@1636: } dvander@1636: dvander@1636: CON_COMMAND(sm_dump_netprops_xml, "Dumps the networkable property table as an XML file") dvander@1636: { ds@2583: #if SOURCE_ENGINE <= SE_DARKMESSIAH dvander@1636: CCommand args; dvander@1636: #endif dvander@1636: dvander@1636: if (args.ArgC() < 2) dvander@1636: { dvander@1636: META_CONPRINT("Usage: sm_dump_netprops_xml \n"); dvander@1636: return; dvander@1636: } dvander@1636: dvander@1636: const char *file = args.Arg(1); dvander@1636: if (!file || file[0] == '\0') dvander@1636: { dvander@1636: META_CONPRINT("Usage: sm_dump_netprops_xml \n"); dvander@1636: return; dvander@1636: } dvander@1636: dvander@1636: char path[PLATFORM_MAX_PATH]; dvander@1636: g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file); dvander@1636: dvander@1636: FILE *fp = NULL; dvander@1636: if ((fp = fopen(path, "wt")) == NULL) dvander@1636: { dvander@1636: META_CONPRINTF("Could not open file \"%s\"\n", path); dvander@1636: return; dvander@1636: } dvander@1636: dvander@1636: fprintf(fp, "\n\n"); dvander@1636: fprintf(fp, "\n\n", g_pSM->GetGameFolderName()); dvander@1636: dvander@1636: ServerClass *pBase = gamedll->GetAllServerClasses(); dvander@1636: while (pBase != NULL) dvander@1636: { dvander@1636: UTIL_DrawServerClass_XML(fp, pBase); dvander@1636: pBase = pBase->m_pNext; dvander@1636: } dvander@1636: dvander@1636: fclose(fp); dvander@1636: } dvander@1636: dvander@1636: CON_COMMAND(sm_dump_netprops, "Dumps the networkable property table as a text file") dvander@1636: { ds@2583: #if SOURCE_ENGINE <= SE_DARKMESSIAH dvander@1636: CCommand args; dvander@1636: #endif dvander@1636: dvander@1636: if (args.ArgC() < 2) dvander@1636: { dvander@1636: META_CONPRINT("Usage: sm_dump_netprops \n"); dvander@1636: return; dvander@1636: } dvander@1636: dvander@1636: const char *file = args.Arg(1); dvander@1636: if (!file || file[0] == '\0') dvander@1636: { dvander@1636: META_CONPRINT("Usage: sm_dump_netprops \n"); dvander@1636: return; dvander@1636: } dvander@1636: dvander@1636: char path[PLATFORM_MAX_PATH]; dvander@1636: g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file); dvander@1636: dvander@1636: FILE *fp = NULL; dvander@1636: if ((fp = fopen(path, "wt")) == NULL) dvander@1636: { dvander@1636: META_CONPRINTF("Could not open file \"%s\"\n", path); dvander@1636: return; dvander@1636: } dvander@1636: dvander@1636: fprintf(fp, "// Dump of all network properties for \"%s\" follows\n//\n\n", g_pSM->GetGameFolderName()); dvander@1636: dvander@1636: ServerClass *pBase = gamedll->GetAllServerClasses(); dvander@1636: while (pBase != NULL) dvander@1636: { asherkin@3686: fprintf(fp, "%s (type %s)\n", pBase->GetName(), pBase->m_pTable->GetName()); asherkin@3686: UTIL_DrawSendTable(fp, pBase->m_pTable); dvander@1636: pBase = pBase->m_pNext; dvander@1636: } dvander@1636: dvander@1636: fclose(fp); dvander@1636: } dvander@1636: pred@1922: #if defined SUBPLATFORM_SECURECRT pred@1922: void _ignore_invalid_parameter( pred@1922: const wchar_t * expression, pred@1922: const wchar_t * function, pred@1922: const wchar_t * file, pred@1922: unsigned int line, pred@1922: uintptr_t pReserved pred@1922: ) pred@1922: { pred@1922: /* Wow we don't care, thanks Microsoft. */ pred@1922: } pred@1922: #endif pred@1922: skamonkey@4169: CEntityFactoryDictionary *GetEntityFactoryDictionary() skamonkey@4169: { skamonkey@4169: static CEntityFactoryDictionary *dict = NULL; skamonkey@4169: skamonkey@4169: #if SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_SDK2013 skamonkey@4169: dict = (CEntityFactoryDictionary *) servertools->GetEntityFactoryDictionary(); skamonkey@4169: #else skamonkey@4169: if (dict == NULL) skamonkey@4169: { skamonkey@4169: void *addr; skamonkey@4169: if (g_pGameConf->GetMemSig("EntityFactoryFinder", (void **) &addr) && addr) skamonkey@4169: { skamonkey@4169: int offset; skamonkey@4169: if (!g_pGameConf->GetOffset("EntityFactoryOffset", &offset) || !offset) skamonkey@4169: { skamonkey@4169: return NULL; skamonkey@4169: } skamonkey@4169: dict = *reinterpret_cast((intptr_t) addr + offset); skamonkey@4169: } skamonkey@4169: } skamonkey@4169: skamonkey@4169: if (dict == NULL) skamonkey@4169: { skamonkey@4169: ICallWrapper *pWrapper = NULL; skamonkey@4169: skamonkey@4169: PassInfo retData; skamonkey@4169: retData.flags = PASSFLAG_BYVAL; skamonkey@4169: retData.size = sizeof(void *); skamonkey@4169: retData.type = PassType_Basic; skamonkey@4169: skamonkey@4169: void *addr; ds@4272: if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || !addr) skamonkey@4169: { ds@4272: int offset; ds@4272: ds@4272: if (!g_pGameConf->GetMemSig("EntityFactoryCaller", &addr) || !addr) ds@4272: return NULL; ds@4272: ds@4272: if (!g_pGameConf->GetOffset("EntityFactoryCallOffset", &offset)) ds@4272: return NULL; ds@4272: ds@4272: // Get relative offset to function ds@4272: int32_t funcOffset = *(int32_t *)((intptr_t)addr + offset); ds@4272: ds@4272: // Get real address of function ds@4272: // Address of signature + offset of relative offset + sizeof(int32_t) offset + relative offset ds@4272: addr = (void *)((intptr_t)addr + offset + 4 + funcOffset); skamonkey@4169: } skamonkey@4169: ds@4272: pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0); ds@4272: skamonkey@4169: if (pWrapper) skamonkey@4169: { skamonkey@4169: void *returnData = NULL; skamonkey@4169: skamonkey@4169: pWrapper->Execute(NULL, &returnData); skamonkey@4169: skamonkey@4169: pWrapper->Destroy(); skamonkey@4169: skamonkey@4169: if (returnData == NULL) skamonkey@4169: { skamonkey@4169: return NULL; skamonkey@4169: } skamonkey@4169: skamonkey@4169: dict = (CEntityFactoryDictionary *) returnData; skamonkey@4169: } skamonkey@4169: } skamonkey@4169: #endif skamonkey@4169: skamonkey@4169: return dict; skamonkey@4169: } skamonkey@4169: pred@1922: CON_COMMAND(sm_dump_classes, "Dumps the class list as a text file") pred@1922: { ds@2583: #if SOURCE_ENGINE <= SE_DARKMESSIAH pred@1922: CCommand args; pred@1922: #endif pred@1922: pred@1922: if (args.ArgC() < 2) pred@1922: { pred@1922: META_CONPRINT("Usage: sm_dump_classes \n"); pred@1922: return; pred@1922: } pred@1922: pred@1922: const char *file = args.Arg(1); pred@1922: if (!file || file[0] == '\0') pred@1922: { pred@1922: META_CONPRINT("Usage: sm_dump_classes \n"); pred@1922: return; pred@1922: } pred@1922: skamonkey@4169: CEntityFactoryDictionary *dict = GetEntityFactoryDictionary(); skamonkey@4159: if (dict == NULL) pred@1922: { skamonkey@4169: META_CONPRINT("Failed to locate function\n"); pred@1922: return; pred@1922: } pred@1922: pred@1922: char path[PLATFORM_MAX_PATH]; pred@1922: g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file); pred@1922: pred@1922: FILE *fp = NULL; pred@1922: if ((fp = fopen(path, "wt")) == NULL) pred@1922: { pred@1922: META_CONPRINTF("Could not open file \"%s\"\n", path); pred@1922: return; pred@1922: } pred@1922: pred@1922: char buffer[80]; pred@1922: buffer[0] = 0; pred@1922: pred@1922: #if defined SUBPLATFORM_SECURECRT pred@1922: _invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter); pred@1922: #endif pred@1922: pred@1922: time_t t = g_pSM->GetAdjustedTime(); pred@1922: size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t)); pred@1922: pred@1922: #if defined SUBPLATFORM_SECURECRT pred@1922: _set_invalid_parameter_handler(handler); pred@1922: #endif pred@1922: pred@1922: fprintf(fp, "// Dump of all classes for \"%s\" as at %s\n//\n\n", g_pSM->GetGameFolderName(), buffer); pred@1922: kyle@3997: sm_datatable_info_t info; pred@1922: for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) ) pred@1922: { pred@1922: IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i)); pred@1922: ServerClass *sclass = entity->GetServerClass(); pred@1922: fprintf(fp,"%s - %s\n",sclass->GetName(), dict->m_Factories.GetElementName(i)); kyle@3997: kyle@3997: if (!gamehelpers->FindDataMapInfo(gamehelpers->GetDataMap(entity->GetBaseEntity()), "m_iEFlags", &info)) kyle@3997: continue; kyle@3997: kyle@3997: int *eflags = (int *)((char *)entity->GetBaseEntity() + info.actual_offset); pred@1922: *eflags |= (1<<0); // EFL_KILLME pred@1922: } pred@1922: pred@1922: fclose(fp); pred@1922: pred@1922: } pred@1922: pred@1954: char *UTIL_FlagsToString(int flags) pred@1954: { pred@1954: static char str[1024]; pred@1954: str[0] = 0; pred@1922: pred@1954: if (flags & FTYPEDESC_GLOBAL) pred@1954: { pred@1954: strcat(str, "Global|"); pred@1954: } pred@1954: if (flags & FTYPEDESC_SAVE) pred@1954: { pred@1954: strcat(str, "Save|"); pred@1954: } pred@1954: if (flags & FTYPEDESC_KEY) pred@1954: { pred@1954: strcat(str, "Key|"); pred@1954: } pred@1954: if (flags & FTYPEDESC_INPUT) pred@1954: { pred@1954: strcat(str, "Input|"); pred@1954: } pred@1954: if (flags & FTYPEDESC_OUTPUT) pred@1954: { pred@1954: strcat(str, "Output|"); pred@1954: } pred@1954: if (flags & FTYPEDESC_FUNCTIONTABLE) pred@1954: { pred@1954: strcat(str, "FunctionTable|"); pred@1954: } pred@1954: if (flags & FTYPEDESC_PTR) pred@1954: { pred@1954: strcat(str, "Ptr|"); pred@1954: } pred@1954: if (flags & FTYPEDESC_OVERRIDE) pred@1954: { pred@1954: strcat(str, "Override|"); pred@1954: } pred@1954: pred@1954: int len = strlen(str) - 1; pred@1954: if (len > 0) pred@1954: { pred@1954: str[len] = 0; // Strip the final '|' pred@1954: } pred@1954: pred@1954: return str; pred@1954: } pred@1954: pred@1954: void UTIL_DrawDataTable(FILE *fp, datamap_t *pMap, int level) pred@1954: { pred@1954: char spaces[255]; pred@1954: pred@1954: for (int i=0; idataNumFields; i++) pred@1954: { pred@1954: if (pMap->dataDesc[i].fieldName == NULL) pred@1954: { pred@1954: continue; pred@1954: } pred@1954: pred@1954: if (pMap->dataDesc[i].td) pred@1954: { pred@1954: fprintf(fp, " %sSub-Class Table (%d Deep): %s - %s\n", spaces, level+1, pMap->dataDesc[i].fieldName, pMap->dataDesc[i].td->dataClassName); pred@1954: UTIL_DrawDataTable(fp, pMap->dataDesc[i].td, level+1); pred@1954: } pred@1954: else pred@1954: { pred@1954: externalname = pMap->dataDesc[i].externalName; pred@1954: flags = UTIL_FlagsToString(pMap->dataDesc[i].flags); pred@1954: pred@1954: if (externalname == NULL) pred@1954: { pred@1954: fprintf(fp,"%s- %s (%s)(%i Bytes)\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes); pred@1954: } pred@1954: else pred@1954: { pred@1954: fprintf(fp,"%s- %s (%s)(%i Bytes) - %s\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes, externalname); pred@1954: } pred@1954: } pred@1954: } pred@1954: pMap = pMap->baseMap; pred@1954: } pred@1954: } pred@1954: pred@1954: CON_COMMAND(sm_dump_datamaps, "Dumps the data map list as a text file") pred@1954: { ds@2583: #if SOURCE_ENGINE <= SE_DARKMESSIAH pred@1954: CCommand args; pred@1954: #endif pred@1954: pred@1954: if (args.ArgC() < 2) pred@1954: { pred@1954: META_CONPRINT("Usage: sm_dump_datamaps \n"); pred@1954: return; pred@1954: } pred@1954: pred@1954: const char *file = args.Arg(1); pred@1954: if (!file || file[0] == '\0') pred@1954: { pred@1954: META_CONPRINT("Usage: sm_dump_datamaps \n"); pred@1954: return; pred@1954: } pred@1954: skamonkey@4169: CEntityFactoryDictionary *dict = GetEntityFactoryDictionary(); januk@3859: if ( dict == NULL ) pred@1954: { januk@3859: META_CONPRINT("Failed to locate function\n"); pred@1954: return; pred@1954: } pred@1954: pred@1954: char path[PLATFORM_MAX_PATH]; pred@1954: g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file); pred@1954: pred@1954: FILE *fp = NULL; pred@1954: if ((fp = fopen(path, "wt")) == NULL) pred@1954: { pred@1954: META_CONPRINTF("Could not open file \"%s\"\n", path); pred@1954: return; pred@1954: } pred@1954: pred@1954: char buffer[80]; pred@1954: buffer[0] = 0; pred@1954: pred@1954: #if defined SUBPLATFORM_SECURECRT pred@1954: _invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter); pred@1954: #endif pred@1954: pred@1954: time_t t = g_pSM->GetAdjustedTime(); pred@1954: size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t)); pred@1954: pred@1954: #if defined SUBPLATFORM_SECURECRT pred@1954: _set_invalid_parameter_handler(handler); pred@1954: #endif pred@1954: pred@1954: fprintf(fp, "// Dump of all datamaps for \"%s\" as at %s\n//\n//\n", g_pSM->GetGameFolderName(), buffer); pred@1954: pred@1954: pred@1954: fprintf(fp, "// Flag Details:\n//\n"); pred@1954: pred@1954: fprintf(fp, "// Global: This field is masked for global entity save/restore\n"); pred@1954: fprintf(fp, "// Save: This field is saved to disk\n"); pred@1954: fprintf(fp, "// Key: This field can be requested and written to by string name at load time\n"); pred@1954: fprintf(fp, "// Input: This field can be written to by string name at run time, and a function called\n"); pred@1954: fprintf(fp, "// Output: This field propogates it's value to all targets whenever it changes\n"); pred@1954: fprintf(fp, "// FunctionTable: This is a table entry for a member function pointer\n"); pred@1954: fprintf(fp, "// Ptr: This field is a pointer, not an embedded object\n"); pred@1954: fprintf(fp, "// Override: The field is an override for one in a base class (only used by prediction system for now)\n"); pred@1954: pred@1954: fprintf(fp, "//\n\n"); pred@1954: skamonkey@3858: static int offsEFlags = -1; pred@1954: for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) ) pred@1954: { pred@1954: IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i)); pred@1954: ServerClass *sclass = entity->GetServerClass(); pred@1954: datamap_t *pMap = gamehelpers->GetDataMap(entity->GetBaseEntity()); pred@1954: pred@1954: fprintf(fp,"%s - %s\n", sclass->GetName(), dict->m_Factories.GetElementName(i)); pred@1954: pred@1954: UTIL_DrawDataTable(fp, pMap, 0); pred@1954: skamonkey@3858: if (offsEFlags == -1) skamonkey@3858: { kyle@3997: sm_datatable_info_t info; kyle@3997: if (!gamehelpers->FindDataMapInfo(pMap, "m_iEFlags", &info)) skamonkey@3858: { skamonkey@3858: continue; skamonkey@3858: } skamonkey@3858: kyle@3997: offsEFlags = info.actual_offset; skamonkey@3018: } skamonkey@3018: skamonkey@3858: int *eflags = (int *)((char *)entity->GetBaseEntity() + offsEFlags); pred@1954: *eflags |= (1<<0); // EFL_KILLME pred@1954: } pred@1954: pred@1954: fclose(fp); pred@1954: pred@1954: }