engine: client: add command listdemo to show information about demo file (isn't really useful, just reads file header)
This commit is contained in:
parent
2785376bd3
commit
8be3bdac5d
4 changed files with 136 additions and 35 deletions
|
@ -79,7 +79,7 @@ typedef struct
|
|||
typedef struct
|
||||
{
|
||||
demoentry_t *entries; // track entry info
|
||||
int numentries; // number of tracks
|
||||
int32_t numentries; // number of tracks
|
||||
} demodirectory_t;
|
||||
|
||||
// add angles
|
||||
|
@ -1449,6 +1449,51 @@ void CL_Record_f( void )
|
|||
CL_WriteDemoHeader( demopath );
|
||||
}
|
||||
|
||||
static qboolean CL_ParseDemoHeader( const char *callee, const char *filename, file_t *f, demoheader_t *hdr, int32_t *numentries )
|
||||
{
|
||||
if( FS_Read( f, hdr, sizeof( *hdr )) != sizeof( *hdr ) || hdr->id != IDEMOHEADER )
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: %s is not in supported format or not a demo file\n", callee, filename );
|
||||
return false;
|
||||
}
|
||||
|
||||
// force null terminate strings
|
||||
hdr->mapname[sizeof( hdr->mapname ) - 1] = 0;
|
||||
hdr->comment[sizeof( hdr->comment ) - 1] = 0;
|
||||
hdr->gamedir[sizeof( hdr->gamedir ) - 1] = 0;
|
||||
|
||||
if( hdr->dem_protocol != DEMO_PROTOCOL )
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: demo protocol outdated (%i should be %i)\n",
|
||||
callee, hdr->net_protocol, DEMO_PROTOCOL );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( hdr->net_protocol != PROTOCOL_VERSION && hdr->net_protocol != PROTOCOL_LEGACY_VERSION )
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: net protocol outdated (%i should be %i or %i)\n",
|
||||
callee, hdr->net_protocol, PROTOCOL_VERSION, PROTOCOL_LEGACY_VERSION );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( FS_Seek( f, hdr->directory_offset, SEEK_SET ) < 0
|
||||
|| FS_Read( f, numentries, sizeof( *numentries )) != sizeof( *numentries ))
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: can't find directory offset in %s, demo file corrupted\n",
|
||||
callee, filename );
|
||||
return false;
|
||||
}
|
||||
|
||||
if(( *numentries < 1 ) || ( *numentries > 1024 ))
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: demo have bogus # of directory entries: %i\n",
|
||||
callee, *numentries );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_PlayDemo_f
|
||||
|
@ -1469,9 +1514,7 @@ void CL_PlayDemo_f( void )
|
|||
}
|
||||
|
||||
if( cls.demoplayback )
|
||||
{
|
||||
CL_StopPlayback();
|
||||
}
|
||||
|
||||
if( cls.demorecording )
|
||||
{
|
||||
|
@ -1526,47 +1569,27 @@ void CL_PlayDemo_f( void )
|
|||
}
|
||||
|
||||
// read in the demo header
|
||||
FS_Read( cls.demofile, &demo.header, sizeof( demoheader_t ));
|
||||
|
||||
if( demo.header.id != IDEMOHEADER )
|
||||
if( !CL_ParseDemoHeader( Cmd_Argv( 0 ), filename, cls.demofile, &demo.header, &demo.directory.numentries ))
|
||||
{
|
||||
Con_Printf( S_ERROR "%s is not a demo file\n", demoname );
|
||||
CL_DemoAborted();
|
||||
return;
|
||||
}
|
||||
|
||||
if( demo.header.dem_protocol != DEMO_PROTOCOL )
|
||||
{
|
||||
Con_Printf( S_ERROR "playdemo: demo protocol outdated (%i should be %i)\n", demo.header.dem_protocol, DEMO_PROTOCOL );
|
||||
CL_DemoAborted();
|
||||
return;
|
||||
}
|
||||
|
||||
if( demo.header.net_protocol != PROTOCOL_VERSION &&
|
||||
demo.header.net_protocol != PROTOCOL_LEGACY_VERSION )
|
||||
{
|
||||
Con_Printf( S_ERROR "playdemo: net protocol outdated (%i should be %i)\n", demo.header.net_protocol, PROTOCOL_VERSION );
|
||||
CL_DemoAborted();
|
||||
return;
|
||||
}
|
||||
|
||||
// now read in the directory structure.
|
||||
FS_Seek( cls.demofile, demo.header.directory_offset, SEEK_SET );
|
||||
FS_Read( cls.demofile, &demo.directory.numentries, sizeof( int ));
|
||||
|
||||
if( demo.directory.numentries < 1 || demo.directory.numentries > 1024 )
|
||||
{
|
||||
Con_Printf( S_ERROR "demo had bogus # of directory entries: %i\n", demo.directory.numentries );
|
||||
CL_DemoAborted();
|
||||
return;
|
||||
}
|
||||
|
||||
// allocate demo entries
|
||||
demo.directory.entries = Mem_Malloc( cls.mempool, sizeof( demoentry_t ) * demo.directory.numentries );
|
||||
demo.directory.entries = Mem_Malloc( cls.mempool, sizeof( *demo.directory.entries ) * demo.directory.numentries );
|
||||
|
||||
for( i = 0; i < demo.directory.numentries; i++ )
|
||||
{
|
||||
FS_Read( cls.demofile, &demo.directory.entries[i], sizeof( demoentry_t ));
|
||||
demoentry_t *entry = &demo.directory.entries[i];
|
||||
|
||||
if( FS_Read( cls.demofile, entry, sizeof( *entry )) != sizeof( *entry ))
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: demo entry %i of %s corrupted", Cmd_Argv( 0 ), i, filename );
|
||||
CL_DemoAborted();
|
||||
return;
|
||||
}
|
||||
|
||||
entry->description[sizeof( entry->description ) - 1] = 0;
|
||||
}
|
||||
|
||||
demo.entryIndex = 0;
|
||||
|
@ -1680,3 +1703,78 @@ void CL_Stop_f( void )
|
|||
S_StopBackgroundTrack();
|
||||
}
|
||||
}
|
||||
|
||||
void CL_ListDemo_f( void )
|
||||
{
|
||||
demoheader_t hdr;
|
||||
int32_t num_entries;
|
||||
file_t *f;
|
||||
char filename[MAX_QPATH];
|
||||
char demoname[MAX_QPATH];
|
||||
int i;
|
||||
|
||||
if( Cmd_Argc() < 2 )
|
||||
{
|
||||
Con_Printf( S_USAGE "%s <demoname>\n", Cmd_Argv( 0 ));
|
||||
return;
|
||||
}
|
||||
|
||||
Q_strncpy( demoname, Cmd_Argv( 1 ), sizeof( demoname ));
|
||||
COM_StripExtension( demoname );
|
||||
Q_snprintf( filename, sizeof( filename ), "%s.dem", demoname );
|
||||
|
||||
f = FS_Open( filename, "rb", true );
|
||||
if( !f )
|
||||
{
|
||||
Con_Printf( S_ERROR "couldn't open %s\n", filename );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !CL_ParseDemoHeader( Cmd_Argv( 0 ), filename, f, &hdr, &num_entries ))
|
||||
{
|
||||
FS_Close( f );
|
||||
return;
|
||||
}
|
||||
|
||||
Con_Printf( "Demo contents for %s:\n"
|
||||
"\tProtocol: %i net/%i demo\n"
|
||||
"\tFPS: %g\n"
|
||||
"\tMap: %s\n"
|
||||
"\tComment: %s\n"
|
||||
"\tGame: %s\n",
|
||||
filename, hdr.net_protocol, hdr.dem_protocol, hdr.host_fps, hdr.mapname,
|
||||
hdr.comment, hdr.gamedir );
|
||||
|
||||
for( i = 0; i < num_entries; i++ )
|
||||
{
|
||||
demoentry_t entry;
|
||||
|
||||
Con_Printf( "Demo entry #%i:\n", i );
|
||||
|
||||
if( FS_Read( f, &entry, sizeof( entry )) != sizeof( entry ))
|
||||
{
|
||||
Con_Printf( S_ERROR "can't read demo entry\n" );
|
||||
FS_Close( f );
|
||||
return;
|
||||
}
|
||||
|
||||
entry.description[sizeof( entry.description ) - 1] = 0;
|
||||
|
||||
if( entry.entrytype == DEMO_STARTUP )
|
||||
{
|
||||
// startup entries don't have anything useful
|
||||
Con_Printf( "\tEntry type: " S_YELLOW "startup" S_DEFAULT "\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Printf( "\tEntry type: " S_GREEN "normal" S_DEFAULT " (%i)\n"
|
||||
"\tEntry playback time/frames: %.2f seconds/%i frames\n"
|
||||
"\tEntry flags: 0x%x\n"
|
||||
"\tEntry description: %s\n",
|
||||
entry.entrytype, entry.playback_time, entry.playback_frames,
|
||||
entry.flags, entry.description );
|
||||
}
|
||||
}
|
||||
|
||||
FS_Close( f );
|
||||
}
|
||||
|
|
|
@ -3160,6 +3160,7 @@ static void CL_InitLocal( void )
|
|||
Cmd_AddCommand ("demos", CL_Demos_f, "restart looping demos defined by the last startdemos command" );
|
||||
Cmd_AddCommand ("movie", CL_PlayVideo_f, "play a movie" );
|
||||
Cmd_AddCommand ("stop", CL_Stop_f, "stop playing or recording a demo" );
|
||||
Cmd_AddCommand( "listdemo", CL_ListDemo_f, "list demo entries" );
|
||||
Cmd_AddCommand ("info", NULL, "collect info about local servers with specified protocol" );
|
||||
Cmd_AddCommand ("escape", CL_Escape_f, "escape from game to menu" );
|
||||
Cmd_AddCommand ("togglemenu", CL_Escape_f, "toggle between game and menu" );
|
||||
|
|
|
@ -784,6 +784,7 @@ void CL_Demos_f( void );
|
|||
void CL_DeleteDemo_f( void );
|
||||
void CL_Record_f( void );
|
||||
void CL_Stop_f( void );
|
||||
void CL_ListDemo_f( void );
|
||||
int CL_GetDemoComment( const char *demoname, char *comment );
|
||||
|
||||
//
|
||||
|
|
|
@ -1019,6 +1019,7 @@ autocomplete_list_t cmd_list[] =
|
|||
{ "changelevel", 1, Cmd_GetMapList },
|
||||
{ "playdemo", 1, Cmd_GetDemoList, },
|
||||
{ "timedemo", 1, Cmd_GetDemoList, },
|
||||
{ "listdemo", 1, Cmd_GetDemoList, },
|
||||
{ "playvol", 1, Cmd_GetSoundList },
|
||||
{ "hpkval", 1, Cmd_GetCustomList },
|
||||
{ "hpklist", 1, Cmd_GetCustomList },
|
||||
|
|
Loading…
Add table
Reference in a new issue