22 Jun 2010

This commit is contained in:
g-cont 2010-06-22 00:00:00 +04:00 committed by Alibek Omarov
parent c593e56413
commit b6585b23af
5 changed files with 280 additions and 89 deletions

View File

@ -11,6 +11,53 @@
#define dem_read 1
#define dem_set 2
/*
====================
CL_WriteDemoCmd
Writes the current user cmd
====================
*/
void CL_WriteDemoCmd( usercmd_t *pcmd )
{
int i;
float fl;
usercmd_t cmd;
byte c;
fl = LittleFloat(( float )host.realtime );
FS_Write( cls.demofile, &fl, sizeof( fl ));
c = dem_cmd;
FS_Write( cls.demofile, &c, sizeof( c ));
// correct for byte order, bytes don't matter
cmd = *pcmd;
// byte order stuff
for( i = 0; i < 3; i++ )
cmd.viewangles[i] = LittleFloat( cmd.viewangles[i] );
cmd.forwardmove = LittleFloat( cmd.forwardmove );
cmd.sidemove = LittleFloat( cmd.sidemove );
cmd.upmove = LittleFloat( cmd.upmove );
cmd.msec = LittleLong( cmd.msec );
cmd.lightlevel = LittleLong( cmd.lightlevel );
cmd.buttons = LittleLong( cmd.buttons );
cmd.impulse = LittleLong( cmd.impulse );
cmd.weaponselect = LittleLong( cmd.weaponselect );
cmd.random_seed = LittleLong( cmd.random_seed );
cmd.target_edict = LittleLong( cmd.target_edict );
FS_Write( cls.demofile, &cmd, sizeof( cmd ));
for( i = 0; i < 3; i++ )
{
fl = LittleFloat( cl.refdef.cl_viewangles[i] );
FS_Write( cls.demofile, &fl, sizeof( fl ));
}
}
/*
====================
CL_WriteDemoMessage
@ -18,21 +65,77 @@ CL_WriteDemoMessage
Dumps the current net message, prefixed by the length
====================
*/
void CL_WriteDemoMessage( sizebuf_t *msg, int head_size )
void CL_WriteDemoMessage( sizebuf_t *msg )
{
int len, swlen;
int len;
float fl;
byte c;
if( !cls.demofile ) return;
if( cl.refdef.paused || cls.key_dest == key_menu )
if( !cls.demorecording || !cls.demofile )
return;
// the first eight bytes are just packet sequencing stuff
len = msg->cursize - head_size;
swlen = LittleLong( len );
fl = LittleFloat(( float )host.realtime );
FS_Write( cls.demofile, &fl, sizeof( fl ));
if( !swlen ) return; // ignore null messages
FS_Write( cls.demofile, &swlen, 4 );
FS_Write( cls.demofile, msg->data + head_size, len );
c = dem_read;
FS_Write( cls.demofile, &c, sizeof( c ));
len = LittleLong( msg->cursize );
FS_Write( cls.demofile, &len, sizeof( len ));
FS_Write( cls.demofile, msg->data, msg->cursize );
}
/*
====================
CL_WriteDemoMessage
Dumps the current net message, prefixed by the length and view angles
====================
*/
void CL_WriteRecordDemoMessage( sizebuf_t *msg, int seq )
{
int i, len;
float fl;
byte c;
if( !cls.demorecording || !cls.demofile )
return;
fl = LittleFloat(( float )host.realtime );
FS_Write( cls.demofile, &fl, sizeof( fl ));
c = dem_read;
FS_Write( cls.demofile, &c, sizeof( c ));
len = LittleLong( msg->cursize + 8 ); // FIXME: needs 10 bytes ?
FS_Write( cls.demofile, &len, sizeof( len ));
i = LittleLong( seq );
FS_Write( cls.demofile, &i, sizeof( i ));
FS_Write( cls.demofile, &i, sizeof( i ));
FS_Write( cls.demofile, msg->data, msg->cursize );
}
void CL_WriteSetDemoMessage( void )
{
int len;
float fl;
byte c;
if( !cls.demorecording || !cls.demofile )
return;
fl = LittleFloat(( float )host.realtime );
FS_Write( cls.demofile, &fl, sizeof( fl ));
c = dem_set;
FS_Write( cls.demofile, &c, sizeof( c ));
len = LittleLong( cls.netchan.outgoing_sequence );
FS_Write( cls.demofile, &len, sizeof( len ));
len = LittleLong(cls.netchan.incoming_sequence);
FS_Write( cls.demofile, &len, sizeof( len ));
}
void CL_WriteDemoHeader( const char *name )
@ -40,8 +143,8 @@ void CL_WriteDemoHeader( const char *name )
char buf_data[MAX_MSGLEN];
entity_state_t *state, nullstate;
movevars_t nullmovevars;
int i, seq = 1;
sizebuf_t buf;
int i, len;
MsgDev( D_INFO, "recording to %s.\n", name );
cls.demofile = FS_Open( name, "wb" );
@ -69,6 +172,10 @@ void CL_WriteDemoHeader( const char *name )
MSG_WriteString( &buf, cl.configstrings[CS_NAME] );
MSG_WriteString( &buf, clgame.maptitle );
// flush packet
CL_WriteRecordDemoMessage( &buf, seq++ );
MSG_Clear( &buf );
// configstrings
for( i = 0; i < MAX_CONFIGSTRINGS; i++ )
{
@ -81,15 +188,20 @@ void CL_WriteDemoHeader( const char *name )
if( buf.cursize > ( buf.maxsize / 2 ))
{
// write it out
len = LittleLong( buf.cursize );
FS_Write( cls.demofile, &len, 4 );
FS_Write( cls.demofile, buf.data, buf.cursize );
buf.cursize = 0;
CL_WriteRecordDemoMessage( &buf, seq++ );
MSG_Clear( &buf );
}
}
}
if( buf.cursize )
{
// write it out
CL_WriteRecordDemoMessage( &buf, seq++ );
MSG_Clear( &buf );
}
// baselines
Mem_Set( &nullstate, 0, sizeof( nullstate ));
Mem_Set( &nullmovevars, 0, sizeof( nullmovevars ));
@ -106,13 +218,18 @@ void CL_WriteDemoHeader( const char *name )
if( buf.cursize > ( buf.maxsize / 2 ))
{
// write it out
len = LittleLong( buf.cursize );
FS_Write( cls.demofile, &len, 4 );
FS_Write( cls.demofile, buf.data, buf.cursize );
buf.cursize = 0;
CL_WriteRecordDemoMessage( &buf, seq++ );
MSG_Clear( &buf );
}
}
if( buf.cursize )
{
// write it out
CL_WriteRecordDemoMessage( &buf, seq++ );
MSG_Clear( &buf );
}
MSG_WriteByte( &buf, svc_stufftext );
MSG_WriteString( &buf, "precache\n" );
@ -138,10 +255,10 @@ void CL_WriteDemoHeader( const char *name )
MSG_WriteDeltaMovevars( &buf, &nullmovevars, &clgame.movevars );
// write it to the demo file
len = LittleLong( buf.cursize );
FS_Write( cls.demofile, &len, 4 );
FS_Write( cls.demofile, buf.data, buf.cursize );
CL_WriteRecordDemoMessage( &buf, seq++ );
CL_WriteSetDemoMessage();
Msg( "total %i sequences writed\n", seq );
// force client.dll update
Cmd_ExecuteString( "cmd fullupdate\n" );
@ -224,65 +341,139 @@ void CL_DemoCompleted( void )
/*
=================
CL_ReadDemoMessage
CL_GetDemoMessage
reads demo data and write it to client
=================
*/
void CL_ReadDemoMessage( void )
bool CL_GetDemoMessage( sizebuf_t *msg )
{
sizebuf_t buf;
char bufData[MAX_MSGLEN];
int r;
int r, i, j;
float f, demotime;
usercmd_t *pcmd;
byte cmd;
if( !cls.demofile )
{
CL_DemoCompleted();
return;
return 0;
}
if( cl.refdef.paused || cls.key_dest == key_menu )
return;
// read the time from the packet
FS_Read( cls.demofile, &demotime, sizeof( demotime ));
demotime = LittleFloat( demotime );
// don't need another message yet
if( cl.time <= cl.mtime[0] )
return;
// decide if it is time to grab the next message
if( !cl.refdef.paused && cls.key_dest == key_game && cls.state >= ca_connected )
{
// allways grab until fully connected
if( host.realtime + 1.0f < demotime )
{
// too far back
host.realtime = demotime - 1.0f;
// rewind back to time
FS_Seek( cls.demofile, FS_Tell( cls.demofile ) - sizeof( demotime ), SEEK_SET );
return 0;
}
else if( host.realtime < demotime )
{
// rewind back to time
FS_Seek( cls.demofile, FS_Tell( cls.demofile ) - sizeof( demotime ), SEEK_SET );
return 0; // don't need another message yet
}
}
else host.realtime = demotime; // we're warping
// get the msg type
FS_Read( cls.demofile, &cmd, sizeof( cmd ));
// init the message
MSG_Init( &buf, bufData, sizeof( bufData ));
// get the length
r = FS_Read( cls.demofile, &buf.cursize, 4 );
if( r != 4 )
Msg( "read cmd %i\n", cmd );
switch( cmd )
{
case dem_cmd:
// user sent input
i = cls.netchan.outgoing_sequence & CMD_MASK;
pcmd = &cl.cmds[i];
r = FS_Read( cls.demofile, pcmd, sizeof( *pcmd ));
if( r != sizeof( *pcmd ))
{
CL_DemoCompleted();
return 0;
}
// byte order stuff
for( j = 0; j < 3; j++ )
pcmd->viewangles[j] = LittleFloat( pcmd->viewangles[j] );
pcmd->forwardmove = LittleFloat( pcmd->forwardmove );
pcmd->sidemove = LittleFloat( pcmd->sidemove );
pcmd->upmove = LittleFloat( pcmd->upmove );
pcmd->msec = LittleLong( pcmd->msec );
pcmd->lightlevel = LittleLong( pcmd->lightlevel );
pcmd->buttons = LittleLong( pcmd->buttons );
pcmd->impulse = LittleLong( pcmd->impulse );
pcmd->weaponselect = LittleLong( pcmd->weaponselect );
pcmd->random_seed = LittleLong( pcmd->random_seed );
pcmd->target_edict = LittleLong( pcmd->target_edict );
i = cls.netchan.outgoing_sequence & CL_UPDATE_MASK;
cl.frames[i].sent_time = demotime;
cl.frames[i].recv_time = -1; // we haven't gotten a reply yet
cls.netchan.outgoing_sequence++;
for( i = 0; i < 3; i++ )
{
r = FS_Read( cls.demofile, &f, sizeof( f ));
cl.refdef.cl_viewangles[i] = LittleFloat( f );
}
break;
case dem_read:
// get the next message
FS_Read( cls.demofile, &msg->cursize, sizeof( msg->cursize ));
msg->cursize = LittleLong( msg->cursize );
Msg( "read: %ld bytes\n", msg->cursize );
if( msg->cursize > msg->maxsize )
Host_Error( "demo message > MAX_MSGLEN\n" );
r = FS_Read( cls.demofile, msg->data, msg->cursize );
if( r != msg->cursize )
{
CL_DemoCompleted();
return 0;
}
break;
case dem_set :
FS_Read( cls.demofile, &i, sizeof( i ));
cls.netchan.outgoing_sequence = LittleLong( i );
FS_Read( cls.demofile, &i, sizeof( i ));
cls.netchan.incoming_sequence = LittleLong( i );
break;
default:
MsgDev( D_ERROR, "demos %s is corrupted.\n", cls.demoname );
CL_DemoCompleted();
return;
return 0;
}
return 1;
}
buf.cursize = LittleLong( buf.cursize );
if( buf.cursize == -1 )
{
CL_DemoCompleted();
return;
}
/*
====================
CL_GetMessage
if( buf.cursize > buf.maxsize )
{
Host_Error( "CL_ReadDemoMessage: demoMsglen > MAX_MSGLEN\n" );
return;
}
r = FS_Read( cls.demofile, buf.data, buf.cursize );
Handles recording and playback of demos, on top of NET_ code
====================
*/
bool CL_GetMessage( void )
{
if( cls.demoplayback )
return CL_GetDemoMessage( &net_message );
if( r != buf.cursize )
{
MsgDev( D_ERROR, "CL_ReadDemoMessage: demo file was truncated( %d )\n", cls.state );
CL_DemoCompleted();
return;
}
if( !NET_GetPacket( NS_CLIENT, &net_from, &net_message ))
return false;
cls.connect_time = host.realtime;
buf.readcount = 0;
CL_ParseServerMessage( &buf );
CL_WriteDemoMessage( &net_message );
return true;
}
/*
@ -310,16 +501,21 @@ void CL_StopPlayback( void )
void CL_StopRecord( void )
{
int len = -1;
if( !cls.demorecording ) return;
// finish up
FS_Write( cls.demofile, &len, 4 );
// write a disconnect message to the demo file
MSG_Clear( &net_message );
MSG_WriteLong( &net_message, -1 ); // -1 sequence means out of band
MSG_WriteByte( &net_message, svc_disconnect );
MSG_WriteString( &net_message, "EndOfDemo" );
CL_WriteDemoMessage( &net_message );
FS_Close( cls.demofile );
cls.demofile = NULL;
cls.demorecording = false;
cls.demoname[0] = '\0';
Msg( "Completed demo\n" );
}
/*
@ -369,7 +565,7 @@ bool CL_GetComment( const char *demoname, char *comment )
{
FS_Close( demfile );
com.strncpy( comment, "<not compatible>", MAX_STRING );
return false;
return true;
}
r = FS_Read( demfile, buf.data, buf.cursize );
@ -545,6 +741,9 @@ void CL_PlayDemo_f( void )
cls.demoplayback = true;
com.strncpy( cls.servername, Cmd_Argv( 1 ), sizeof( cls.servername ));
Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableValue( "net_qport" ));
// host.realtime = 0;
// begin a playback demo
}

View File

@ -801,11 +801,8 @@ CL_ReadNetMessage
*/
void CL_ReadNetMessage( void )
{
while( NET_GetPacket( NS_CLIENT, &net_from, &net_message ))
while( CL_GetMessage( ))
{
if( host.type == HOST_DEDICATED || cls.demoplayback )
return;
if( net_message.cursize >= 4 && *(int *)net_message.data == -1 )
{
CL_ConnectionlessPacket( net_from, &net_message );
@ -822,32 +819,22 @@ void CL_ReadNetMessage( void )
}
// packet from server
if( !NET_CompareAdr( net_from, cls.netchan.remote_address ))
if( !cls.demoplayback && !NET_CompareAdr( net_from, cls.netchan.remote_address ))
{
MsgDev( D_WARN, "CL_ReadPackets: %s:sequenced packet without connection\n", NET_AdrToString( net_from ));
return;
}
if( Netchan_Process( &cls.netchan, &net_message ))
{
// the header is different lengths for reliable and unreliable messages
int headerBytes = net_message.readcount;
if( !Netchan_Process( &cls.netchan, &net_message ))
continue;
CL_ParseServerMessage( &net_message );
// we don't know if it is ok to save a demo message until
// after we have parsed the frame
if( cls.demorecording && !cls.demowaiting )
CL_WriteDemoMessage( &net_message, headerBytes );
}
CL_ParseServerMessage( &net_message );
}
}
void CL_ReadPackets( void )
{
if( cls.demoplayback )
CL_ReadDemoMessage();
else CL_ReadNetMessage();
CL_ReadNetMessage();
cl.lerpFrac = CL_LerpPoint();

View File

@ -146,7 +146,7 @@ void CL_WritePacket( void )
if( cls.netchan.outgoing_sequence - cl.validsequence >= CL_UPDATE_BACKUP - 1 )
cl.validsequence = 0;
if( cl.validsequence && !cl_nodelta->integer && !cls.demowaiting )
if( cl.validsequence && !cl_nodelta->integer && !cls.demorecording )
{
cl.frames[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].delta_sequence = cl.validsequence;
MSG_WriteByte( &buf, clc_delta );
@ -154,6 +154,9 @@ void CL_WritePacket( void )
}
else cl.frames[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].delta_sequence = -1;
if( cls.demorecording && !cls.demowaiting )
CL_WriteDemoCmd( cmd );
// deliver the message
Netchan_Transmit( &cls.netchan, buf.cursize, buf.data );
}

View File

@ -41,6 +41,7 @@ typedef struct frame_s
{
bool valid; // cleared if delta parsing was invalid
double recv_time; // time message was received, or -1
double sent_time;
int delta_sequence;
int num_entities;
int parse_entities; // non-masked index into cl_parse_entities array
@ -409,8 +410,9 @@ void CL_SendCmd( void );
//
// cl_demo.c
//
bool CL_GetMessage( void );
void CL_DrawDemoRecording( void );
void CL_WriteDemoMessage( sizebuf_t *msg, int head_size );
void CL_WriteDemoCmd( usercmd_t *pcmd );
void CL_ReadDemoMessage( void );
void CL_StopPlayback( void );
void CL_StopRecord( void );

View File

@ -100,7 +100,7 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport )
chan->last_received = host.realtime;
chan->incoming_sequence = 0;
chan->outgoing_sequence = 1;
chan->compress = true;
chan->compress = false;
chan->rate = 1.0f / 2500;
MSG_Init( &chan->message, chan->message_buf, sizeof( chan->message_buf ));