diff options
-rw-r--r-- | source/cl_scrn.c | 5 | ||||
-rw-r--r-- | source/g_public.h | 2 | ||||
-rw-r--r-- | source/mvd_client.c | 296 | ||||
-rw-r--r-- | source/mvd_game.c | 2 | ||||
-rw-r--r-- | source/mvd_local.h | 9 | ||||
-rw-r--r-- | source/mvd_parse.c | 2 | ||||
-rw-r--r-- | source/sv_game.c | 49 | ||||
-rw-r--r-- | source/sv_http.c | 18 | ||||
-rw-r--r-- | source/sv_local.h | 3 | ||||
-rw-r--r-- | source/sv_main.c | 12 |
10 files changed, 224 insertions, 174 deletions
diff --git a/source/cl_scrn.c b/source/cl_scrn.c index 18571ad..ee0df1d 100644 --- a/source/cl_scrn.c +++ b/source/cl_scrn.c @@ -203,7 +203,7 @@ SCR_DrawDemoBar ================ */ static void SCR_DrawDemoBar( void ) { - int percent, bufferPercent; + //int percent, bufferPercent; if( !scr_demobar->integer ) { return; @@ -215,7 +215,7 @@ static void SCR_DrawDemoBar( void ) { } return; } - +#if 0 if( sv_running->integer != ss_broadcast ) { return; } @@ -230,6 +230,7 @@ static void SCR_DrawDemoBar( void ) { if( scr_demobar->integer & 2 ) { SCR_DrawPercentBar( bufferPercent ); } +#endif } diff --git a/source/g_public.h b/source/g_public.h index 3a07639..703e23c 100644 --- a/source/g_public.h +++ b/source/g_public.h @@ -156,7 +156,7 @@ typedef struct void (*WriteAngle) (float f); // managed memory allocation - void *(*TagMalloc) (int size, memtag_t tag); + void *(*TagMalloc) (size_t size, memtag_t tag); void (*TagFree) (void *block); void (*FreeTags) (memtag_t tag); diff --git a/source/mvd_client.c b/source/mvd_client.c index 721444e..e20de4a 100644 --- a/source/mvd_client.c +++ b/source/mvd_client.c @@ -30,16 +30,14 @@ list_t mvd_channels; list_t mvd_ready; mvd_t mvd_waitingRoom; qboolean mvd_dirty; +int mvd_chanid; jmp_buf mvd_jmpbuf; -cvar_t *mvd_pause; cvar_t *mvd_running; cvar_t *mvd_shownet; cvar_t *mvd_debug; -cvar_t *mvd_nextserver; cvar_t *mvd_timeout; -cvar_t *mvd_safecmd; cvar_t *mvd_wait_enter; cvar_t *mvd_wait_leave; @@ -120,7 +118,7 @@ void MVD_Destroyf( mvd_t *mvd, const char *fmt, ... ) { Q_vsnprintf( text, sizeof( text ), fmt, argptr ); va_end( argptr ); - Com_Printf( S_COLOR_YELLOW "%s\n", text ); + Com_Printf( "[%s] %s\n", mvd->name, text ); MVD_Destroy( mvd ); @@ -135,7 +133,7 @@ void MVD_Dropf( mvd_t *mvd, const char *fmt, ... ) { Q_vsnprintf( text, sizeof( text ), fmt, argptr ); va_end( argptr ); - Com_Printf( S_COLOR_YELLOW "%s\n", text ); + Com_Printf( "[%s] %s\n", mvd->name, text ); MVD_Drop( mvd ); @@ -157,7 +155,7 @@ void MVD_DPrintf( const char *fmt, ... ) { Com_Printf( S_COLOR_BLUE "%s", text ); } -void MVD_HttpPrintf( mvd_t *mvd, const char *fmt, ... ) { +static void MVD_HttpPrintf( mvd_t *mvd, const char *fmt, ... ) { char buffer[MAX_STRING_CHARS]; va_list argptr; int length; @@ -294,72 +292,116 @@ void MVD_SendGamestate( tcpClient_t *client ) { SZ_Clear( &msg_write ); } -void MVD_RejectStream( const char *error, const char *reason ) { +void MVD_GetStatus( void ) { char buffer[MAX_STRING_CHARS]; mvd_t *mvd; - int number, count; + int count; - SV_HttpPrintf( - "HTTP/1.0 %s\r\n" - "Content-Type: text/html; charset=us-ascii\r\n" - "Cache-Control: no-cache\r\n" - "\r\n", error ); + SV_HttpPrintf( "HTTP/1.0 200 OK\r\n" ); - SV_HttpHeader( error ); - SV_HttpPrintf( - "<h1>%s</h1><p>%s</p><table border=\"1\"><tr>" - "<th>Index</th><th>Name</th><th>Map</th><th>Clients</th></tr>", - error, reason ); + if( http_client->method == HTTP_METHOD_HEAD ) { + SV_HttpPrintf( "\r\n" ); + SV_HttpDrop( http_client, "200 OK" ); + return; + } - number = 0; - LIST_FOR_EACH( mvd_t, mvd, &mvd_ready, entry ) { - SV_HttpPrintf( - "<tr><td><a href=\"http://%s/mvdstream/%d\">%d</a></td>", - http_host, number, number ); + SV_HttpPrintf( + "Content-Type: text/html; charset=us-ascii\r\n" + "\r\n" ); - Q_EscapeMarkup( buffer, mvd->name, sizeof( buffer ) ); - SV_HttpPrintf( "<td>%s</td>", buffer ); + count = SV_CountClients(); + Q_EscapeMarkup( buffer, sv_hostname->string, sizeof( buffer ) ); + SV_HttpHeader( va( "%s - %d/%d", buffer, count, sv_maxclients->integer ) ); + SV_HttpPrintf( "<h1>Status page of %s</h1>" + "<p>This server has ", buffer ); - Q_EscapeMarkup( buffer, mvd->mapname, sizeof( buffer ) ); - count = List_Count( &mvd->udpClients ); - SV_HttpPrintf( "<td>%s</td><td>%d</td></tr>", buffer, count ); + count = List_Count( &mvd_ready ); + if( count ) { + SV_HttpPrintf( "%d MVD stream%s available. ", + count, count == 1 ? "" : "s" ); + } else { + SV_HttpPrintf( "no MVD streams available. " ); + } - number++; + count = List_Count( &mvd_waitingRoom.udpClients ); + if( count ) { + SV_HttpPrintf( "Waiting room has %d client%s.</p>", + count, count == 1 ? "" : "s" ); + } else { + SV_HttpPrintf( "Waiting room is empty.</p>" ); } - SV_HttpPrintf( "</table>" ); + + if( !LIST_EMPTY( &mvd_ready ) ) { + SV_HttpPrintf( + "<table border=\"1\"><tr>" + "<th>ID</th><th>Name</th><th>Map</th><th>Clients</th></tr>" ); + + LIST_FOR_EACH( mvd_t, mvd, &mvd_ready, ready ) { + SV_HttpPrintf( + "<tr><td><a href=\"http://%s/mvdstream/%d\">%d</a></td>", + http_host, mvd->id, mvd->id ); + + Q_EscapeMarkup( buffer, mvd->name, sizeof( buffer ) ); + SV_HttpPrintf( + "<td><a href=\"http://%s/mvdstream/%d\">%s</a></td>", + http_host, mvd->id, buffer ); + + Q_EscapeMarkup( buffer, mvd->mapname, sizeof( buffer ) ); + count = List_Count( &mvd->udpClients ); + SV_HttpPrintf( "<td>%s</td><td>%d</td></tr>", buffer, count ); + } + SV_HttpPrintf( "</table><br>" ); + } + + SV_HttpPrintf( "<a href=\"quake2://%s\">Join this server</a>", http_host ); SV_HttpFooter(); - SV_HttpDrop( http_client, error ); + SV_HttpDrop( http_client, "200 OK" ); } -void MVD_GetStream( const char *uri ) { +static mvd_t *MVD_SetStream( const char *uri ) { mvd_t *mvd; - int index; - uint32 magic; + int id; + + if( LIST_EMPTY( &mvd_ready ) ) { + SV_HttpReject( "503 Service Unavailable", + "No MVD streams are available on this server." ); + return NULL; + } if( *uri == '/' ) { uri++; } - if( !*uri ) { - if( LIST_EMPTY( &mvd_ready ) ) { - SV_HttpReject( "503 Service Unavailable", - "No MVD streams available." ); - } else { - MVD_RejectStream( "300 Multiple Choices", - "There are several MVD channels available. " - "Please select an appropriate stream." ); + if( *uri == 0 ) { + if( List_Count( &mvd_ready ) == 1 ) { + return LIST_FIRST( mvd_t, &mvd_ready, ready ); } - return; + strcpy( http_header, "Cache-Control: no-cache\r\n" ); + SV_HttpReject( "300 Multiple Choices", + "Please specify an exact stream ID." ); + return NULL; } - index = atoi( uri ); + id = atoi( uri ); + LIST_FOR_EACH( mvd_t, mvd, &mvd_ready, ready ) { + if( mvd->id == id ) { + return mvd; + } + } - mvd = LIST_INDEX( mvd_t, index, &mvd_ready, ready ); + SV_HttpReject( "404 Not Found", + "Requested MVD stream was not found on this server." ); + return NULL; +} + +void MVD_GetStream( const char *uri ) { + mvd_t *mvd; + uint32 magic; + + mvd = MVD_SetStream( uri ); if( !mvd ) { - MVD_RejectStream( "404 Not Found", - "Requested MVD stream was not found on this server." ); return; } @@ -415,27 +457,6 @@ void MVD_ChangeLevel( mvd_t *mvd ) { SV_SendAsyncPackets(); } -#ifndef DEDICATED_ONLY -/* called by the client code */ -qboolean MVD_GetDemoPercent( int *percent, int *bufferPercent ) { -#if 0 - int delta; - - if( !mvd.demoplayback ) { - return qfalse; - } - - delta = mvd.serverPacketNum - mvd.timelines[0].framenum; - *bufferPercent = 100 - delta * 100 / ( mvd.frameBackup - 1 ); - *percent = mvd.demofilePercent; - - return qtrue; -#else - return qfalse; -#endif -} -#endif - static void MVD_ReadDemo( mvd_t *mvd ) { byte *data; int length, read, total = 0; @@ -595,6 +616,13 @@ void MVD_Frame( void ) { ret = NET_Run( &mvd->stream ); switch( ret ) { case NET_AGAIN: + // check timeout + if( mvd->lastReceived > svs.realtime ) { + mvd->lastReceived = svs.realtime; + } + if( svs.realtime - mvd->lastReceived > mvd_timeout->value * 1000 ) { + MVD_Dropf( mvd, "Connection timed out" ); + } continue; case NET_ERROR: MVD_Dropf( mvd, "%s to %s", NET_ErrorString(), @@ -605,10 +633,13 @@ void MVD_Frame( void ) { break; } + // don't timeout + mvd->lastReceived = svs.realtime; + // run MVD state machine switch( mvd->state ) { case MVD_CONNECTING: - Com_Printf( "Connected, awaiting response...\n" ); + Com_Printf( "[%s] Connected, awaiting response...\n", mvd->name ); mvd->state = MVD_CONNECTED; // fall through case MVD_CONNECTED: @@ -619,7 +650,7 @@ void MVD_Frame( void ) { MVD_Dropf( mvd, "HTTP request failed: %d %s", mvd->statusCode, mvd->statusText ); } - Com_Printf( "Got response, awaiting gamestate...\n" ); + Com_Printf( "[%s] Got response, awaiting gamestate...\n", mvd->name ); mvd->state = MVD_CHECKING; // fall through case MVD_CHECKING: @@ -631,14 +662,14 @@ void MVD_Frame( void ) { usage = MVD_BufferPercent( mvd ); if( mvd->state == MVD_WAITING ) { if( usage >= mvd_wait_leave->value ) { - Com_Printf( "Reading data...\n" ); + Com_Printf( "[%s] Reading data...\n", mvd->name ); mvd->state = MVD_READING; } } else { if( mvd_wait_leave->value > mvd_wait_enter->value && usage < mvd_wait_enter->value ) { - Com_Printf( "Buffering data...\n" ); + Com_Printf( "[%s] Buffering data...\n", mvd->name ); mvd->state = MVD_WAITING; } } @@ -659,28 +690,36 @@ OPERATOR COMMANDS mvd_t *MVD_SetChannel( int arg ) { char *s = Cmd_Argv( arg ); mvd_t *mvd; + int id; + + if( LIST_EMPTY( &mvd_channels ) ) { + Com_Printf( "No active channels.\n" ); + return NULL; + } if( !*s ) { if( List_Count( &mvd_channels ) == 1 ) { return LIST_FIRST( mvd_t, &mvd_channels, entry ); } - Com_Printf( "Please specify a channel\n" ); + Com_Printf( "Please specify an exact channel ID.\n" ); return NULL; } - mvd = LIST_INDEX( mvd_t, atoi( s ), &mvd_channels, entry ); - if( mvd ) { - return mvd; + id = atoi( s ); + LIST_FOR_EACH( mvd_t, mvd, &mvd_channels, entry ) { + if( mvd->id == id ) { + return mvd; + } } - Com_Printf( "No such channel: %s\n", s ); + Com_Printf( "No such channel ID: %s\n", s ); return NULL; } void MVD_Spawn_f( void ) { SV_InitGame( qtrue ); - /* set serverinfo variables */ + // set serverinfo variables Cvar_Set( "mapname", "nomap" ); Cvar_SetInteger( "sv_running", ss_broadcast ); Cvar_SetInteger( "sv_paused", 0 ); @@ -694,19 +733,18 @@ void MVD_Spawn_f( void ) { void MVD_ListChannels_f( void ) { mvd_t *mvd; - int number, usage; + int usage; if( LIST_EMPTY( &mvd_channels ) ) { Com_Printf( "No active channels.\n" ); return; } - Com_Printf( "num name map state buf address \n" - "--- ---------------- -------- ----- --- --------------\n" ); + Com_Printf( "id name map state buf address \n" + "-- ---------------- -------- ----- --- --------------\n" ); - number = 0; LIST_FOR_EACH( mvd_t, mvd, &mvd_channels, entry ) { - Com_Printf( "%3d %-16.16s %-8.8s", number, + Com_Printf( "%2d %-16.16s %-8.8s", mvd->id, mvd->name, mvd->mapname ); switch( mvd->state ) { case MVD_DEAD: @@ -731,14 +769,7 @@ void MVD_ListChannels_f( void ) { break; } usage = MVD_BufferPercent( mvd ); - Com_Printf( " %3d ", usage ); - if( mvd->demoplayback ) { - Com_Printf( "%s", mvd->demopath ); - } else { - Com_Printf( "%s", NET_AdrToString( &mvd->stream.address ) ); - } - Com_Printf( "\n" ); - number++; + Com_Printf( " %3d %s\n", usage, mvd->address ); } } @@ -748,12 +779,12 @@ void MVD_StreamedStop_f( void ) { mvd = MVD_SetChannel( 1 ); if( !mvd ) { - Com_Printf( "Usage: %s [channel]\n", Cmd_Argv( 0 ) ); + Com_Printf( "Usage: %s [chanid]\n", Cmd_Argv( 0 ) ); return; } if( !mvd->demorecording ) { - Com_Printf( "Not recording on channel %s.\n", mvd->name ); + Com_Printf( "[%s] Not recording a demo.\n", mvd->name ); return; } @@ -764,7 +795,7 @@ void MVD_StreamedStop_f( void ) { mvd->demofile = 0; mvd->demorecording = qfalse; - Com_Printf( "Stopped recording on channel %s.\n", mvd->name ); + Com_Printf( "[%s] Stopped recording.\n", mvd->name ); } void MVD_StreamedRecord_f( void ) { @@ -775,17 +806,17 @@ void MVD_StreamedRecord_f( void ) { uint32 magic; if( Cmd_Argc() < 2 || ( mvd = MVD_SetChannel( 2 ) ) == NULL ) { - Com_Printf( "Usage: %s [/]<filename> [channel]\n", Cmd_Argv( 0 ) ); + Com_Printf( "Usage: %s [/]<filename> [chanid]\n", Cmd_Argv( 0 ) ); return; } if( mvd->demorecording ) { - Com_Printf( "Already recording on channel %s.\n", mvd->name ); + Com_Printf( "[%s] Already recording.\n", mvd->name ); return; } if( mvd->state < MVD_WAITING ) { - Com_Printf( "Channel %s is not ready for recording.\n", mvd->name ); + Com_Printf( "[%s] Channel not ready.\n", mvd->name ); return; } @@ -806,7 +837,7 @@ void MVD_StreamedRecord_f( void ) { return; } - Com_Printf( "Recording on channel %s into %s\n", mvd->name, buffer ); + Com_Printf( "[%s] Recording into %s.\n", mvd->name, buffer ); mvd->demofile = f; mvd->demorecording = qtrue; @@ -838,17 +869,20 @@ void MVD_Connect_f( void ) { mvd_t *mvd; uint16 port; - if ( Cmd_Argc() < 2 ) { - Com_Printf( "Usage: %s <[http://][user:pass@]server[:port][/resource]> [name]", Cmd_Argv( 0 ) ); + if( Cmd_Argc() < 2 ) { + Com_Printf( "Usage: %s [http://][user:pass@]<host>[:port][/resource] [stream_id] [chan_name]", Cmd_Argv( 0 ) ); return; } Cmd_ArgvBuffer( 1, buffer, sizeof( buffer ) ); + // skip optional http:// prefix host = buffer; if( !strncmp( host, "http://", 7 ) ) { host += 7; } + + // parse credentials p = strchr( host, '@' ); if( p ) { *p = 0; @@ -857,6 +891,8 @@ void MVD_Connect_f( void ) { } else { credentials[0] = 0; } + + // parse resource p = strchr( host, '/' ); if( p ) { *p = 0; @@ -867,11 +903,12 @@ void MVD_Connect_f( void ) { "mvdstream/", Cmd_Argv( 2 ), NULL ); port = BigShort( PORT_SERVER ); } + + // resolve hostname if( !NET_StringToAdr( host, &adr ) ) { Com_Printf( "Bad server address: %s\n", host ); return; } - if( !adr.port ) { adr.port = port; } @@ -882,16 +919,10 @@ void MVD_Connect_f( void ) { return; } - p = Cmd_Argv( 2 ); - Z_TagReserve( sizeof( *mvd ) + MAX_MSGLEN * 2 + 256, TAG_MVD ); mvd = Z_ReservedAllocz( sizeof( *mvd ) ); - if( *p ) { - Q_strncpyz( mvd->name, p, sizeof( mvd->name ) ); - } else { - strcpy( mvd->name, "unnamed stream" ); - } + mvd->id = mvd_chanid++; mvd->state = MVD_CONNECTING; mvd->stream = stream; mvd->stream.recv.data = Z_ReservedAlloc( MAX_MSGLEN * 2 ); @@ -902,12 +933,27 @@ void MVD_Connect_f( void ) { mvd->pool.edict_size = sizeof( edict_t ); mvd->pool.max_edicts = MAX_EDICTS; mvd->pm_type = PM_SPECTATOR; + mvd->lastReceived = svs.realtime; List_Init( &mvd->udpClients ); List_Init( &mvd->tcpClients ); List_Init( &mvd->ready ); List_Append( &mvd_channels, &mvd->entry ); - Com_Printf( "Connecting to %s...\n", NET_AdrToString( &adr ) ); + // set channel name + if( p ) { + p = Cmd_Argv( 2 ); + } else { + p = Cmd_Argv( 3 ); + } + if( *p ) { + Q_strncpyz( mvd->name, p, sizeof( mvd->name ) ); + } else { + Com_sprintf( mvd->name, sizeof( mvd->name ), "net%d", mvd->id ); + } + + Q_strncpyz( mvd->address, host, sizeof( mvd->address ) ); + + Com_Printf( "[%s] Connecting to %s...\n", mvd->name, NET_AdrToString( &adr ) ); MVD_HttpPrintf( mvd, "GET /%s HTTP/1.0\r\n" @@ -930,17 +976,16 @@ static void MVD_Disconnect_f( void ) { mvd = MVD_SetChannel( 1 ); if( !mvd ) { - Com_Printf( "Usage: %s [channel]\n", Cmd_Argv( 0 ) ); return; } if( mvd->state == MVD_DISCONNECTED ) { - Com_Printf( "Channel is already disconnected.\n" ); + Com_Printf( "[%s] Already disconnected.\n", mvd->name ); return; } + Com_Printf( "[%s] Channel was disconnected.\n", mvd->name ); MVD_Drop( mvd ); - Com_Printf( "Channel was disconnected.\n" ); } static void MVD_Kill_f( void ) { @@ -948,12 +993,11 @@ static void MVD_Kill_f( void ) { mvd = MVD_SetChannel( 1 ); if( !mvd ) { - Com_Printf( "Usage: %s [channel]\n", Cmd_Argv( 0 ) ); return; } + Com_Printf( "[%s] Channel was killed.\n", mvd->name ); MVD_Destroy( mvd ); - Com_Printf( "Channel was killed.\n" ); } const char *MVD_Play_g( const char *partial, int state ) { @@ -965,12 +1009,11 @@ void MVD_Play_f( void ) { char *name; char buffer[MAX_OSPATH]; fileHandle_t f; - int length; uint32 magic = 0; mvd_t *mvd; if( Cmd_Argc() < 2 ) { - Com_Printf( "Usage: %s [/]<filename>\n", Cmd_Argv( 0 ) ); + Com_Printf( "Usage: %s [/]<filename> [chanid]\n", Cmd_Argv( 0 ) ); return; } @@ -997,7 +1040,7 @@ void MVD_Play_f( void ) { Z_TagReserve( sizeof( *mvd ) + MAX_MSGLEN * 2, TAG_MVD ); mvd = Z_ReservedAllocz( sizeof( *mvd ) ); - strcpy( mvd->name, "unnamed demo" ); + mvd->id = mvd_chanid++; mvd->state = MVD_PREPARING; mvd->demoplayback = qtrue; mvd->demofile = f; @@ -1012,14 +1055,16 @@ void MVD_Play_f( void ) { List_Init( &mvd->ready ); List_Append( &mvd_channels, &mvd->entry ); - if( dedicated->integer && !sv_nextserver->string[0] ) { - Cvar_Set( "nextserver", va( "mvdplay /%s", buffer ) ); + // set channel name + name = Cmd_Argv( 2 ); + if( *name ) { + Q_strncpyz( mvd->name, name, sizeof( mvd->name ) ); + } else { + Com_sprintf( mvd->name, sizeof( mvd->name ), "dem%d", mvd->id ); } - length = FS_GetFileLengthNoCache( mvd->demofile ); - mvd->demofileFrameOffset = FS_Tell( mvd->demofile ); - mvd->demofileSize = length - mvd->demofileFrameOffset; - strcpy( mvd->demopath, buffer ); + // set channel address + Q_strncpyz( mvd->address, COM_SkipPath( buffer ), sizeof( mvd->address ) ); } @@ -1040,6 +1085,8 @@ void MVD_Shutdown( void ) { mvd_clients = NULL; } + mvd_chanid = 0; + Z_LeakTest( TAG_MVD ); } @@ -1063,10 +1110,7 @@ MVD_Register void MVD_Register( void ) { mvd_shownet = Cvar_Get( "mvd_shownet", "0", 0 ); mvd_debug = Cvar_Get( "mvd_debug", "0", 0 ); - mvd_pause = Cvar_Get( "mvd_pause", "0", 0 ); - mvd_nextserver = Cvar_Get( "mvd_nextserver", "1", 0 ); mvd_timeout = Cvar_Get( "mvd_timeout", "120", 0 ); - mvd_safecmd = Cvar_Get( "mvd_safecmd", "", 0 ); mvd_wait_enter = Cvar_Get( "mvd_wait_enter", "0.5", 0 ); mvd_wait_leave = Cvar_Get( "mvd_wait_leave", "2", 0 ); diff --git a/source/mvd_game.c b/source/mvd_game.c index daf374e..2b5e2c2 100644 --- a/source/mvd_game.c +++ b/source/mvd_game.c @@ -338,6 +338,8 @@ void MVD_SwitchChannel( udpClient_t *client, mvd_t *mvd ) { client_t *cl = client->cl; if( mvd == client->mvd ) { + SV_ClientPrintf( client->cl, PRINT_HIGH, + "[MVD] You are already on this channel.\n" ); return; // nothing to do } diff --git a/source/mvd_local.h b/source/mvd_local.h index 99a5365..7971a12 100644 --- a/source/mvd_local.h +++ b/source/mvd_local.h @@ -100,22 +100,21 @@ typedef struct { typedef struct mvd_s { list_t entry; list_t ready; + + int id; char name[MAX_QPATH]; // demo related variables fileHandle_t demofile; qboolean demoplayback; qboolean demorecording; - int demofileSize; - int demofileFrameOffset; - int demofilePercent; - char demopath[MAX_QPATH]; // connection variables mvdState_t state; int servercount; int clientNum; netstream_t stream; + char address[MAX_QPATH]; char response[MAX_NET_STRING]; int responseLength; int contentLength; @@ -127,6 +126,7 @@ typedef struct mvd_s { #endif fifo_t zbuf; int framenum; + int lastReceived; // game state char gamedir[MAX_QPATH]; @@ -174,6 +174,7 @@ void MVD_Disconnect( mvd_t *mvd ); void MVD_ClearState( mvd_t *mvd ); void MVD_ChangeLevel( mvd_t *mvd ); void MVD_GetStream( const char *uri ); +void MVD_GetStatus( void ); void MVD_Free( mvd_t *mvd ); void MVD_Shutdown( void ); diff --git a/source/mvd_parse.c b/source/mvd_parse.c index 2b5731f..363572d 100644 --- a/source/mvd_parse.c +++ b/source/mvd_parse.c @@ -912,7 +912,7 @@ static void MVD_ParseServerData( mvd_t *mvd ) { // load the world model (we are only interesed in // visibility info, do not load brushes and such) - Com_Printf( "Loading %s...\n", string ); + Com_Printf( "[%s] Loading %s...\n", mvd->name, string ); CM_LoadMap( &mvd->cm, string, CM_LOAD_VISONLY, &checksum ); #if USE_MAPCHECKSUM diff --git a/source/sv_game.c b/source/sv_game.c index f135b36..fa8b8c3 100644 --- a/source/sv_game.c +++ b/source/sv_game.c @@ -86,13 +86,13 @@ static void PF_Unicast( edict_t *ent, qboolean reliable ) { clientNum = NUM_FOR_EDICT( ent ) - 1; if( clientNum < 0 || clientNum >= sv_maxclients->integer ) { - Com_WPrintf( "unicast to a non-client %d\n", clientNum ); + Com_WPrintf( "PF_Unicast to a non-client %d\n", clientNum ); return; } client = svs.clientpool + clientNum; if( client->state == cs_free ) { - Com_WPrintf( "unicast to a free client %d\n", clientNum ); + Com_WPrintf( "PF_Unicast to a free client %d\n", clientNum ); return; } @@ -115,12 +115,10 @@ static void PF_Unicast( edict_t *ent, qboolean reliable ) { if( client == svs.mvd.dummy ) { if( msg_write.data[0] == svc_stufftext && reliable ) { - /* probably some Q2Admin crap, - * let MVD client process this internally */ + // let MVD client process this internally SV_ClientAddMessage( client, flags ); } else if( sv.mvd.paused < PAUSED_FRAMES ) { - /* otherwise, MVD client will send - * this to everyone in freefloat mode */ + // send this to all observers SV_MvdUnicast( buf, clientNum, op ); } } else { @@ -161,7 +159,7 @@ static void PF_bprintf( int level, const char *fmt, ... ) { // echo to console if( dedicated->integer ) { // mask off high bits - for( i = 0; string[i]; i++ ) + for( i = 0; i < length; i++ ) string[i] &= 127; Com_Printf( "%s", string ); } @@ -225,12 +223,12 @@ static void PF_cprintf( edict_t *ent, int level, const char *fmt, ... ) { clientNum = NUM_FOR_EDICT( ent ) - 1; if( clientNum < 0 || clientNum >= sv_maxclients->integer ) { - Com_Error( ERR_DROP, "cprintf to a non-client %d", clientNum ); + Com_Error( ERR_DROP, "PF_cprintf to a non-client %d", clientNum ); } client = svs.clientpool + clientNum; if( client->state == cs_free ) { - Com_Error( ERR_DROP, "cprintf to a free client %d", clientNum ); + Com_Error( ERR_DROP, "PF_cprintf to a free client %d", clientNum ); } MSG_WriteByte( svc_print ); @@ -259,7 +257,7 @@ Centerprint to a single client. Archived in MVD stream. =============== */ -static void PF_centerprintf (edict_t *ent, const char *fmt, ...) { +static void PF_centerprintf( edict_t *ent, const char *fmt, ... ) { char msg[MAX_STRING_CHARS]; va_list argptr; int n, length; @@ -268,20 +266,20 @@ static void PF_centerprintf (edict_t *ent, const char *fmt, ...) { return; } - n = NUM_FOR_EDICT(ent); - if (n < 1 || n > sv_maxclients->integer) { - Com_WPrintf( "centerprintf to a non-client\n" ); + n = NUM_FOR_EDICT( ent ); + if( n < 1 || n > sv_maxclients->integer ) { + Com_WPrintf( "PF_centerprintf to a non-client\n" ); return; } - va_start (argptr,fmt); + va_start( argptr, fmt ); length = Q_vsnprintf( msg, sizeof( msg ), fmt, argptr ); - va_end (argptr); + va_end( argptr ); - MSG_WriteByte (svc_centerprint); - MSG_WriteData (msg, length + 1); + MSG_WriteByte( svc_centerprint ); + MSG_WriteData( msg, length + 1 ); - PF_Unicast (ent, qtrue); + PF_Unicast( ent, qtrue ); } @@ -739,19 +737,6 @@ static qboolean PF_AreasConnected( int area1, int area2 ) { return CM_AreasConnected( &sv.cm, area1, area2 ); } -static void *PF_TagMalloc( int size, memtag_t tag ) { - void *ptr; - - if( !size ) { - return NULL; - } - - ptr = Z_TagMalloc( size, tag ); - memset( ptr, 0, size ); - - return ptr; -} - //============================================== static void *game_library; @@ -908,7 +893,7 @@ void SV_InitGameProgs ( void ) import.WriteDir = MSG_WriteDir; import.WriteAngle = MSG_WriteAngle; - import.TagMalloc = PF_TagMalloc; + import.TagMalloc = Z_TagMallocz; import.TagFree = Z_Free; import.FreeTags = Z_FreeTags; diff --git a/source/sv_http.c b/source/sv_http.c index a2eea65..feb37aa 100644 --- a/source/sv_http.c +++ b/source/sv_http.c @@ -62,7 +62,7 @@ void SV_HttpReject( const char *error, const char *reason ) { SV_HttpDrop( http_client, error ); } -static void uri_status( const char *uri ) { +static void SV_GetStatus( void ) { char buffer[MAX_STRING_CHARS]; cvar_t *var; client_t *cl; @@ -88,13 +88,7 @@ static void uri_status( const char *uri ) { // "Content-Encoding: deflate\r\n" "\r\n" ); - count = 0; - FOR_EACH_CLIENT( cl ) { - if( cl->state != cs_zombie ) { - count++; - } - } - + count = SV_CountClients(); Q_EscapeMarkup( buffer, sv_hostname->string, sizeof( buffer ) ); SV_HttpHeader( va( "%s - %d/%d", buffer, count, sv_maxclients->integer ) ); SV_HttpPrintf( "<h1>Status page of %s</h1>", buffer ); @@ -149,6 +143,14 @@ static void uri_status( const char *uri ) { SV_HttpDrop( http_client, "200 OK" ); } +static void uri_status( const char *uri ) { + if( sv.state == ss_game ) { + SV_GetStatus(); + } else { + MVD_GetStatus(); + } +} + static void uri_mvdstream( const char *uri ) { if( !sv_mvd_enable->integer ) { SV_HttpReject( "403 Forbidden", diff --git a/source/sv_local.h b/source/sv_local.h index b4bb68c..c739cbf 100644 --- a/source/sv_local.h +++ b/source/sv_local.h @@ -382,6 +382,8 @@ void SV_RateInit( ratelimit_t *r, int limit, int period ); addrmatch_t *SV_MatchAddress( list_t *list, netadr_t *address ); void SV_DumpMatches( list_t *list ); +int SV_CountClients( void ); + void Master_Heartbeat (void); void Master_Packet (void); @@ -456,6 +458,7 @@ void SV_MvdSpawnDummy( void ); extern tcpClient_t *http_client; extern char http_host[MAX_STRING_CHARS]; +extern char http_header[MAX_STRING_CHARS]; void SV_HttpRun( void ); diff --git a/source/sv_main.c b/source/sv_main.c index 008a194..089b2c4 100644 --- a/source/sv_main.c +++ b/source/sv_main.c @@ -1011,6 +1011,18 @@ static void SV_ConnectionlessPacket( void ) { //============================================================================ + +int SV_CountClients( void ) { + client_t *cl; + int count = 0; + + FOR_EACH_CLIENT( cl ) { + if( cl->state > cs_zombie ) { + count++; + } + } + return count; +} /* =================== SV_CalcPings |