diff options
author | Andrey Nazarov <skuller@skuller.net> | 2008-10-11 15:05:50 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2008-10-11 15:05:50 +0000 |
commit | d02633af4e780c4b6f6d938c67d84d2c968adb79 (patch) | |
tree | 3379b9615e285346ad6b1f87639912e01ecd44c7 /source/mvd_parse.c | |
parent | f8abe42a0d1a42653b39f6cf320d3fbdd1279bb3 (diff) |
Major redesign of GTV protocol: added support for persistent GTV connections,
bidirectional pinging, low traffic (`suspended') modes.
HTTP server is now gone (remote console logging is temporary gone too),
custom binary protocol is used for GTV connections now.
MVD client no longer serves other MVD clients, only regular spectators.
Changed FIFO buffers to be regular circular buffers, not BIP-buffers.
Removed `sv_http_*', `sv_console_auth' variables.
Added `sv_mvd_maxclients' variable, `addgtvhost', `delgtvhost' and
`listgtvhosts' commands.
Renamed `sv_mvd_max*' cvars for consistency.
Reset `sv_ghostime' default value back to 6, but changed semantics:
it now waits for any packet from client, not just `begin' packet.
Added `--disable-mvd-server' and `--disable-mvd-client' options to
configure script.
FS_Restart() no longer chokes on real files opened for reading.
Fixed client chat prompt length.
Stubbed out more debugging stuff from dedicated server builds.
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; } |