From 90ed3bb8d220af782f4a4427d4aacedfb072aa77 Mon Sep 17 00:00:00 2001 From: mittorn Date: Thu, 6 Sep 2018 02:32:52 +0700 Subject: [PATCH] Entity save fields dumper --- dlls/enttools.cpp | 180 ++++++++++++++++++++++++++++++++++++++++++++- dlls/saverestore.h | 6 +- dlls/util.cpp | 11 +++ 3 files changed, 193 insertions(+), 4 deletions(-) diff --git a/dlls/enttools.cpp b/dlls/enttools.cpp index 1db9ce12..d5da41a5 100644 --- a/dlls/enttools.cpp +++ b/dlls/enttools.cpp @@ -3,7 +3,7 @@ #include "cbase.h" #include "game.h" #include "player.h" - +#include "saverestore.h" #define Ent_IsValidEdict( e ) ( e && !e->free ) // stop any actions with players @@ -481,6 +481,182 @@ bool Ent_CheckModel( const char *model ) return true; } +class CDumper: public CSave +{ +public: + CDumper( edict_t *cl, bool E, bool EV ) : CSave(NULL), client(cl), dumpEmpty(E), dumpEntvars(EV) {}; + /*CSave& operator CSave&() + { + return (CSave&)*this; + }*/ + int WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); + int WriteEntVars( const char *pname, entvars_t *pev ) + { + if( dumpEntvars ) + return CSave::WriteEntVars( pname, pev ); + return true; + } +private: + edict_t *client; + bool dumpEmpty; + bool dumpEntvars; +}; +#ifdef __GNUC__ +extern "C" char *__cxa_demangle(const char* mangled_name, + char* output_buffer, size_t* length, + int* status); +#endif +#define PRINTARR(pat, type, add) \ + for( j = 0; j < pTest->fieldSize - 1; j++ ) \ + Ent_ClientPrintf( client, pat", ", ((type*)pOutputData)[j] add ); \ + Ent_ClientPrintf( client, pat"\n", ((type*)pOutputData)[pTest->fieldSize - 1] add); + +int CDumper::WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) +{ + int i, j; + + if( !dumpEntvars && !strcmp( pname, "ENTVARS") ) + return 0; + + Ent_ClientPrintf( client, "%s:\n", pname ); + + for( i = 0; i < fieldCount; i++ ) + { + TYPEDESCRIPTION *pTest = &pFields[i]; + void *pOutputData = ( (char *)pBaseData + pTest->fieldOffset ); + + if( !dumpEmpty && FieldEmpty(pTest, pOutputData) ) + continue; + + if( pTest->fieldSize > 1 ) + Ent_ClientPrintf( client, "%s : \n", pTest->fieldName ); + else + Ent_ClientPrintf( client, "%s : ", pTest->fieldName ); + + switch( pTest->fieldType ) + { + case FIELD_FLOAT: + PRINTARR("%f",float,) + break; + case FIELD_TIME: + PRINTARR("%+fs",float,-gpGlobals->time) + break; + case FIELD_MODELNAME: + case FIELD_SOUNDNAME: + case FIELD_STRING: + for( j = 0; j < pTest->fieldSize - 1; j++ ) + if(((string_t*)pOutputData)[j]) + Ent_ClientPrintf( client, "\"%s\", ", STRING(((string_t*)pOutputData)[j]) ); + else + Ent_ClientPrintf( client, "null, "); + + if(((string_t*)pOutputData)[pTest->fieldSize - 1]) + Ent_ClientPrintf( client, "\"%s\"\n", STRING(((string_t*)pOutputData)[pTest->fieldSize - 1]) ); + else + Ent_ClientPrintf( client, "null\n"); + break; + case FIELD_CLASSPTR: + case FIELD_EVARS: + case FIELD_EDICT: + case FIELD_ENTITY: + case FIELD_EHANDLE: + for( j = 0; j < pTest->fieldSize; j++ ) + { + CBaseEntity *ent; + switch( pTest->fieldType ) + { + case FIELD_EVARS: + ent = CBaseEntity::Instance( ( (entvars_t **)pOutputData )[j] ); + break; + case FIELD_CLASSPTR: + ent = ( (CBaseEntity **)pOutputData )[j]; + break; + case FIELD_EDICT: + ent = CBaseEntity::Instance( ( (edict_t **)pOutputData )[j] ); + break; + case FIELD_ENTITY: + ent = CBaseEntity::Instance( ( (EOFFSET *)pOutputData )[j] ); + break; + case FIELD_EHANDLE: + ent = (CBaseEntity *)( ( (EHANDLE *)pOutputData)[j] ); + break; + default: + break; + } + if( ent ) + { + const char *classname = ""; + if( ent->pev->classname ) + classname = STRING(ent->pev->classname); + + Ent_ClientPrintf( client, "%i %s\n", ENTINDEX(ent->edict()), classname); + } + else + Ent_ClientPrintf( client, "null\n"); + + } + break; + case FIELD_POSITION_VECTOR: + case FIELD_VECTOR: + for( j = 0; j < pTest->fieldSize; j++ ) + Ent_ClientPrintf( client, "%f %f %f\n", ((float*)pOutputData)[j*3],((float*)pOutputData)[j*3+1],((float*)pOutputData)[j*3+2] ); + break; + case FIELD_BOOLEAN: + case FIELD_INTEGER: + PRINTARR("%i",int,) + break; + case FIELD_SHORT: + PRINTARR("%i",short,) + break; + case FIELD_CHARACTER: + for( j = 0; j < pTest->fieldSize; j++ ) + { + signed char c = ((char*)pOutputData)[j]; + if( c < 32 ) // allow bool/int types + Ent_ClientPrintf( client, "\\%d", c); + else + Ent_ClientPrintf( client, "%c", c); + if( c == 0 ) + break; + } + Ent_ClientPrintf( client, "\n"); + break; + // For now, just write the address out, we're not going to change memory while doing this yet! + case FIELD_POINTER: + PRINTARR("%p",void*,) + break; + case FIELD_FUNCTION: + for( j = 0; j < pTest->fieldSize; j++ ) + { + const char *name = NAME_FOR_FUNCTION(((void**)pOutputData)[j]); +#ifdef __GNUC__ + char *demangled = __cxa_demangle( name, NULL, NULL, NULL ); + if( demangled ) name = demangled; + Ent_ClientPrintf( client, "%s\n", name ); + if( demangled ) free( demangled ); +#else + Ent_ClientPrintf( client, "%s\n", name ); +#endif + + } + break; + default: + ALERT( at_error, "Bad field type\n" ); + } + } + return 1; +} + + +void Ent_Dump_f(edict_t *player) +{ + CDumper dumper( player, atoi(CMD_ARGV(2)), atoi(CMD_ARGV(3)) ); + edict_t *pent = Ent_FindSingle(player, CMD_ARGV(1)); + CBaseEntity *ent = CBaseEntity::Instance( pent ); + if( ent ) + ent->Save( dumper ); +} + /* =============== Ent_Fire_f @@ -929,6 +1105,8 @@ ucmd_t enttoolscmds[] = { "ent_fire", Ent_Fire_f }, { "ent_create", Ent_Create_f }, { "ent_getvars", Ent_GetVars_f }, +{ "ent_dump", Ent_Dump_f }, + { NULL, NULL } }; diff --git a/dlls/saverestore.h b/dlls/saverestore.h index 81f9f131..bd302394 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -18,7 +18,7 @@ #define SAVERESTORE_H class CBaseEntity; - +bool FieldEmpty( TYPEDESCRIPTION *field, void *pOutputData ); class CSaveRestoreBuffer { public: @@ -65,8 +65,8 @@ public: void WritePositionVector( const char *pname, const Vector &value ); // Offset for landmark if necessary void WritePositionVector( const char *pname, const float *value, int count ); // array of pos vectors void WriteFunction( const char *pname, void **value, int count ); // Save a function pointer - int WriteEntVars( const char *pname, entvars_t *pev ); // Save entvars_t (entvars_t) - int WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); + virtual int WriteEntVars( const char *pname, entvars_t *pev ); // Save entvars_t (entvars_t) + virtual int WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); private: int DataEmpty( const char *pdata, int size ); diff --git a/dlls/util.cpp b/dlls/util.cpp index 5772d461..dfdf3d82 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -2227,6 +2227,17 @@ int CSave::WriteEntVars( const char *pname, entvars_t *pev ) return WriteFields( pname, pev, gEntvarsDescription, ENTVARS_COUNT ); } +bool FieldEmpty( TYPEDESCRIPTION *field, void *pOutputData ) +{ + int j; + + for( j = 0; j < field->fieldSize * gSizes[field->fieldType]; j++ ) + if( ((const char*)pOutputData)[j] ) + return false; + + return true; +} + int CSave::WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) { int i, j, actualCount, emptyCount;