summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/cl_scrn.c5
-rw-r--r--source/g_public.h2
-rw-r--r--source/mvd_client.c296
-rw-r--r--source/mvd_game.c2
-rw-r--r--source/mvd_local.h9
-rw-r--r--source/mvd_parse.c2
-rw-r--r--source/sv_game.c49
-rw-r--r--source/sv_http.c18
-rw-r--r--source/sv_local.h3
-rw-r--r--source/sv_main.c12
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