ds@1952: /** ds@1952: * vim: set ts=4 : ds@1952: * ============================================================================= ds@1952: * SourceMod SDKTools Extension ds@1952: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. ds@1952: * ============================================================================= ds@1952: * ds@1952: * This program is free software; you can redistribute it and/or modify it under ds@1952: * the terms of the GNU General Public License, version 3.0, as published by the ds@1952: * Free Software Foundation. ds@1952: * ds@1952: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1952: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1952: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1952: * details. ds@1952: * ds@1952: * You should have received a copy of the GNU General Public License along with ds@1952: * this program. If not, see . ds@1952: * ds@1952: * As a special exception, AlliedModders LLC gives you permission to link the ds@1952: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1952: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1952: * by the Valve Corporation. You must obey the GNU General Public License in ds@1952: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1952: * this exception to all derivative works. AlliedModders LLC defines further ds@1952: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1952: * or . ds@1952: * ds@1952: * Version: $Id$ ds@1952: */ ds@1952: ds@1952: #include "extension.h" ds@1952: #include "util.h" ds@1952: #include "vhelpers.h" ds@1952: ds@1952: CallHelper s_Teleport; ds@1952: CallHelper s_GetVelocity; ds@1952: CallHelper s_EyeAngles; ds@1952: ds@1952: class CTraceFilterSimple : public CTraceFilterEntitiesOnly ds@1952: { ds@1952: public: ds@1952: CTraceFilterSimple(const IHandleEntity *passentity): m_pPassEnt(passentity) ds@1952: { ds@1952: } ds@1952: virtual bool ShouldHitEntity(IHandleEntity *pServerEntity, int contentsMask) ds@1952: { ds@1952: if (pServerEntity == m_pPassEnt) ds@1952: { ds@1952: return false; ds@1952: } ds@1952: return true; ds@1952: } ds@1952: private: ds@1952: const IHandleEntity *m_pPassEnt; ds@1952: }; ds@1952: ds@1952: bool SetupTeleport() ds@1952: { ds@1952: if (s_Teleport.setup) ds@1952: { ds@1952: return s_Teleport.supported; ds@1952: } ds@1952: ds@1952: /* Setup Teleport */ ds@1952: int offset; ds@1952: if (g_pGameConf->GetOffset("Teleport", &offset)) ds@1952: { ds@1952: PassInfo info[3]; ds@1952: info[0].flags = info[1].flags = info[2].flags = PASSFLAG_BYVAL; ds@1952: info[0].size = info[1].size = info[2].size = sizeof(void *); ds@1952: info[0].type = info[1].type = info[2].type = PassType_Basic; ds@1952: ds@1952: s_Teleport.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 3); ds@1952: ds@1952: if (s_Teleport.call != NULL) ds@1952: { ds@1952: s_Teleport.supported = true; ds@1952: } ds@1952: } ds@1952: ds@1952: s_Teleport.setup = true; ds@1952: ds@1952: return s_Teleport.supported; ds@1952: } ds@1952: ds@1952: void Teleport(CBaseEntity *pEntity, Vector *origin, QAngle *ang, Vector *velocity) ds@1952: { ds@1952: unsigned char params[sizeof(void *) * 4]; ds@1952: unsigned char *vptr = params; ds@1952: *(CBaseEntity **)vptr = pEntity; ds@1952: vptr += sizeof(CBaseEntity *); ds@1952: *(Vector **)vptr = origin; ds@1952: vptr += sizeof(Vector *); ds@1952: *(QAngle **)vptr = ang; ds@1952: vptr += sizeof(QAngle *); ds@1952: *(Vector **)vptr = velocity; ds@1952: ds@1952: s_Teleport.call->Execute(params, NULL); ds@1952: } ds@1952: ds@1952: bool IsTeleportSupported() ds@1952: { ds@1952: return SetupTeleport(); ds@1952: } ds@1952: ds@1952: bool SetupGetVelocity() ds@1952: { ds@1952: if (s_GetVelocity.setup) ds@1952: { ds@1952: return s_GetVelocity.supported; ds@1952: } ds@1952: ds@1952: int offset; ds@1952: if (g_pGameConf->GetOffset("GetVelocity", &offset)) ds@1952: { ds@1952: PassInfo info[2]; ds@1952: info[0].flags = info[1].flags = PASSFLAG_BYVAL; ds@1952: info[0].size = info[1].size = sizeof(void *); ds@1952: info[0].type = info[1].type = PassType_Basic; ds@1952: ds@1952: s_GetVelocity.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 2); ds@1952: ds@1952: if (s_GetVelocity.call != NULL) ds@1952: { ds@1952: s_GetVelocity.supported = true; ds@1952: } ds@1952: } ds@1952: ds@1952: s_GetVelocity.setup = true; ds@1952: ds@1952: return s_GetVelocity.supported; ds@1952: } ds@1952: ds@1952: void GetVelocity(CBaseEntity *pEntity, Vector *velocity, AngularImpulse *angvelocity) ds@1952: { ds@1952: unsigned char params[sizeof(void *) * 3]; ds@1952: unsigned char *vptr = params; ds@1952: *(CBaseEntity **)vptr = pEntity; ds@1952: vptr += sizeof(CBaseEntity *); ds@1952: *(Vector **)vptr = velocity; ds@1952: vptr += sizeof(Vector *); ds@1952: *(AngularImpulse **)vptr = angvelocity; ds@1952: ds@1952: s_GetVelocity.call->Execute(params, NULL); ds@1952: } ds@1952: ds@1952: bool IsGetVelocitySupported() ds@1952: { ds@1952: return SetupGetVelocity(); ds@1952: } ds@1952: ds@1952: bool SetupGetEyeAngles() ds@1952: { ds@1952: if (s_EyeAngles.setup) ds@1952: { ds@1952: return s_EyeAngles.supported; ds@1952: } ds@1952: ds@1952: int offset; ds@1952: if (g_pGameConf->GetOffset("EyeAngles", &offset)) ds@1952: { ds@1952: PassInfo info[2]; ds@1952: info[0].flags = info[1].flags = PASSFLAG_BYVAL; ds@1952: info[0].size = info[1].size = sizeof(void *); ds@1952: info[0].type = info[1].type = PassType_Basic; ds@1952: ds@1952: s_EyeAngles.call = g_pBinTools->CreateVCall(offset, 0, 0, &info[0], &info[1], 1); ds@1952: ds@1952: if (s_EyeAngles.call != NULL) ds@1952: { ds@1952: s_EyeAngles.supported = true; ds@1952: } ds@1952: } ds@1952: ds@1952: s_EyeAngles.setup = true; ds@1952: ds@1952: return s_EyeAngles.supported; ds@1952: } ds@1952: ds@1952: bool GetEyeAngles(CBaseEntity *pEntity, QAngle *pAngles) ds@1952: { ds@1952: if (!IsEyeAnglesSupported()) ds@1952: { ds@1952: return false; ds@1952: } ds@1952: ds@1952: QAngle *pRetAngle = NULL; ds@1952: unsigned char params[sizeof(void *)]; ds@1952: unsigned char *vptr = params; ds@1952: ds@1952: *(CBaseEntity **)vptr = pEntity; ds@1952: vptr += sizeof(CBaseEntity *); ds@1952: ds@1952: s_EyeAngles.call->Execute(params, &pRetAngle); ds@1952: ds@1952: if (pRetAngle == NULL) ds@1952: { ds@1952: return false; ds@1952: } ds@1952: ds@1952: *pAngles = *pRetAngle; ds@1952: ds@1952: return true; ds@1952: } ds@1952: ds@1952: int GetClientAimTarget(edict_t *pEdict, bool only_players) ds@1952: { ds@1952: CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL; ds@1952: ds@1952: if (pEntity == NULL) ds@1952: { ds@1952: return -1; ds@1952: } ds@1952: ds@1952: Vector eye_position; ds@1952: QAngle eye_angles; ds@1952: ds@1952: /* Get the private information we need */ ds@1952: serverClients->ClientEarPosition(pEdict, &eye_position); ds@1952: if (!GetEyeAngles(pEntity, &eye_angles)) ds@1952: { ds@1952: return -2; ds@1952: } ds@1952: ds@1952: Vector aim_dir; ds@1952: AngleVectors(eye_angles, &aim_dir); ds@1952: VectorNormalize(aim_dir); ds@1952: ds@1952: Vector vec_end = eye_position + aim_dir * 8000; ds@1952: ds@1952: Ray_t ray; ds@1952: ray.Init(eye_position, vec_end); ds@1952: ds@1952: trace_t tr; ds@1952: CTraceFilterSimple simple(pEdict->GetIServerEntity()); ds@1952: ds@1952: enginetrace->TraceRay(ray, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, &simple, &tr); ds@1952: ds@1952: if (tr.fraction == 1.0f || tr.m_pEnt == NULL) ds@1952: { ds@1952: return -1; ds@1952: } ds@1952: ds@1952: edict_t *pTarget = gameents->BaseEntityToEdict(tr.m_pEnt); ds@1952: if (pTarget == NULL) ds@1952: { ds@1952: return -1; ds@1952: } ds@1952: ds@1952: int ent_index = engine->IndexOfEdict(pTarget); ds@1952: ds@1952: IGamePlayer *pTargetPlayer = playerhelpers->GetGamePlayer(ent_index); ds@1952: if (pTargetPlayer != NULL && !pTargetPlayer->IsInGame()) ds@1952: { ds@1952: return -1; ds@1952: } ds@1952: else if (only_players && pTargetPlayer == NULL) ds@1952: { ds@1952: return -1; ds@1952: } ds@1952: ds@1952: return ent_index; ds@1952: } ds@1952: ds@1952: bool IsEyeAnglesSupported() ds@1952: { ds@1952: return SetupGetEyeAngles(); ds@1952: } ds@1952: ds@1952: bool GetPlayerInfo(int client, player_info_t *info) ds@1952: { ds@1952: #if defined ORANGEBOX_BUILD ds@1952: return engine->GetPlayerInfo(client, info); ds@1952: #else ds@1952: return (iserver) ? iserver->GetPlayerInfo(client-1, info) : false; ds@1952: #endif ds@1952: } ds@1952: ds@1952: void ShutdownHelpers() ds@1952: { ds@1952: s_Teleport.Shutdown(); ds@1952: s_GetVelocity.Shutdown(); ds@1952: } ds@1952: ds@1952: const char *GetDTTypeName(int type) ds@1952: { ds@1952: switch (type) ds@1952: { ds@1952: case DPT_Int: ds@1952: { ds@1952: return "integer"; ds@1952: } ds@1952: case DPT_Float: ds@1952: { ds@1952: return "float"; ds@1952: } ds@1952: case DPT_Vector: ds@1952: { ds@1952: return "vector"; ds@1952: } ds@1952: case DPT_String: ds@1952: { ds@1952: return "string"; ds@1952: } ds@1952: case DPT_Array: ds@1952: { ds@1952: return "array"; ds@1952: } ds@1952: case DPT_DataTable: ds@1952: { ds@1952: return "datatable"; ds@1952: } ds@1952: default: ds@1952: { ds@1952: return NULL; ds@1952: } ds@1952: } ds@1952: ds@1952: return NULL; ds@1952: } ds@1952: ds@1952: void UTIL_DrawSendTable_XML(FILE *fp, SendTable *pTable, int space_count) ds@1952: { ds@1952: char spaces[255]; ds@1952: ds@1952: for (int i = 0; i < space_count; i++) ds@1952: { ds@1952: spaces[i] = ' '; ds@1952: } ds@1952: spaces[space_count] = '\0'; ds@1952: ds@1952: const char *type_name; ds@1952: SendTable *pOtherTable; ds@1952: SendProp *pProp; ds@1952: ds@1952: fprintf(fp, " %s\n", spaces, pTable->GetName()); ds@1952: for (int i = 0; i < pTable->GetNumProps(); i++) ds@1952: { ds@1952: pProp = pTable->GetProp(i); ds@1952: ds@1952: fprintf(fp, " %s\n", spaces, pProp->GetName()); ds@1952: ds@1952: if ((type_name = GetDTTypeName(pProp->GetType())) != NULL) ds@1952: { ds@1952: fprintf(fp, " %s%s\n", spaces, type_name); ds@1952: } ds@1952: else ds@1952: { ds@1952: fprintf(fp, " %s%d\n", spaces, pProp->GetType()); ds@1952: } ds@1952: ds@1952: fprintf(fp, " %s%d\n", spaces, pProp->GetOffset()); ds@1952: fprintf(fp, " %s%d\n", spaces, pProp->m_nBits); ds@1952: ds@1952: if ((pOtherTable = pTable->GetProp(i)->GetDataTable()) != NULL) ds@1952: { ds@1952: UTIL_DrawSendTable_XML(fp, pOtherTable, space_count + 3); ds@1952: } ds@1952: ds@1952: fprintf(fp, " %s\n", spaces); ds@1952: } ds@1952: fprintf(fp, " %s\n", spaces); ds@1952: } ds@1952: ds@1952: void UTIL_DrawServerClass_XML(FILE *fp, ServerClass *sc) ds@1952: { ds@1952: fprintf(fp, "\n", sc->GetName()); ds@1952: UTIL_DrawSendTable_XML(fp, sc->m_pTable, 0); ds@1952: fprintf(fp, "\n"); ds@1952: } ds@1952: ds@1952: void UTIL_DrawSendTable(FILE *fp, SendTable *pTable, int level) ds@1952: { ds@1952: char spaces[255]; ds@1952: for (int i=0; iGetName()); ds@1952: ds@1952: for (int i=0; iGetNumProps(); i++) ds@1952: { ds@1952: pProp = pTable->GetProp(i); ds@1952: name = pProp->GetName(); ds@1952: if (pProp->GetDataTable()) ds@1952: { ds@1952: UTIL_DrawSendTable(fp, pProp->GetDataTable(), level + 1); ds@1952: } ds@1952: else ds@1952: { ds@1952: type = GetDTTypeName(pProp->GetType()); ds@1952: ds@1952: if (type != NULL) ds@1952: { ds@1952: fprintf(fp, ds@1952: "%s-Member: %s (offset %d) (type %s) (bits %d)\n", ds@1952: spaces, ds@1952: pProp->GetName(), ds@1952: pProp->GetOffset(), ds@1952: type, ds@1952: pProp->m_nBits); ds@1952: } ds@1952: else ds@1952: { ds@1952: fprintf(fp, ds@1952: "%s-Member: %s (offset %d) (type %d) (bits %d)\n", ds@1952: spaces, ds@1952: pProp->GetName(), ds@1952: pProp->GetOffset(), ds@1952: pProp->GetType(), ds@1952: pProp->m_nBits); ds@1952: } ds@1952: } ds@1952: } ds@1952: } ds@1952: ds@1952: CON_COMMAND(sm_dump_netprops_xml, "Dumps the networkable property table as an XML file") ds@1952: { ds@1952: #if !defined ORANGEBOX_BUILD ds@1952: CCommand args; ds@1952: #endif ds@1952: ds@1952: if (args.ArgC() < 2) ds@1952: { ds@1952: META_CONPRINT("Usage: sm_dump_netprops_xml \n"); ds@1952: return; ds@1952: } ds@1952: ds@1952: const char *file = args.Arg(1); ds@1952: if (!file || file[0] == '\0') ds@1952: { ds@1952: META_CONPRINT("Usage: sm_dump_netprops_xml \n"); ds@1952: return; ds@1952: } ds@1952: ds@1952: char path[PLATFORM_MAX_PATH]; ds@1952: g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file); ds@1952: ds@1952: FILE *fp = NULL; ds@1952: if ((fp = fopen(path, "wt")) == NULL) ds@1952: { ds@1952: META_CONPRINTF("Could not open file \"%s\"\n", path); ds@1952: return; ds@1952: } ds@1952: ds@1952: fprintf(fp, "\n\n"); ds@1952: fprintf(fp, "\n\n", g_pSM->GetGameFolderName()); ds@1952: ds@1952: ServerClass *pBase = gamedll->GetAllServerClasses(); ds@1952: while (pBase != NULL) ds@1952: { ds@1952: UTIL_DrawServerClass_XML(fp, pBase); ds@1952: pBase = pBase->m_pNext; ds@1952: } ds@1952: ds@1952: fclose(fp); ds@1952: } ds@1952: ds@1952: CON_COMMAND(sm_dump_netprops, "Dumps the networkable property table as a text file") ds@1952: { ds@1952: #if !defined ORANGEBOX_BUILD ds@1952: CCommand args; ds@1952: #endif ds@1952: ds@1952: if (args.ArgC() < 2) ds@1952: { ds@1952: META_CONPRINT("Usage: sm_dump_netprops \n"); ds@1952: return; ds@1952: } ds@1952: ds@1952: const char *file = args.Arg(1); ds@1952: if (!file || file[0] == '\0') ds@1952: { ds@1952: META_CONPRINT("Usage: sm_dump_netprops \n"); ds@1952: return; ds@1952: } ds@1952: ds@1952: char path[PLATFORM_MAX_PATH]; ds@1952: g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file); ds@1952: ds@1952: FILE *fp = NULL; ds@1952: if ((fp = fopen(path, "wt")) == NULL) ds@1952: { ds@1952: META_CONPRINTF("Could not open file \"%s\"\n", path); ds@1952: return; ds@1952: } ds@1952: ds@1952: fprintf(fp, "// Dump of all network properties for \"%s\" follows\n//\n\n", g_pSM->GetGameFolderName()); ds@1952: ds@1952: ServerClass *pBase = gamedll->GetAllServerClasses(); ds@1952: while (pBase != NULL) ds@1952: { ds@1952: fprintf(fp, "%s:\n", pBase->GetName()); ds@1952: UTIL_DrawSendTable(fp, pBase->m_pTable, 1); ds@1952: pBase = pBase->m_pNext; ds@1952: } ds@1952: ds@1952: fclose(fp); ds@1952: } ds@1952: ds@1952: #if defined SUBPLATFORM_SECURECRT ds@1952: void _ignore_invalid_parameter( ds@1952: const wchar_t * expression, ds@1952: const wchar_t * function, ds@1952: const wchar_t * file, ds@1952: unsigned int line, ds@1952: uintptr_t pReserved ds@1952: ) ds@1952: { ds@1952: /* Wow we don't care, thanks Microsoft. */ ds@1952: } ds@1952: #endif ds@1952: ds@1952: CON_COMMAND(sm_dump_classes, "Dumps the class list as a text file") ds@1952: { ds@1952: #if !defined ORANGEBOX_BUILD ds@1952: CCommand args; ds@1952: #endif ds@1952: ds@1952: if (args.ArgC() < 2) ds@1952: { ds@1952: META_CONPRINT("Usage: sm_dump_classes \n"); ds@1952: return; ds@1952: } ds@1952: ds@1952: const char *file = args.Arg(1); ds@1952: if (!file || file[0] == '\0') ds@1952: { ds@1952: META_CONPRINT("Usage: sm_dump_classes \n"); ds@1952: return; ds@1952: } ds@1952: ds@1952: ICallWrapper *pWrapper = NULL; ds@1952: ds@1952: if (!pWrapper) ds@1952: { ds@1952: PassInfo retData; ds@1952: retData.flags = PASSFLAG_BYVAL; ds@1952: retData.size = sizeof(void *); ds@1952: retData.type = PassType_Basic; ds@1952: ds@1952: void *addr; ds@1952: if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || addr == NULL) ds@1952: { ds@1952: META_CONPRINT("Failed to locate function\n"); ds@1952: return; ds@1952: } ds@1952: ds@1952: pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0); ds@1952: } ds@1952: ds@1952: ds@1952: void *returnData = NULL; ds@1952: ds@1952: pWrapper->Execute(NULL, &returnData); ds@1952: ds@1952: pWrapper->Destroy(); ds@1952: ds@1952: if (returnData == NULL) ds@1952: { ds@1952: return; ds@1952: } ds@1952: ds@1952: CEntityFactoryDictionary *dict = ( CEntityFactoryDictionary * )returnData; ds@1952: ds@1952: if ( !dict ) ds@1952: { ds@1952: return; ds@1952: } ds@1952: ds@1952: char path[PLATFORM_MAX_PATH]; ds@1952: g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file); ds@1952: ds@1952: FILE *fp = NULL; ds@1952: if ((fp = fopen(path, "wt")) == NULL) ds@1952: { ds@1952: META_CONPRINTF("Could not open file \"%s\"\n", path); ds@1952: return; ds@1952: } ds@1952: ds@1952: char buffer[80]; ds@1952: buffer[0] = 0; ds@1952: ds@1952: #if defined SUBPLATFORM_SECURECRT ds@1952: _invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter); ds@1952: #endif ds@1952: ds@1952: time_t t = g_pSM->GetAdjustedTime(); ds@1952: size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t)); ds@1952: ds@1952: #if defined SUBPLATFORM_SECURECRT ds@1952: _set_invalid_parameter_handler(handler); ds@1952: #endif ds@1952: ds@1952: fprintf(fp, "// Dump of all classes for \"%s\" as at %s\n//\n\n", g_pSM->GetGameFolderName(), buffer); ds@1952: ds@1952: for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) ) ds@1952: { ds@1952: IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i)); ds@1952: ServerClass *sclass = entity->GetServerClass(); ds@1952: fprintf(fp,"%s - %s\n",sclass->GetName(), dict->m_Factories.GetElementName(i)); ds@1952: ds@1952: typedescription_t *datamap = gamehelpers->FindInDataMap(gamehelpers->GetDataMap(entity->GetBaseEntity()), "m_iEFlags"); ds@1952: ds@1952: int *eflags = (int *)((char *)entity->GetBaseEntity() + datamap->fieldOffset[TD_OFFSET_NORMAL]); ds@1952: *eflags |= (1<<0); // EFL_KILLME ds@1952: } ds@1952: ds@1952: fclose(fp); ds@1952: ds@1952: } ds@1952: pred@1954: char *UTIL_FlagsToString(int flags) pred@1954: { pred@1954: static char str[1024]; pred@1954: str[0] = 0; ds@1952: 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: { pred@1954: #if !defined ORANGEBOX_BUILD 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: pred@1954: ICallWrapper *pWrapper = NULL; pred@1954: pred@1954: if (!pWrapper) pred@1954: { pred@1954: PassInfo retData; pred@1954: retData.flags = PASSFLAG_BYVAL; pred@1954: retData.size = sizeof(void *); pred@1954: retData.type = PassType_Basic; pred@1954: pred@1954: void *addr; pred@1954: if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || addr == NULL) pred@1954: { pred@1954: META_CONPRINT("Failed to locate function\n"); pred@1954: return; pred@1954: } pred@1954: pred@1954: pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0); pred@1954: } pred@1954: pred@1954: pred@1954: void *returnData = NULL; pred@1954: pred@1954: pWrapper->Execute(NULL, &returnData); pred@1954: pred@1954: pWrapper->Destroy(); pred@1954: pred@1954: if (returnData == NULL) pred@1954: { pred@1954: return; pred@1954: } pred@1954: pred@1954: CEntityFactoryDictionary *dict = ( CEntityFactoryDictionary * )returnData; pred@1954: pred@1954: if ( !dict ) pred@1954: { 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: 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: pred@1954: typedescription_t *datamap = gamehelpers->FindInDataMap(pMap), "m_iEFlags"); pred@1954: pred@1954: int *eflags = (int *)((char *)entity->GetBaseEntity() + datamap->fieldOffset[TD_OFFSET_NORMAL]); pred@1954: *eflags |= (1<<0); // EFL_KILLME pred@1954: } pred@1954: pred@1954: fclose(fp); pred@1954: pred@1954: } pred@1954: pred@1954: pred@1954: pred@1954: pred@1954: pred@1954: pred@1954: