diff options
Diffstat (limited to 'source/mvd_parse.c')
-rw-r--r-- | source/mvd_parse.c | 242 |
1 files changed, 94 insertions, 148 deletions
diff --git a/source/mvd_parse.c b/source/mvd_parse.c index 4a8a336..4b558cd 100644 --- a/source/mvd_parse.c +++ b/source/mvd_parse.c @@ -194,7 +194,7 @@ void MVD_ParseEntityString( mvd_t *mvd, const char *data ) { } static void MVD_ParseMulticast( mvd_t *mvd, mvd_ops_t op, int extrabits ) { - udpClient_t *client; + mvd_client_t *client; client_t *cl; byte mask[MAX_MAP_VIS]; mleaf_t *leaf1, *leaf2; @@ -242,7 +242,7 @@ static void MVD_ParseMulticast( mvd_t *mvd, mvd_ops_t op, int extrabits ) { } // send the data to all relevent clients - LIST_FOR_EACH( udpClient_t, client, &mvd->udpClients, entry ) { + LIST_FOR_EACH( mvd_client_t, client, &mvd->clients, entry ) { cl = client->cl; if( cl->state < cs_primed ) { continue; @@ -271,11 +271,11 @@ static void MVD_ParseMulticast( mvd_t *mvd, mvd_ops_t op, int extrabits ) { static void MVD_UnicastSend( mvd_t *mvd, qboolean reliable, byte *data, size_t length, mvd_player_t *player ) { mvd_player_t *target; - udpClient_t *client; + mvd_client_t *client; client_t *cl; // send to all relevant clients - LIST_FOR_EACH( udpClient_t, client, &mvd->udpClients, entry ) { + LIST_FOR_EACH( mvd_client_t, client, &mvd->clients, entry ) { cl = client->cl; if( cl->state < cs_spawned ) { continue; @@ -288,7 +288,7 @@ static void MVD_UnicastSend( mvd_t *mvd, qboolean reliable, byte *data, size_t l } static void MVD_UnicastLayout( mvd_t *mvd, qboolean reliable, mvd_player_t *player ) { - udpClient_t *client; + mvd_client_t *client; if( player != mvd->dummy ) { MSG_ReadString( NULL, 0 ); @@ -298,7 +298,7 @@ static void MVD_UnicastLayout( mvd_t *mvd, qboolean reliable, mvd_player_t *play MSG_ReadString( mvd->layout, sizeof( mvd->layout ) ); // force an update to all relevant clients - LIST_FOR_EACH( udpClient_t, client, &mvd->udpClients, entry ) { + LIST_FOR_EACH( mvd_client_t, client, &mvd->clients, entry ) { if( client->cl->state < cs_spawned ) { continue; } @@ -355,7 +355,7 @@ static void MVD_UnicastPrint( mvd_t *mvd, qboolean reliable, mvd_player_t *playe int level; byte *data; size_t readcount, length; - udpClient_t *client; + mvd_client_t *client; client_t *cl; mvd_player_t *target; @@ -368,7 +368,7 @@ static void MVD_UnicastPrint( mvd_t *mvd, qboolean reliable, mvd_player_t *playe length = msg_read.readcount - readcount; // send to all relevant clients - LIST_FOR_EACH( udpClient_t, client, &mvd->udpClients, entry ) { + LIST_FOR_EACH( mvd_client_t, client, &mvd->clients, entry ) { cl = client->cl; if( cl->state < cs_spawned ) { continue; @@ -489,7 +489,7 @@ static void MVD_ParseSound( mvd_t *mvd, int extrabits ) { int volume, attenuation, offset, sendchan; int entnum; vec3_t origin; - udpClient_t *client; + mvd_client_t *client; client_t *cl; byte mask[MAX_MAP_VIS]; mleaf_t *leaf; @@ -523,7 +523,7 @@ static void MVD_ParseSound( mvd_t *mvd, int extrabits ) { return; } - LIST_FOR_EACH( udpClient_t, client, &mvd->udpClients, entry ) { + LIST_FOR_EACH( mvd_client_t, client, &mvd->clients, entry ) { cl = client->cl; // do not send unreliables to connecting clients @@ -610,6 +610,15 @@ static void MVD_ParseSound( mvd_t *mvd, int extrabits ) { } } +void MVD_FreePlayer( mvd_player_t *player ) { + mvd_cs_t *cs, *next; + + for( cs = player->configstrings; cs; cs = next ) { + next = cs->next; + Z_Free( cs ); + } +} + static void set_player_name( mvd_player_t *player, const char *string ) { char *p; @@ -624,7 +633,7 @@ static void MVD_ParseConfigstring( mvd_t *mvd ) { int index; size_t len, maxlen; char *string; - udpClient_t *client; + mvd_client_t *client; mvd_player_t *player; mvd_cs_t *cs, **pcs; int i; @@ -645,7 +654,7 @@ static void MVD_ParseConfigstring( mvd_t *mvd ) { // update player name player = &mvd->players[ index - CS_PLAYERSKINS ]; set_player_name( player, string ); - LIST_FOR_EACH( udpClient_t, client, &mvd->udpClients, entry ) { + LIST_FOR_EACH( mvd_client_t, client, &mvd->clients, entry ) { if( client->cl->state < cs_spawned ) { continue; } @@ -675,7 +684,7 @@ static void MVD_ParseConfigstring( mvd_t *mvd ) { MSG_WriteData( string, len + 1 ); // broadcast configstring change - LIST_FOR_EACH( udpClient_t, client, &mvd->udpClients, entry ) { + LIST_FOR_EACH( mvd_client_t, client, &mvd->clients, entry ) { if( client->cl->state < cs_primed ) { continue; } @@ -889,6 +898,68 @@ static void MVD_ParseFrame( mvd_t *mvd ) { mvd->framenum++; } +static void MVD_ClearState( mvd_t *mvd ) { + mvd_player_t *player; + int i; + + // clear all entities, don't trust num_edicts as it is possible + // to miscount removed entities + memset( mvd->edicts, 0, sizeof( mvd->edicts ) ); + mvd->pool.num_edicts = 0; + + // clear all players + for( i = 0; i < mvd->maxclients; i++ ) { + player = &mvd->players[i]; + MVD_FreePlayer( player ); + memset( player, 0, sizeof( *player ) ); + } + mvd->numplayers = 0; + + // free current map + CM_FreeMap( &mvd->cm ); + + if( mvd->intermission ) { + // save oldscores + //strcpy( mvd->oldscores, mvd->layout ); + } + + memset( mvd->configstrings, 0, sizeof( mvd->configstrings ) ); + mvd->layout[0] = 0; + + mvd->framenum = 0; + // intermission flag will be cleared in MVD_ChangeLevel +} + +static void MVD_ChangeLevel( mvd_t *mvd ) { + mvd_client_t *client; + + if( sv.state != ss_broadcast ) { + MVD_Spawn_f(); // the game is just starting + return; + } + + // cause all UDP clients to reconnect + MSG_WriteByte( svc_stufftext ); + MSG_WriteString( va( "changing map=%s; reconnect\n", mvd->mapname ) ); + + LIST_FOR_EACH( mvd_client_t, client, &mvd->clients, entry ) { + if( mvd->intermission && client->cl->state == cs_spawned ) { + // make them switch to previous target instead of MVD dummy + client->target = client->oldtarget; + client->oldtarget = NULL; + } + SV_ClientReset( client->cl ); + client->cl->spawncount = mvd->servercount; + SV_ClientAddMessage( client->cl, MSG_RELIABLE ); + } + + SZ_Clear( &msg_write ); + + mvd->intermission = qfalse; + + SV_SendAsyncPackets(); +} + static void MVD_ParseServerData( mvd_t *mvd ) { int protocol; size_t len, maxlen; @@ -920,7 +991,7 @@ static void MVD_ParseServerData( mvd_t *mvd ) { mvd->clientNum = MSG_ReadShort(); // change gamedir unless playing a demo - if( !mvd->demoplayback ) { + /*if( !mvd->demoplayback )*/ { Cvar_UserSet( "game", mvd->gamedir ); if( FS_NeedRestart() ) { FS_Restart(); @@ -961,6 +1032,7 @@ static void MVD_ParseServerData( mvd_t *mvd ) { mvd->players = MVD_Mallocz( sizeof( mvd_player_t ) * index ); mvd->maxclients = index; } else if( index != mvd->maxclients ) { + // TODO: allow this! MVD_Destroyf( mvd, "Unexpected maxclients change" ); } @@ -1005,18 +1077,17 @@ static void MVD_ParseServerData( mvd_t *mvd ) { MVD_ParseFrame( mvd ); // if the channel has been just created, init some things - if( mvd->state < MVD_WAITING ) { + if( !mvd->state ) { mvd_t *cur; // sort this one into the list of ready channels - LIST_FOR_EACH( mvd_t, cur, &mvd_ready, ready ) { + LIST_FOR_EACH( mvd_t, cur, &mvd_channels, entry ) { if( cur->id > mvd->id ) { break; } } - List_Append( &cur->ready, &mvd->ready ); - mvd->state = mvd->demoplayback ? MVD_READING : MVD_WAITING; - mvd->waitTime = svs.realtime; + List_Append( &cur->entry, &mvd->entry ); + mvd->state = MVD_WAITING; // for local client MVD_CheckActive( mvd ); @@ -1026,54 +1097,9 @@ static void MVD_ParseServerData( mvd_t *mvd ) { MVD_ChangeLevel( mvd ); } -static qboolean MVD_ParseMessage( mvd_t *mvd, fifo_t *fifo ) { - uint16_t msglen; - uint32_t magic; - void *data; - size_t length; +void MVD_ParseMessage( mvd_t *mvd ) { int cmd, extrabits; - // parse magic - if( mvd->state == MVD_CHECKING ) { - if( !FIFO_TryRead( fifo, &magic, 4 ) ) { - return qfalse; - } - if( magic != MVD_MAGIC ) { - MVD_Destroyf( mvd, "Not a MVD stream" ); - } - mvd->state = MVD_PREPARING; - } - - // parse msglen - if( !mvd->msglen ) { - if( !FIFO_TryRead( fifo, &msglen, 2 ) ) { - return qfalse; - } - if( !msglen ) { - MVD_Finish( mvd, "End of MVD stream reached" ); - } - msglen = LittleShort( msglen ); - if( msglen > MAX_MSGLEN ) { - MVD_Destroyf( mvd, "Invalid MVD message length: %u bytes", msglen ); - } - mvd->msglen = msglen; - } - - // first, try to read in a single block - data = FIFO_Peek( fifo, &length ); - if( length < mvd->msglen ) { - if( !FIFO_TryRead( fifo, msg_read_buffer, mvd->msglen ) ) { - return qfalse; // not yet available - } - SZ_Init( &msg_read, msg_read_buffer, sizeof( msg_read_buffer ) ); - } else { - SZ_Init( &msg_read, data, mvd->msglen ); - FIFO_Decommit( fifo, mvd->msglen ); - } - - msg_read.cursize = mvd->msglen; - mvd->msglen = 0; - if( mvd_shownet->integer == 1 ) { Com_Printf( "%"PRIz" ", msg_read.cursize ); } else if( mvd_shownet->integer > 1 ) { @@ -1087,21 +1113,21 @@ static qboolean MVD_ParseMessage( mvd_t *mvd, fifo_t *fifo ) { if( msg_read.readcount > msg_read.cursize ) { MVD_Destroyf( mvd, "Read past end of message" ); } - - if( ( cmd = MSG_ReadByte() ) == -1 ) { + if( msg_read.readcount == msg_read.cursize ) { if( mvd_shownet->integer > 1 ) { Com_Printf( "%3"PRIz":END OF MESSAGE\n", msg_read.readcount - 1 ); } break; } + cmd = MSG_ReadByte(); extrabits = cmd >> SVCMD_BITS; cmd &= SVCMD_MASK; if( mvd_shownet->integer > 1 ) { MVD_ShowSVC( cmd ); } - + switch( cmd ) { case mvd_serverdata: MVD_ParseServerData( mvd ); @@ -1124,10 +1150,6 @@ static qboolean MVD_ParseMessage( mvd_t *mvd, fifo_t *fifo ) { case mvd_frame: MVD_ParseFrame( mvd ); break; - //case mvd_frame_nodelta: - //MVD_ResetFrame( mvd ); - //MVD_ParseFrame( mvd ); - //break; case mvd_sound: MVD_ParseSound( mvd, extrabits ); break; @@ -1139,81 +1161,5 @@ static qboolean MVD_ParseMessage( mvd_t *mvd, fifo_t *fifo ) { msg_read.readcount - 1, cmd ); } } - - return qtrue; -} - -#if USE_ZLIB -static int MVD_Decompress( mvd_t *mvd ) { - byte *data; - size_t avail_in, avail_out; - z_streamp z = &mvd->z; - int ret = Z_BUF_ERROR; - - do { - data = FIFO_Peek( &mvd->stream.recv, &avail_in ); - if( !avail_in ) { - break; - } - z->next_in = data; - z->avail_in = ( uInt )avail_in; - - data = FIFO_Reserve( &mvd->zbuf, &avail_out ); - if( !avail_out ) { - break; - } - z->next_out = data; - z->avail_out = ( uInt )avail_out; - - ret = inflate( z, Z_SYNC_FLUSH ); - - FIFO_Decommit( &mvd->stream.recv, avail_in - z->avail_in ); - FIFO_Commit( &mvd->zbuf, avail_out - z->avail_out ); - } while( ret == Z_OK ); - - return ret; -} -#endif - -qboolean MVD_Parse( mvd_t *mvd ) { - fifo_t *fifo; - -#if USE_ZLIB - if( mvd->z.state ) { - int ret = MVD_Decompress( mvd ); - - switch( ret ) { - case Z_BUF_ERROR: - case Z_OK: - break; - case Z_STREAM_END: - Com_DPrintf( "End of zlib stream reached\n" ); - inflateEnd( &mvd->z ); - break; - default: - MVD_Destroyf( mvd, "inflate() failed: %s", mvd->z.msg ); - } - } - if( mvd->zbuf.data ) { - fifo = &mvd->zbuf; - } else -#endif - { - fifo = &mvd->stream.recv; - } - - if( MVD_ParseMessage( mvd, fifo ) ) { - return qtrue; - } - - // ran out of buffers - if( mvd->state == MVD_DISCONNECTED ) { - MVD_Finish( mvd, "MVD stream was truncated" ); - } - if( mvd->state == MVD_READING ) { - Com_Printf( "[%s] Buffering data...\n", mvd->name ); - MVD_BeginWaiting( mvd ); - } - return qfalse; } |