summaryrefslogtreecommitdiff
path: root/source/mvd_client.c
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2008-11-13 18:58:41 +0000
committerAndrey Nazarov <skuller@skuller.net>2008-11-13 18:58:41 +0000
commitbbefa87db18f5b76dc67efa00b7cc798361480f3 (patch)
treeefc130fe3b4fe22f111154a8720491b756daa7bd /source/mvd_client.c
parentd65e02496cd9873f5bb0297661b19762b44ddfec (diff)
Hacked the source to get it compile on Windows Mobile using CeGCC toolchain.
Fixed nasty memory corruption bug in UI scripts loading code. Fixed software refresh compilation issues on Windows. Inactive MVD channels are now completely destroyed and recreated once they are active again, and they are no longer allowed to stay in waiting state forever. Fixed delay buffer overflow resulting in fatal connection error. Preserve MVD stream flags in demos recorded on GTV server, and handle `inuse' flag correctly on players when writing gamestate. Updated documentation and Debian package descriptions.
Diffstat (limited to 'source/mvd_client.c')
-rw-r--r--source/mvd_client.c186
1 files changed, 82 insertions, 104 deletions
diff --git a/source/mvd_client.c b/source/mvd_client.c
index 859227e..c8fb982 100644
--- a/source/mvd_client.c
+++ b/source/mvd_client.c
@@ -97,7 +97,6 @@ static const char *const mvd_states[MVD_NUM_STATES] = {
static LIST_DECL( mvd_gtv_list );
LIST_DECL( mvd_channel_list );
-LIST_DECL( mvd_active_list );
mvd_t mvd_waitingRoom;
qboolean mvd_dirty;
@@ -147,7 +146,6 @@ void MVD_Free( mvd_t *mvd ) {
Z_Free( mvd->delay.data );
- List_Remove( &mvd->active );
List_Remove( &mvd->entry );
Z_Free( mvd );
}
@@ -156,7 +154,7 @@ void MVD_Destroy( mvd_t *mvd ) {
mvd_client_t *client, *next;
// update channel menus
- if( !LIST_EMPTY( &mvd->active ) ) {
+ if( !LIST_EMPTY( &mvd->entry ) ) {
mvd_dirty = qtrue;
}
@@ -245,31 +243,6 @@ mvd_t *MVD_SetChannel( int arg ) {
return NULL;
}
-void MVD_CheckActive( mvd_t *mvd ) {
- mvd_t *cur;
-
- if( mvd->state == MVD_READING || ( mvd->gtv &&
- mvd->gtv->state == GTV_READING ) )
- {
- if( LIST_EMPTY( &mvd->active ) ) {
- // sort this one into the list of active channels
- LIST_FOR_EACH( mvd_t, cur, &mvd_active_list, active ) {
- if( cur->id > mvd->id ) {
- break;
- }
- }
- List_Append( &cur->active, &mvd->active );
- mvd_dirty = qtrue;
- }
- } else {
- if( !LIST_EMPTY( &mvd->active ) ) {
- // delete this one from the list of active channels
- List_Delete( &mvd->active );
- mvd_dirty = qtrue;
- }
- }
-}
-
/*
====================================================================
@@ -324,7 +297,6 @@ static mvd_t *create_channel( gtv_t *gtv ) {
mvd->min_packets = mvd_wait_delay->value * 10;
List_Init( &mvd->clients );
List_Init( &mvd->entry );
- List_Init( &mvd->active );
return mvd;
}
@@ -677,24 +649,32 @@ static void write_message( gtv_t *gtv, gtv_clientop_t op ) {
}
static qboolean gtv_wait_stop( mvd_t *mvd ) {
+ gtv_t *gtv = mvd->gtv;
int usage;
+ // if not connected, flush any data left
+ if( !gtv || gtv->state != GTV_READING ) {
+ goto stop;
+ }
+
// see how many frames are buffered
if( mvd->num_packets >= mvd->min_packets ) {
- Com_Printf( "[%s] -=- Waiting finished, reading...\n", mvd->name );
- mvd->state = MVD_READING;
- return qtrue;
+ Com_Printf( "[%s] -=- Waiting stoped, reading...\n", mvd->name );
+ goto stop;
}
// see how much data is buffered
usage = FIFO_Percent( &mvd->delay );
if( usage >= mvd_wait_percent->value ) {
- Com_Printf( "[%s] -=- Buffering finished, reading...\n", mvd->name );
- mvd->state = MVD_READING;
- return qtrue;
+ Com_Printf( "[%s] -=- Buffering stoped, reading...\n", mvd->name );
+ goto stop;
}
return qfalse;
+
+stop:
+ mvd->state = MVD_READING;
+ return qtrue;
}
// ran out of buffers
@@ -707,36 +687,37 @@ static void gtv_wait_start( mvd_t *mvd ) {
MVD_Destroyf( mvd, "End of MVD stream reached" );
}
- Com_Printf( "[%s] -=- Buffering data...\n", mvd->name );
+ // if connection is suspended, kill it
+ if( gtv->state != GTV_READING ) {
+ Com_Printf( "[%s] -=- Ran out of buffers.\n", mvd->name );
- mvd->state = MVD_WAITING;
+ gtv->mvd = NULL;
+ mvd->gtv = NULL;
+ MVD_Destroy( mvd );
- if( gtv->state == GTV_READING ) {
- // oops, if this happened in the middle of the game,
- // resume as quickly as possible after there is some
- // data available again
- mvd->min_packets = 50 + 5 * mvd->underflows;
- if( mvd->min_packets > tr ) {
- mvd->min_packets = tr;
- }
- mvd->underflows++;
+ longjmp( mvd_jmpbuf, -1 );
+ }
- // notify spectators
- if( Com_IsDedicated() ) {
- MVD_BroadcastPrintf( mvd, PRINT_HIGH, 0,
- "[MVD] Buffering data, please wait...\n" );
- }
+ Com_Printf( "[%s] -=- Buffering data...\n", mvd->name );
- // send ping to force server to flush
- write_message( gtv, GTC_PING );
- } else {
- // channel is expected to underflow after suspend,
- // reset delay to default
+ // oops, underflowed in the middle of the game,
+ // resume as quickly as possible after there is some
+ // data available again
+ mvd->min_packets = 50 + 5 * mvd->underflows;
+ if( mvd->min_packets > tr ) {
mvd->min_packets = tr;
- mvd->underflows = 0;
+ }
+ mvd->underflows++;
+ mvd->state = MVD_WAITING;
+
+ // notify spectators
+ if( Com_IsDedicated() ) {
+ MVD_BroadcastPrintf( mvd, PRINT_HIGH, 0,
+ "[MVD] Buffering data, please wait...\n" );
}
- MVD_CheckActive( mvd );
+ // send ping to force server to flush
+ write_message( gtv, GTC_PING );
}
static qboolean gtv_read_frame( mvd_t *mvd ) {
@@ -923,33 +904,10 @@ static void parse_hello( gtv_t *gtv ) {
}
static void parse_stream_start( gtv_t *gtv ) {
- mvd_t *mvd = gtv->mvd;
- size_t size;
-
if( gtv->state != GTV_RESUMING ) {
gtv_destroyf( gtv, "Unexpected stream start ack in state %u", gtv->state );
}
- // create the channel
- if( !mvd ) {
- mvd = create_channel( gtv );
-
- Cvar_ClampInteger( mvd_buffer_size, 2, 10 );
-
- // allocate delay buffer
- size = mvd_buffer_size->integer * MAX_MSGLEN;
- mvd->delay.data = MVD_Malloc( size );
- mvd->delay.size = size;
- mvd->read_frame = gtv_read_frame;
- mvd->forward_cmd = gtv_forward_cmd;
-
- gtv->mvd = mvd;
- } else {
- // reset delay to default
- mvd->min_packets = mvd_wait_delay->value * 10;
- mvd->underflows = 0;
- }
-
Com_Printf( "[%s] -=- Stream start ack received.\n", gtv->name );
gtv->state = GTV_READING;
@@ -967,6 +925,7 @@ static void parse_stream_stop( gtv_t *gtv ) {
static void parse_stream_data( gtv_t *gtv ) {
mvd_t *mvd = gtv->mvd;
+ size_t size;
if( gtv->state < GTV_WAITING ) {
gtv_destroyf( gtv, "Unexpected stream data packet" );
@@ -993,8 +952,24 @@ static void parse_stream_data( gtv_t *gtv ) {
gtv->state = GTV_READING;
}
+ // create the channel, if not yet created
+ if( !mvd ) {
+ mvd = create_channel( gtv );
+
+ Cvar_ClampInteger( mvd_buffer_size, 2, 10 );
+
+ // allocate delay buffer
+ size = mvd_buffer_size->integer * MAX_MSGLEN;
+ mvd->delay.data = MVD_Malloc( size );
+ mvd->delay.size = size;
+ mvd->read_frame = gtv_read_frame;
+ mvd->forward_cmd = gtv_forward_cmd;
+
+ gtv->mvd = mvd;
+ }
+
if( !mvd->state ) {
- // parse it in place
+ // parse it in place until we get a gamestate
MVD_ParseMessage( mvd );
} else {
byte *data = msg_read.data + 1;
@@ -1019,8 +994,10 @@ static void parse_stream_data( gtv_t *gtv ) {
}
// clear entire delay buffer
+ // minimize the delay
FIFO_Clear( &mvd->delay );
mvd->state = MVD_WAITING;
+ mvd->num_packets = 0;
mvd->min_packets = 50;
mvd->overflows++;
@@ -1428,7 +1405,9 @@ void MVD_Spawn_f( void ) {
Cvar_Set( "timedemo", "0" );
SV_InfoSet( "port", net_port->string );
+#if USE_SYSCON
SV_SetConsoleTitle();
+#endif
// generate spawncount for Waiting Room
sv.spawncount = ( rand() | ( rand() << 16 ) ) ^ Sys_Milliseconds();
@@ -1515,13 +1494,16 @@ static void MVD_EmitGamestate( mvd_t *mvd ) {
char *string;
int i;
edict_t *ent;
- player_state_t *ps;
+ mvd_player_t *player;
size_t length;
- int flags, portalbytes;
+ int flags, extra, portalbytes;
byte portalbits[MAX_MAP_AREAS/8];
+ // pack MVD stream flags into extra bits
+ extra = mvd->flags << SVCMD_BITS;
+
// send the serverdata
- MSG_WriteByte( mvd_serverdata );
+ MSG_WriteByte( mvd_serverdata | extra );
MSG_WriteLong( PROTOCOL_VERSION_MVD );
MSG_WriteShort( PROTOCOL_VERSION_MVD_CURRENT );
MSG_WriteLong( mvd->servercount );
@@ -1549,29 +1531,28 @@ static void MVD_EmitGamestate( mvd_t *mvd ) {
portalbytes = CM_WritePortalBits( &sv.cm, portalbits );
MSG_WriteByte( portalbytes );
MSG_WriteData( portalbits, portalbytes );
-
+
// send base player states
- for( i = 0; i < mvd->maxclients; i++ ) {
- ps = &mvd->players[i].ps;
+ for( i = 0, player = mvd->players; i < mvd->maxclients; i++, player++ ) {
flags = 0;
- if( !PPS_INUSE( ps ) ) {
+ if( !player->inuse ) {
flags |= MSG_PS_REMOVE;
}
- MSG_WriteDeltaPlayerstate_Packet( NULL, ps, i, flags );
+ MSG_WriteDeltaPlayerstate_Packet( NULL, &player->ps, i, flags );
}
MSG_WriteByte( CLIENTNUM_NONE );
// send base entity states
- for( i = 1; i < mvd->pool.num_edicts; i++ ) {
- ent = &mvd->edicts[i];
+ for( i = 1, ent = mvd->edicts + 1; i < mvd->pool.num_edicts; i++, ent++ ) {
flags = 0;
- if( i <= mvd->maxclients ) {
- ps = &mvd->players[ i - 1 ].ps;
- if( PPS_INUSE( ps ) && ps->pmove.pm_type == PM_NORMAL ) {
- flags |= MSG_ES_FIRSTPERSON;
+ if( ent->inuse ) {
+ if( i <= mvd->maxclients ) {
+ player = &mvd->players[ i - 1 ];
+ if( player->inuse && player->ps.pmove.pm_type == PM_NORMAL ) {
+ flags |= MSG_ES_FIRSTPERSON;
+ }
}
- }
- if( !ent->inuse ) {
+ } else {
flags |= MSG_ES_REMOVE;
}
MSG_WriteDeltaEntity( NULL, &ent->s, flags );
@@ -1581,8 +1562,6 @@ static void MVD_EmitGamestate( mvd_t *mvd ) {
// TODO: write private layouts/configstrings
}
-extern const cmd_option_t o_mvdrecord[];
-
void MVD_StreamedRecord_f( void ) {
char buffer[MAX_OSPATH];
fileHandle_t f;
@@ -1593,12 +1572,12 @@ void MVD_StreamedRecord_f( void ) {
int c;
size_t len;
- while( ( c = Cmd_ParseOptions( o_mvdrecord ) ) != -1 ) {
+ while( ( c = Cmd_ParseOptions( o_record ) ) != -1 ) {
switch( c ) {
case 'h':
- Cmd_PrintUsage( o_mvdrecord, "[/]<filename> [chanid]" );
+ Cmd_PrintUsage( o_record, "[/]<filename> [chanid]" );
Com_Printf( "Begin MVD recording on the specified channel.\n" );
- Cmd_PrintHelp( o_mvdrecord );
+ Cmd_PrintHelp( o_record );
return;
case 'z':
gzip = qtrue;
@@ -2040,7 +2019,6 @@ void MVD_Shutdown( void ) {
List_Init( &mvd_gtv_list );
List_Init( &mvd_channel_list );
- List_Init( &mvd_active_list );
Z_Free( mvd_clients );
mvd_clients = NULL;