Entity save fields dumper

This commit is contained in:
mittorn 2018-09-06 02:32:52 +07:00
parent bc2b07a240
commit 90ed3bb8d2
3 changed files with 193 additions and 4 deletions

View File

@ -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 }
};

View File

@ -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 );

View File

@ -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;