1.1 --- a/extensions/sdktools/vhelpers.cpp Fri Jul 11 06:51:21 2008 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,826 +0,0 @@
1.4 -/**
1.5 - * vim: set ts=4 :
1.6 - * =============================================================================
1.7 - * SourceMod SDKTools Extension
1.8 - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 - * =============================================================================
1.10 - *
1.11 - * This program is free software; you can redistribute it and/or modify it under
1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
1.13 - * Free Software Foundation.
1.14 - *
1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 - * details.
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License along with
1.21 - * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 - *
1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 - * by the Valve Corporation. You must obey the GNU General Public License in
1.27 - * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 - * this exception to all derivative works. AlliedModders LLC defines further
1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 - * or <http://www.sourcemod.net/license.php>.
1.31 - *
1.32 - * Version: $Id$
1.33 - */
1.34 -
1.35 -#include "extension.h"
1.36 -#include "util.h"
1.37 -#include "vhelpers.h"
1.38 -
1.39 -CallHelper s_Teleport;
1.40 -CallHelper s_GetVelocity;
1.41 -CallHelper s_EyeAngles;
1.42 -
1.43 -class CTraceFilterSimple : public CTraceFilterEntitiesOnly
1.44 -{
1.45 -public:
1.46 - CTraceFilterSimple(const IHandleEntity *passentity): m_pPassEnt(passentity)
1.47 - {
1.48 - }
1.49 - virtual bool ShouldHitEntity(IHandleEntity *pServerEntity, int contentsMask)
1.50 - {
1.51 - if (pServerEntity == m_pPassEnt)
1.52 - {
1.53 - return false;
1.54 - }
1.55 - return true;
1.56 - }
1.57 -private:
1.58 - const IHandleEntity *m_pPassEnt;
1.59 -};
1.60 -
1.61 -bool SetupTeleport()
1.62 -{
1.63 - if (s_Teleport.setup)
1.64 - {
1.65 - return s_Teleport.supported;
1.66 - }
1.67 -
1.68 - /* Setup Teleport */
1.69 - int offset;
1.70 - if (g_pGameConf->GetOffset("Teleport", &offset))
1.71 - {
1.72 - PassInfo info[3];
1.73 - info[0].flags = info[1].flags = info[2].flags = PASSFLAG_BYVAL;
1.74 - info[0].size = info[1].size = info[2].size = sizeof(void *);
1.75 - info[0].type = info[1].type = info[2].type = PassType_Basic;
1.76 -
1.77 - s_Teleport.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 3);
1.78 -
1.79 - if (s_Teleport.call != NULL)
1.80 - {
1.81 - s_Teleport.supported = true;
1.82 - }
1.83 - }
1.84 -
1.85 - s_Teleport.setup = true;
1.86 -
1.87 - return s_Teleport.supported;
1.88 -}
1.89 -
1.90 -void Teleport(CBaseEntity *pEntity, Vector *origin, QAngle *ang, Vector *velocity)
1.91 -{
1.92 - unsigned char params[sizeof(void *) * 4];
1.93 - unsigned char *vptr = params;
1.94 - *(CBaseEntity **)vptr = pEntity;
1.95 - vptr += sizeof(CBaseEntity *);
1.96 - *(Vector **)vptr = origin;
1.97 - vptr += sizeof(Vector *);
1.98 - *(QAngle **)vptr = ang;
1.99 - vptr += sizeof(QAngle *);
1.100 - *(Vector **)vptr = velocity;
1.101 -
1.102 - s_Teleport.call->Execute(params, NULL);
1.103 -}
1.104 -
1.105 -bool IsTeleportSupported()
1.106 -{
1.107 - return SetupTeleport();
1.108 -}
1.109 -
1.110 -bool SetupGetVelocity()
1.111 -{
1.112 - if (s_GetVelocity.setup)
1.113 - {
1.114 - return s_GetVelocity.supported;
1.115 - }
1.116 -
1.117 - int offset;
1.118 - if (g_pGameConf->GetOffset("GetVelocity", &offset))
1.119 - {
1.120 - PassInfo info[2];
1.121 - info[0].flags = info[1].flags = PASSFLAG_BYVAL;
1.122 - info[0].size = info[1].size = sizeof(void *);
1.123 - info[0].type = info[1].type = PassType_Basic;
1.124 -
1.125 - s_GetVelocity.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 2);
1.126 -
1.127 - if (s_GetVelocity.call != NULL)
1.128 - {
1.129 - s_GetVelocity.supported = true;
1.130 - }
1.131 - }
1.132 -
1.133 - s_GetVelocity.setup = true;
1.134 -
1.135 - return s_GetVelocity.supported;
1.136 -}
1.137 -
1.138 -void GetVelocity(CBaseEntity *pEntity, Vector *velocity, AngularImpulse *angvelocity)
1.139 -{
1.140 - unsigned char params[sizeof(void *) * 3];
1.141 - unsigned char *vptr = params;
1.142 - *(CBaseEntity **)vptr = pEntity;
1.143 - vptr += sizeof(CBaseEntity *);
1.144 - *(Vector **)vptr = velocity;
1.145 - vptr += sizeof(Vector *);
1.146 - *(AngularImpulse **)vptr = angvelocity;
1.147 -
1.148 - s_GetVelocity.call->Execute(params, NULL);
1.149 -}
1.150 -
1.151 -bool IsGetVelocitySupported()
1.152 -{
1.153 - return SetupGetVelocity();
1.154 -}
1.155 -
1.156 -bool SetupGetEyeAngles()
1.157 -{
1.158 - if (s_EyeAngles.setup)
1.159 - {
1.160 - return s_EyeAngles.supported;
1.161 - }
1.162 -
1.163 - int offset;
1.164 - if (g_pGameConf->GetOffset("EyeAngles", &offset))
1.165 - {
1.166 - PassInfo info[1];
1.167 - info[0].flags = PASSFLAG_BYVAL;
1.168 - info[0].size = sizeof(void *);
1.169 - info[0].type = PassType_Basic;
1.170 -
1.171 - s_EyeAngles.call = g_pBinTools->CreateVCall(offset, 0, 0, info, NULL, 0);
1.172 -
1.173 - if (s_EyeAngles.call != NULL)
1.174 - {
1.175 - s_EyeAngles.supported = true;
1.176 - }
1.177 - }
1.178 -
1.179 - s_EyeAngles.setup = true;
1.180 -
1.181 - return s_EyeAngles.supported;
1.182 -}
1.183 -
1.184 -bool GetEyeAngles(CBaseEntity *pEntity, QAngle *pAngles)
1.185 -{
1.186 - if (!IsEyeAnglesSupported())
1.187 - {
1.188 - return false;
1.189 - }
1.190 -
1.191 - QAngle *pRetAngle = NULL;
1.192 - unsigned char params[sizeof(void *)];
1.193 - unsigned char *vptr = params;
1.194 -
1.195 - *(CBaseEntity **)vptr = pEntity;
1.196 -
1.197 - s_EyeAngles.call->Execute(params, &pRetAngle);
1.198 -
1.199 - if (pRetAngle == NULL)
1.200 - {
1.201 - return false;
1.202 - }
1.203 -
1.204 - *pAngles = *pRetAngle;
1.205 -
1.206 - return true;
1.207 -}
1.208 -
1.209 -int GetClientAimTarget(edict_t *pEdict, bool only_players)
1.210 -{
1.211 - CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL;
1.212 -
1.213 - if (pEntity == NULL)
1.214 - {
1.215 - return -1;
1.216 - }
1.217 -
1.218 - Vector eye_position;
1.219 - QAngle eye_angles;
1.220 -
1.221 - /* Get the private information we need */
1.222 - serverClients->ClientEarPosition(pEdict, &eye_position);
1.223 - if (!GetEyeAngles(pEntity, &eye_angles))
1.224 - {
1.225 - return -2;
1.226 - }
1.227 -
1.228 - Vector aim_dir;
1.229 - AngleVectors(eye_angles, &aim_dir);
1.230 - VectorNormalize(aim_dir);
1.231 -
1.232 - Vector vec_end = eye_position + aim_dir * 8000;
1.233 -
1.234 - Ray_t ray;
1.235 - ray.Init(eye_position, vec_end);
1.236 -
1.237 - trace_t tr;
1.238 - CTraceFilterSimple simple(pEdict->GetIServerEntity());
1.239 -
1.240 - enginetrace->TraceRay(ray, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, &simple, &tr);
1.241 -
1.242 - if (tr.fraction == 1.0f || tr.m_pEnt == NULL)
1.243 - {
1.244 - return -1;
1.245 - }
1.246 -
1.247 - edict_t *pTarget = gameents->BaseEntityToEdict(tr.m_pEnt);
1.248 - if (pTarget == NULL)
1.249 - {
1.250 - return -1;
1.251 - }
1.252 -
1.253 - int ent_index = engine->IndexOfEdict(pTarget);
1.254 -
1.255 - IGamePlayer *pTargetPlayer = playerhelpers->GetGamePlayer(ent_index);
1.256 - if (pTargetPlayer != NULL && !pTargetPlayer->IsInGame())
1.257 - {
1.258 - return -1;
1.259 - }
1.260 - else if (only_players && pTargetPlayer == NULL)
1.261 - {
1.262 - return -1;
1.263 - }
1.264 -
1.265 - return ent_index;
1.266 -}
1.267 -
1.268 -bool IsEyeAnglesSupported()
1.269 -{
1.270 - return SetupGetEyeAngles();
1.271 -}
1.272 -
1.273 -bool GetPlayerInfo(int client, player_info_t *info)
1.274 -{
1.275 -#if defined ORANGEBOX_BUILD
1.276 - return engine->GetPlayerInfo(client, info);
1.277 -#else
1.278 - return (iserver) ? iserver->GetPlayerInfo(client-1, info) : false;
1.279 -#endif
1.280 -}
1.281 -
1.282 -void ShutdownHelpers()
1.283 -{
1.284 - s_Teleport.Shutdown();
1.285 - s_GetVelocity.Shutdown();
1.286 - s_EyeAngles.Shutdown();
1.287 -}
1.288 -
1.289 -const char *GetDTTypeName(int type)
1.290 -{
1.291 - switch (type)
1.292 - {
1.293 - case DPT_Int:
1.294 - {
1.295 - return "integer";
1.296 - }
1.297 - case DPT_Float:
1.298 - {
1.299 - return "float";
1.300 - }
1.301 - case DPT_Vector:
1.302 - {
1.303 - return "vector";
1.304 - }
1.305 - case DPT_String:
1.306 - {
1.307 - return "string";
1.308 - }
1.309 - case DPT_Array:
1.310 - {
1.311 - return "array";
1.312 - }
1.313 - case DPT_DataTable:
1.314 - {
1.315 - return "datatable";
1.316 - }
1.317 - default:
1.318 - {
1.319 - return NULL;
1.320 - }
1.321 - }
1.322 -
1.323 - return NULL;
1.324 -}
1.325 -
1.326 -void UTIL_DrawSendTable_XML(FILE *fp, SendTable *pTable, int space_count)
1.327 -{
1.328 - char spaces[255];
1.329 -
1.330 - for (int i = 0; i < space_count; i++)
1.331 - {
1.332 - spaces[i] = ' ';
1.333 - }
1.334 - spaces[space_count] = '\0';
1.335 -
1.336 - const char *type_name;
1.337 - SendTable *pOtherTable;
1.338 - SendProp *pProp;
1.339 -
1.340 - fprintf(fp, " %s<sendtable name=\"%s\">\n", spaces, pTable->GetName());
1.341 - for (int i = 0; i < pTable->GetNumProps(); i++)
1.342 - {
1.343 - pProp = pTable->GetProp(i);
1.344 -
1.345 - fprintf(fp, " %s<property name=\"%s\">\n", spaces, pProp->GetName());
1.346 -
1.347 - if ((type_name = GetDTTypeName(pProp->GetType())) != NULL)
1.348 - {
1.349 - fprintf(fp, " %s<type>%s</type>\n", spaces, type_name);
1.350 - }
1.351 - else
1.352 - {
1.353 - fprintf(fp, " %s<type>%d</type>\n", spaces, pProp->GetType());
1.354 - }
1.355 -
1.356 - fprintf(fp, " %s<offset>%d</offset>\n", spaces, pProp->GetOffset());
1.357 - fprintf(fp, " %s<bits>%d</bits>\n", spaces, pProp->m_nBits);
1.358 -
1.359 - if ((pOtherTable = pTable->GetProp(i)->GetDataTable()) != NULL)
1.360 - {
1.361 - UTIL_DrawSendTable_XML(fp, pOtherTable, space_count + 3);
1.362 - }
1.363 -
1.364 - fprintf(fp, " %s</property>\n", spaces);
1.365 - }
1.366 - fprintf(fp, " %s</sendtable>\n", spaces);
1.367 -}
1.368 -
1.369 -void UTIL_DrawServerClass_XML(FILE *fp, ServerClass *sc)
1.370 -{
1.371 - fprintf(fp, "<serverclass name=\"%s\">\n", sc->GetName());
1.372 - UTIL_DrawSendTable_XML(fp, sc->m_pTable, 0);
1.373 - fprintf(fp, "</serverclass>\n");
1.374 -}
1.375 -
1.376 -void UTIL_DrawSendTable(FILE *fp, SendTable *pTable, int level)
1.377 -{
1.378 - char spaces[255];
1.379 - for (int i=0; i<level; i++)
1.380 - spaces[i] = ' ';
1.381 - spaces[level] = '\0';
1.382 -
1.383 - const char *name, *type;
1.384 - SendProp *pProp;
1.385 -
1.386 - fprintf(fp, "%sSub-Class Table (%d Deep): %s\n", spaces, level, pTable->GetName());
1.387 -
1.388 - for (int i=0; i<pTable->GetNumProps(); i++)
1.389 - {
1.390 - pProp = pTable->GetProp(i);
1.391 - name = pProp->GetName();
1.392 - if (pProp->GetDataTable())
1.393 - {
1.394 - UTIL_DrawSendTable(fp, pProp->GetDataTable(), level + 1);
1.395 - }
1.396 - else
1.397 - {
1.398 - type = GetDTTypeName(pProp->GetType());
1.399 -
1.400 - if (type != NULL)
1.401 - {
1.402 - fprintf(fp,
1.403 - "%s-Member: %s (offset %d) (type %s) (bits %d)\n",
1.404 - spaces,
1.405 - pProp->GetName(),
1.406 - pProp->GetOffset(),
1.407 - type,
1.408 - pProp->m_nBits);
1.409 - }
1.410 - else
1.411 - {
1.412 - fprintf(fp,
1.413 - "%s-Member: %s (offset %d) (type %d) (bits %d)\n",
1.414 - spaces,
1.415 - pProp->GetName(),
1.416 - pProp->GetOffset(),
1.417 - pProp->GetType(),
1.418 - pProp->m_nBits);
1.419 - }
1.420 - }
1.421 - }
1.422 -}
1.423 -
1.424 -CON_COMMAND(sm_dump_netprops_xml, "Dumps the networkable property table as an XML file")
1.425 -{
1.426 -#if !defined ORANGEBOX_BUILD
1.427 - CCommand args;
1.428 -#endif
1.429 -
1.430 - if (args.ArgC() < 2)
1.431 - {
1.432 - META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
1.433 - return;
1.434 - }
1.435 -
1.436 - const char *file = args.Arg(1);
1.437 - if (!file || file[0] == '\0')
1.438 - {
1.439 - META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
1.440 - return;
1.441 - }
1.442 -
1.443 - char path[PLATFORM_MAX_PATH];
1.444 - g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
1.445 -
1.446 - FILE *fp = NULL;
1.447 - if ((fp = fopen(path, "wt")) == NULL)
1.448 - {
1.449 - META_CONPRINTF("Could not open file \"%s\"\n", path);
1.450 - return;
1.451 - }
1.452 -
1.453 - fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
1.454 - fprintf(fp, "<!-- Dump of all network properties for \"%s\" follows -->\n\n", g_pSM->GetGameFolderName());
1.455 -
1.456 - ServerClass *pBase = gamedll->GetAllServerClasses();
1.457 - while (pBase != NULL)
1.458 - {
1.459 - UTIL_DrawServerClass_XML(fp, pBase);
1.460 - pBase = pBase->m_pNext;
1.461 - }
1.462 -
1.463 - fclose(fp);
1.464 -}
1.465 -
1.466 -CON_COMMAND(sm_dump_netprops, "Dumps the networkable property table as a text file")
1.467 -{
1.468 -#if !defined ORANGEBOX_BUILD
1.469 - CCommand args;
1.470 -#endif
1.471 -
1.472 - if (args.ArgC() < 2)
1.473 - {
1.474 - META_CONPRINT("Usage: sm_dump_netprops <file>\n");
1.475 - return;
1.476 - }
1.477 -
1.478 - const char *file = args.Arg(1);
1.479 - if (!file || file[0] == '\0')
1.480 - {
1.481 - META_CONPRINT("Usage: sm_dump_netprops <file>\n");
1.482 - return;
1.483 - }
1.484 -
1.485 - char path[PLATFORM_MAX_PATH];
1.486 - g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
1.487 -
1.488 - FILE *fp = NULL;
1.489 - if ((fp = fopen(path, "wt")) == NULL)
1.490 - {
1.491 - META_CONPRINTF("Could not open file \"%s\"\n", path);
1.492 - return;
1.493 - }
1.494 -
1.495 - fprintf(fp, "// Dump of all network properties for \"%s\" follows\n//\n\n", g_pSM->GetGameFolderName());
1.496 -
1.497 - ServerClass *pBase = gamedll->GetAllServerClasses();
1.498 - while (pBase != NULL)
1.499 - {
1.500 - fprintf(fp, "%s:\n", pBase->GetName());
1.501 - UTIL_DrawSendTable(fp, pBase->m_pTable, 1);
1.502 - pBase = pBase->m_pNext;
1.503 - }
1.504 -
1.505 - fclose(fp);
1.506 -}
1.507 -
1.508 -#if defined SUBPLATFORM_SECURECRT
1.509 -void _ignore_invalid_parameter(
1.510 - const wchar_t * expression,
1.511 - const wchar_t * function,
1.512 - const wchar_t * file,
1.513 - unsigned int line,
1.514 - uintptr_t pReserved
1.515 - )
1.516 -{
1.517 - /* Wow we don't care, thanks Microsoft. */
1.518 -}
1.519 -#endif
1.520 -
1.521 -CON_COMMAND(sm_dump_classes, "Dumps the class list as a text file")
1.522 -{
1.523 -#if !defined ORANGEBOX_BUILD
1.524 - CCommand args;
1.525 -#endif
1.526 -
1.527 - if (args.ArgC() < 2)
1.528 - {
1.529 - META_CONPRINT("Usage: sm_dump_classes <file>\n");
1.530 - return;
1.531 - }
1.532 -
1.533 - const char *file = args.Arg(1);
1.534 - if (!file || file[0] == '\0')
1.535 - {
1.536 - META_CONPRINT("Usage: sm_dump_classes <file>\n");
1.537 - return;
1.538 - }
1.539 -
1.540 - ICallWrapper *pWrapper = NULL;
1.541 -
1.542 - if (!pWrapper)
1.543 - {
1.544 - PassInfo retData;
1.545 - retData.flags = PASSFLAG_BYVAL;
1.546 - retData.size = sizeof(void *);
1.547 - retData.type = PassType_Basic;
1.548 -
1.549 - void *addr;
1.550 - if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || addr == NULL)
1.551 - {
1.552 - META_CONPRINT("Failed to locate function\n");
1.553 - return;
1.554 - }
1.555 -
1.556 - pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0);
1.557 - }
1.558 -
1.559 -
1.560 - void *returnData = NULL;
1.561 -
1.562 - pWrapper->Execute(NULL, &returnData);
1.563 -
1.564 - pWrapper->Destroy();
1.565 -
1.566 - if (returnData == NULL)
1.567 - {
1.568 - return;
1.569 - }
1.570 -
1.571 - CEntityFactoryDictionary *dict = ( CEntityFactoryDictionary * )returnData;
1.572 -
1.573 - if ( !dict )
1.574 - {
1.575 - return;
1.576 - }
1.577 -
1.578 - char path[PLATFORM_MAX_PATH];
1.579 - g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
1.580 -
1.581 - FILE *fp = NULL;
1.582 - if ((fp = fopen(path, "wt")) == NULL)
1.583 - {
1.584 - META_CONPRINTF("Could not open file \"%s\"\n", path);
1.585 - return;
1.586 - }
1.587 -
1.588 - char buffer[80];
1.589 - buffer[0] = 0;
1.590 -
1.591 -#if defined SUBPLATFORM_SECURECRT
1.592 - _invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
1.593 -#endif
1.594 -
1.595 - time_t t = g_pSM->GetAdjustedTime();
1.596 - size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t));
1.597 -
1.598 -#if defined SUBPLATFORM_SECURECRT
1.599 - _set_invalid_parameter_handler(handler);
1.600 -#endif
1.601 -
1.602 - fprintf(fp, "// Dump of all classes for \"%s\" as at %s\n//\n\n", g_pSM->GetGameFolderName(), buffer);
1.603 -
1.604 - for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) )
1.605 - {
1.606 - IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i));
1.607 - ServerClass *sclass = entity->GetServerClass();
1.608 - fprintf(fp,"%s - %s\n",sclass->GetName(), dict->m_Factories.GetElementName(i));
1.609 -
1.610 - typedescription_t *datamap = gamehelpers->FindInDataMap(gamehelpers->GetDataMap(entity->GetBaseEntity()), "m_iEFlags");
1.611 -
1.612 - int *eflags = (int *)((char *)entity->GetBaseEntity() + datamap->fieldOffset[TD_OFFSET_NORMAL]);
1.613 - *eflags |= (1<<0); // EFL_KILLME
1.614 - }
1.615 -
1.616 - fclose(fp);
1.617 -
1.618 -}
1.619 -
1.620 -char *UTIL_FlagsToString(int flags)
1.621 -{
1.622 - static char str[1024];
1.623 - str[0] = 0;
1.624 -
1.625 - if (flags & FTYPEDESC_GLOBAL)
1.626 - {
1.627 - strcat(str, "Global|");
1.628 - }
1.629 - if (flags & FTYPEDESC_SAVE)
1.630 - {
1.631 - strcat(str, "Save|");
1.632 - }
1.633 - if (flags & FTYPEDESC_KEY)
1.634 - {
1.635 - strcat(str, "Key|");
1.636 - }
1.637 - if (flags & FTYPEDESC_INPUT)
1.638 - {
1.639 - strcat(str, "Input|");
1.640 - }
1.641 - if (flags & FTYPEDESC_OUTPUT)
1.642 - {
1.643 - strcat(str, "Output|");
1.644 - }
1.645 - if (flags & FTYPEDESC_FUNCTIONTABLE)
1.646 - {
1.647 - strcat(str, "FunctionTable|");
1.648 - }
1.649 - if (flags & FTYPEDESC_PTR)
1.650 - {
1.651 - strcat(str, "Ptr|");
1.652 - }
1.653 - if (flags & FTYPEDESC_OVERRIDE)
1.654 - {
1.655 - strcat(str, "Override|");
1.656 - }
1.657 -
1.658 - int len = strlen(str) - 1;
1.659 - if (len > 0)
1.660 - {
1.661 - str[len] = 0; // Strip the final '|'
1.662 - }
1.663 -
1.664 - return str;
1.665 -}
1.666 -
1.667 -void UTIL_DrawDataTable(FILE *fp, datamap_t *pMap, int level)
1.668 -{
1.669 - char spaces[255];
1.670 -
1.671 - for (int i=0; i<level; i++)
1.672 - {
1.673 - spaces[i] = ' ';
1.674 - }
1.675 -
1.676 - spaces[level] = '\0';
1.677 -
1.678 - const char *externalname;
1.679 - char *flags;
1.680 -
1.681 - while (pMap)
1.682 - {
1.683 - for (int i=0; i<pMap->dataNumFields; i++)
1.684 - {
1.685 - if (pMap->dataDesc[i].fieldName == NULL)
1.686 - {
1.687 - continue;
1.688 - }
1.689 -
1.690 - if (pMap->dataDesc[i].td)
1.691 - {
1.692 - fprintf(fp, " %sSub-Class Table (%d Deep): %s - %s\n", spaces, level+1, pMap->dataDesc[i].fieldName, pMap->dataDesc[i].td->dataClassName);
1.693 - UTIL_DrawDataTable(fp, pMap->dataDesc[i].td, level+1);
1.694 - }
1.695 - else
1.696 - {
1.697 - externalname = pMap->dataDesc[i].externalName;
1.698 - flags = UTIL_FlagsToString(pMap->dataDesc[i].flags);
1.699 -
1.700 - if (externalname == NULL)
1.701 - {
1.702 - fprintf(fp,"%s- %s (%s)(%i Bytes)\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes);
1.703 - }
1.704 - else
1.705 - {
1.706 - fprintf(fp,"%s- %s (%s)(%i Bytes) - %s\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes, externalname);
1.707 - }
1.708 - }
1.709 - }
1.710 - pMap = pMap->baseMap;
1.711 - }
1.712 -}
1.713 -
1.714 -CON_COMMAND(sm_dump_datamaps, "Dumps the data map list as a text file")
1.715 -{
1.716 -#if !defined ORANGEBOX_BUILD
1.717 - CCommand args;
1.718 -#endif
1.719 -
1.720 - if (args.ArgC() < 2)
1.721 - {
1.722 - META_CONPRINT("Usage: sm_dump_datamaps <file>\n");
1.723 - return;
1.724 - }
1.725 -
1.726 - const char *file = args.Arg(1);
1.727 - if (!file || file[0] == '\0')
1.728 - {
1.729 - META_CONPRINT("Usage: sm_dump_datamaps <file>\n");
1.730 - return;
1.731 - }
1.732 -
1.733 - ICallWrapper *pWrapper = NULL;
1.734 -
1.735 - if (!pWrapper)
1.736 - {
1.737 - PassInfo retData;
1.738 - retData.flags = PASSFLAG_BYVAL;
1.739 - retData.size = sizeof(void *);
1.740 - retData.type = PassType_Basic;
1.741 -
1.742 - void *addr;
1.743 - if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || addr == NULL)
1.744 - {
1.745 - META_CONPRINT("Failed to locate function\n");
1.746 - return;
1.747 - }
1.748 -
1.749 - pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0);
1.750 - }
1.751 -
1.752 -
1.753 - void *returnData = NULL;
1.754 -
1.755 - pWrapper->Execute(NULL, &returnData);
1.756 -
1.757 - pWrapper->Destroy();
1.758 -
1.759 - if (returnData == NULL)
1.760 - {
1.761 - return;
1.762 - }
1.763 -
1.764 - CEntityFactoryDictionary *dict = ( CEntityFactoryDictionary * )returnData;
1.765 -
1.766 - if ( !dict )
1.767 - {
1.768 - return;
1.769 - }
1.770 -
1.771 - char path[PLATFORM_MAX_PATH];
1.772 - g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
1.773 -
1.774 - FILE *fp = NULL;
1.775 - if ((fp = fopen(path, "wt")) == NULL)
1.776 - {
1.777 - META_CONPRINTF("Could not open file \"%s\"\n", path);
1.778 - return;
1.779 - }
1.780 -
1.781 - char buffer[80];
1.782 - buffer[0] = 0;
1.783 -
1.784 -#if defined SUBPLATFORM_SECURECRT
1.785 - _invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
1.786 -#endif
1.787 -
1.788 - time_t t = g_pSM->GetAdjustedTime();
1.789 - size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t));
1.790 -
1.791 -#if defined SUBPLATFORM_SECURECRT
1.792 - _set_invalid_parameter_handler(handler);
1.793 -#endif
1.794 -
1.795 - fprintf(fp, "// Dump of all datamaps for \"%s\" as at %s\n//\n//\n", g_pSM->GetGameFolderName(), buffer);
1.796 -
1.797 -
1.798 - fprintf(fp, "// Flag Details:\n//\n");
1.799 -
1.800 - fprintf(fp, "// Global: This field is masked for global entity save/restore\n");
1.801 - fprintf(fp, "// Save: This field is saved to disk\n");
1.802 - fprintf(fp, "// Key: This field can be requested and written to by string name at load time\n");
1.803 - fprintf(fp, "// Input: This field can be written to by string name at run time, and a function called\n");
1.804 - fprintf(fp, "// Output: This field propogates it's value to all targets whenever it changes\n");
1.805 - fprintf(fp, "// FunctionTable: This is a table entry for a member function pointer\n");
1.806 - fprintf(fp, "// Ptr: This field is a pointer, not an embedded object\n");
1.807 - fprintf(fp, "// Override: The field is an override for one in a base class (only used by prediction system for now)\n");
1.808 -
1.809 - fprintf(fp, "//\n\n");
1.810 -
1.811 - for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) )
1.812 - {
1.813 - IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i));
1.814 - ServerClass *sclass = entity->GetServerClass();
1.815 - datamap_t *pMap = gamehelpers->GetDataMap(entity->GetBaseEntity());
1.816 -
1.817 - fprintf(fp,"%s - %s\n", sclass->GetName(), dict->m_Factories.GetElementName(i));
1.818 -
1.819 - UTIL_DrawDataTable(fp, pMap, 0);
1.820 -
1.821 - typedescription_t *datamap = gamehelpers->FindInDataMap(pMap, "m_iEFlags");
1.822 -
1.823 - int *eflags = (int *)((char *)entity->GetBaseEntity() + datamap->fieldOffset[TD_OFFSET_NORMAL]);
1.824 - *eflags |= (1<<0); // EFL_KILLME
1.825 - }
1.826 -
1.827 - fclose(fp);
1.828 -
1.829 -}