/* * TV_Upstream_Precache_f */ static void TV_Upstream_Precache_f( upstream_t *upstream ) { upstream->precacheDone = qtrue; TV_Upstream_AutoRecordAction( upstream, upstream->configstrings[CS_AUTORECORDSTATE] ); // TODO actually check that we have the stuff TV_Upstream_AddReliableCommand( upstream, va( "begin %i\n", atoi( Cmd_Argv( 1 ) ) ) ); TV_Upstream_AddReliableCommand( upstream, "multiview 1\n" ); }
/* * TV_Cmd_f */ static void TV_Cmd_f( void ) { upstream_t *upstream; if( Cmd_Argc() != 3 ) { Com_Printf( "Usage: cmd <server> <command>\n" ); return; } if( !TV_UpstreamForText( Cmd_Argv( 1 ), &upstream ) ) { Com_Printf( "No such upstream\n" ); return; } if( !upstream ) { Com_Printf( "Can't send commands to lobby\n" ); return; } if( !Cmd_Argv( 2 )[0] ) { Com_Printf( "Empty command\n" ); return; } TV_Upstream_AddReliableCommand( upstream, Cmd_Argv( 2 ) ); }
/* * TV_Upstream_ServerReconnect_f * * The server is changing levels */ static void TV_Upstream_ServerReconnect_f( upstream_t *upstream ) { if( upstream->demo.playing ) return; if( upstream->state < CA_CONNECTED ) { Com_Printf( "%s: reconnect request while not connected\n", NET_AddressToString( &upstream->serveraddress ) ); return; } if( upstream->demo.recording ) TV_Upstream_StopDemoRecord( upstream, upstream->demo.autorecording, qfalse ); Com_Printf( "%s: reconnecting...\n", NET_AddressToString( &upstream->serveraddress ) ); upstream->connect_count = 0; upstream->rejected = 0; #ifdef TCP_ALLOW_CONNECT upstream->connect_time = tvs.realtime; #else upstream->connect_time = tvs.realtime - 1500; #endif upstream->state = CA_HANDSHAKE; TV_Upstream_AddReliableCommand( upstream, "new" ); }
/* * TV_Upstream_ParseServerData */ static void TV_Upstream_ParseServerData( upstream_t *upstream, msg_t *msg ) { int i, numpure; TV_Upstream_ClearState( upstream ); upstream->state = CA_CONNECTED; // parse protocol version number i = MSG_ReadLong( msg ); if( i != APP_PROTOCOL_VERSION ) TV_Upstream_Error( upstream, "Server returned version %i, not %i", i, APP_PROTOCOL_VERSION ); upstream->servercount = MSG_ReadLong( msg ); upstream->snapFrameTime = (unsigned int) MSG_ReadShort( msg ); Q_strncpyz( upstream->basegame, MSG_ReadString( msg ), sizeof( upstream->basegame ) ); Q_strncpyz( upstream->game, MSG_ReadString( msg ), sizeof( upstream->game ) ); // parse player entity number upstream->playernum = MSG_ReadShort( msg ); // get the full level name Q_strncpyz( upstream->levelname, MSG_ReadString( msg ), sizeof( upstream->levelname ) ); upstream->sv_bitflags = MSG_ReadByte( msg ); upstream->reliable = ( ( upstream->sv_bitflags & SV_BITFLAGS_RELIABLE ) ? true : false ); if( ( upstream->sv_bitflags & SV_BITFLAGS_HTTP ) != 0 ) { if( ( upstream->sv_bitflags & SV_BITFLAGS_HTTP_BASEURL ) != 0 ) { // read base upstream url MSG_ReadString( msg ); } else { // http port number MSG_ReadShort( msg ); } } // pure list // clean old, if necessary Com_FreePureList( &upstream->purelist ); // add new numpure = MSG_ReadShort( msg ); while( numpure > 0 ) { const char *pakname = MSG_ReadString( msg ); const unsigned checksum = MSG_ReadLong( msg ); Com_AddPakToPureList( &upstream->purelist, pakname, checksum, upstream->mempool ); numpure--; } TV_Upstream_AddReliableCommand( upstream, va( "configstrings %i 0", upstream->servercount ) ); }
/* * TV_Upstream_ClientConnectPacket * ClientConnect in client code */ static void TV_Upstream_ClientConnectPacket( upstream_t *upstream, msg_t *msg ) { if( upstream->state != CA_CONNECTING ) { return; } Netchan_Setup( &upstream->netchan, upstream->socket, &upstream->serveraddress, Netchan_GamePort() ); upstream->state = CA_HANDSHAKE; TV_Upstream_AddReliableCommand( upstream, "new" ); Com_Printf( "%s" S_COLOR_WHITE ": Connected\n", upstream->name ); }
/* * TV_Upstream_ForwardToServer_f */ static void TV_Upstream_ForwardToServer_f( upstream_t *upstream ) { if( upstream->state != CA_CONNECTED && upstream->state != CA_ACTIVE ) { Com_Printf( "Can't \"%s\", not connected\n", Cmd_Argv( 0 ) ); return; } // don't forward the first argument if( Cmd_Argc() > 1 ) TV_Upstream_AddReliableCommand( upstream, Cmd_Args() ); }
/* * TV_Upstream_StartDemoRecord */ void TV_Upstream_StartDemoRecord( upstream_t *upstream, const char *demoname, qboolean silent ) { char *servername, *temp; size_t name_size; assert( upstream ); assert( demoname ); if( upstream->demo.playing ) { if( !silent ) Com_Printf( "You can't record from another demo.\n" ); return; } if( upstream->demo.recording ) { if( !silent ) Com_Printf( "Already recording.\n" ); return; } // strip the port number from servername servername = TempCopyString( upstream->servername ); temp = strstr( servername, ":" ); if( temp ) *temp = '\0'; // store the name name_size = sizeof( char ) * ( strlen( "demos/tvserver" ) + 1 + strlen( servername ) + 1 + strlen( demoname ) + strlen( APP_DEMO_EXTENSION_STR ) + 1 ); upstream->demo.filename = Mem_ZoneMalloc( name_size ); Q_snprintfz( upstream->demo.filename, name_size, "demos/tvserver/%s/%s", servername, demoname ); COM_SanitizeFilePath( upstream->demo.filename ); COM_DefaultExtension( upstream->demo.filename, APP_DEMO_EXTENSION_STR, name_size ); Mem_TempFree( servername ); if( !COM_ValidateRelativeFilename( upstream->demo.filename ) ) { if( !silent ) Com_Printf( "Invalid filename.\n" ); Mem_ZoneFree( upstream->demo.filename ); return; } // temp name name_size = sizeof( char ) * ( strlen( upstream->demo.filename ) + strlen( ".rec" ) + 1 ); upstream->demo.tempname = Mem_ZoneMalloc( name_size ); Q_snprintfz( upstream->demo.tempname, name_size, "%s.rec", upstream->demo.filename ); // open the demo file if( FS_FOpenFile( upstream->demo.tempname, &upstream->demo.filehandle, FS_WRITE|SNAP_DEMO_GZ ) == -1 ) { Com_Printf( "Error: Couldn't create the demo file.\n" ); Mem_ZoneFree( upstream->demo.tempname ); upstream->demo.tempname = NULL; Mem_ZoneFree( upstream->demo.filename ); upstream->demo.filename = NULL; return; } if( !silent ) Com_Printf( "Recording demo: %s\n", upstream->demo.filename ); upstream->demo.recording = qtrue; upstream->demo.localtime = 0; upstream->demo.basetime = upstream->demo.duration = 0; // don't start saving messages until a non-delta compressed message is received TV_Upstream_AddReliableCommand( upstream, "nodelta" ); // request non delta compressed frame from server upstream->demo.waiting = qtrue; // the rest of the demo file will be individual frames }