/* ================ SV_MapRestart_f Completely restarts a level, but doesn't send a new gamestate to the clients. This allows fair starts with variable load times. ================ */ static void SV_MapRestart_f( void ) { int i; client_t *client; char *denied; qboolean isBot; int delay; // make sure we aren't restarting twice in the same frame if ( com_frameTime == sv.serverId ) { return; } // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( sv.restartTime ) { return; } if (Cmd_Argc() > 1 ) { delay = atoi( Cmd_Argv(1) ); } else { delay = 5; } if( delay && (!Cvar_VariableValue("g_doWarmup") || Cvar_VariableValue("g_gametype") == GT_TOURNAMENT) ) { sv.restartTime = svs.time + delay * 1000; SV_SetConfigstring( CS_WARMUP, va("%i", sv.restartTime) ); return; } // check for changes in variables that can't just be restarted // check for maxclients change if ( sv_maxclients->modified || sv_gametype->modified ) { char mapname[MAX_QPATH]; Com_Printf( "variable change -- restarting.\n" ); // restart the map the slow way Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) ); SV_SpawnServer( mapname, qfalse, eForceReload_NOTHING ); return; } // toggle the server bit so clients can detect that a // map_restart has happened svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // generate a new serverid sv.restartedServerId = sv.serverId; sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // reset all the vm data in place without changing memory allocation // note that we do NOT set sv.state = SS_LOADING, so configstrings that // had been changed from their default values will generate broadcast updates sv.state = SS_LOADING; sv.restarting = qtrue; SV_RestartGameProgs(); // run a few frames to allow everything to settle for ( i = 0 ;i < 3 ; i++ ) { VM_Call( gvm, GAME_RUN_FRAME, svs.time ); svs.time += 100; } sv.state = SS_GAME; sv.restarting = qfalse; // connect and begin all the clients for (i=0 ; i<sv_maxclients->integer ; i++) { client = &svs.clients[i]; // send the new gamestate to all connected clients if ( client->state < CS_CONNECTED) { continue; } if ( client->netchan.remoteAddress.type == NA_BOT ) { isBot = qtrue; } else { isBot = qfalse; } // add the map_restart command SV_AddServerCommand( client, "map_restart\n" ); // connect the client again, without the firstTime flag denied = (char *)VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) ); if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( client, denied ); Com_Printf( "SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i ); // bk010125 continue; } client->state = CS_ACTIVE; SV_ClientEnterWorld( client, &client->lastUsercmd ); } // run another frame to allow things to look at all the players VM_Call( gvm, GAME_RUN_FRAME, svs.time ); svs.time += 100; }
/* ================ SV_MapRestart_f Completely restarts a level, but doesn't send a new gamestate to the clients. This allows fair starts with variable load times. ================ */ static void SV_MapRestart_f( void ) { int i; client_t *client; char *denied; int delay; // make sure we aren't restarting twice in the same frame if ( com_frameTime == sv.serverId ) { return; } // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( sv.restartTime ) { return; } if (Cmd_Argc() > 1 ) { delay = atoi( Cmd_Argv(1) ); } else { delay = 5; } if( delay && !Cvar_VariableValue("g_doWarmup") ) { sv.restartTime = sv.time + delay * 1000; SV_SetConfigstring( CS_WARMUP, va("%i", sv.restartTime) ); return; } // check for changes in variables that can't just be restarted // check for maxclients change if ( sv_maxclients->modified ) { char mapname[MAX_QPATH]; Com_Printf( "variable change -- restarting.\n" ); // restart the map the slow way Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) ); SV_SpawnServer( mapname, qfalse ); return; } // toggle the server bit so clients can detect that a // map_restart has happened svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // generate a new serverid // TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // if a map_restart occurs while a client is changing maps, we need // to give them the correct time so that when they finish loading // they don't violate the backwards time check in cl_cgame.c for (i=0 ; i<sv_maxclients->integer ; i++) { if (svs.clients[i].state == CS_PRIMED) { svs.clients[i].oldServerTime = sv.restartTime; } } // reset all the vm data in place without changing memory allocation // note that we do NOT set sv.state = SS_LOADING, so configstrings that // had been changed from their default values will generate broadcast updates sv.state = SS_LOADING; sv.restarting = qtrue; SV_RestartGameProgs(); // run a few frames to allow everything to settle for (i = 0; i < 3; i++) { VM_Call (gvm, GAME_RUN_FRAME, sv.time); sv.time += 100; svs.time += 100; } sv.state = SS_GAME; sv.restarting = qfalse; // connect and begin all the clients for (i=0 ; i<sv_maxclients->integer ; i++) { client = &svs.clients[i]; // send the new gamestate to all connected clients if ( client->state < CS_CONNECTED) { continue; } // add the map_restart command SV_AddServerCommand( client, "map_restart\n" ); // connect the client again, without the firstTime flag denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse ) ); if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( client, denied ); Com_Printf( "SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i ); continue; } if(client->state == CS_ACTIVE) SV_ClientEnterWorld(client, &client->lastUsercmd); else { // If we don't reset client->lastUsercmd and are restarting during map load, // the client will hang because we'll use the last Usercmd from the previous map, // which is wrong obviously. SV_ClientEnterWorld(client, NULL); } } // run another frame to allow things to look at all the players VM_Call (gvm, GAME_RUN_FRAME, sv.time); sv.time += 100; svs.time += 100; }
/* ================ SV_MapRestart_f Completely restarts a level, but doesn't send a new gamestate to the clients. This allows fair starts with variable load times. ================ */ static void SV_MapRestart_f( void ) { int i; client_t *client; char *denied; qboolean isBot; int delay = 0; // make sure we aren't restarting twice in the same frame if ( com_frameTime == sv.serverId ) { return; } // make sure server is running if ( !com_sv_running->integer ) { Com_Printf(_( "Server is not running.\n" )); return; } // ydnar: allow multiple delayed server restarts [atvi bug 3813] //% if ( sv.restartTime ) { //% return; //% } if ( Cmd_Argc() > 1 ) { delay = atoi( Cmd_Argv( 1 ) ); } // check for changes in variables that can't just be restarted // check for maxclients change if ( sv_maxclients->modified ) { char mapname[ MAX_QPATH ]; Com_Printf(_( "sv_maxclients variable change — restarting.\n" )); // restart the map the slow way Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) ); SV_SpawnServer( mapname ); return; } // toggle the server bit so clients can detect that a // map_restart has happened svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // generate a new serverid // TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) ); // reset all the VM data in place without changing memory allocation // note that we do NOT set sv.state = SS_LOADING, so configstrings that // had been changed from their default values will generate broadcast updates sv.state = SS_LOADING; sv.restarting = qtrue; Cvar_Set( "sv_serverRestarting", "1" ); SV_RestartGameProgs(); // run a few frames to allow everything to settle for ( i = 0; i < GAME_INIT_FRAMES; i++ ) { VM_Call( gvm, GAME_RUN_FRAME, svs.time ); svs.time += FRAMETIME; } // create a baseline for more efficient communications // Gordon: meh, this won't work here as the client doesn't know it has happened // SV_CreateBaseline (); sv.state = SS_GAME; sv.restarting = qfalse; // connect and begin all the clients for ( i = 0; i < sv_maxclients->integer; i++ ) { client = &svs.clients[ i ]; // send the new gamestate to all connected clients if ( client->state < CS_CONNECTED ) { continue; } if ( client->netchan.remoteAddress.type == NA_BOT ) { isBot = qtrue; } else { isBot = qfalse; } // add the map_restart command SV_AddServerCommand( client, "map_restart\n" ); // connect the client again, without the firstTime flag denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) ); if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( client, denied ); if ( !isBot ) { Com_Printf( "SV_MapRestart_f(%d): dropped client %i: denied!\n", delay, i ); // bk010125 } continue; } client->state = CS_ACTIVE; SV_ClientEnterWorld( client, &client->lastUsercmd ); } // run another frame to allow things to look at all the players VM_Call( gvm, GAME_RUN_FRAME, svs.time ); svs.time += FRAMETIME; Cvar_Set( "sv_serverRestarting", "0" ); }
/* ================ SV_MapRestart_f Completely restarts a level, but doesn't send a new gamestate to the clients. This allows fair starts with variable load times. ================ */ static void SV_MapRestart_f( void ) { int i, j; client_t *client; player_t *player; char *denied; qboolean isBot; // make sure we aren't restarting twice in the same frame if ( com_frameTime == sv.serverId ) { return; } // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } // let game delay or pervent the restart or force full map reload sv.restartTime = VM_Call( gvm, GAME_MAP_RESTART, sv.time, sv.restartTime ); if( sv.restartTime > sv.time ) { return; } // check for changes in variables that can't just be restarted // check for maxclients change if ( sv_maxclients->modified || sv.restartTime < 0 ) { char mapname[MAX_QPATH]; Com_Printf( "variable change -- restarting.\n" ); // restart the map the slow way Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) ); SV_SpawnServer( mapname, qfalse ); return; } // toggle the server bit so clients can detect that a // map_restart has happened svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // generate a new serverid // TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // if a map_restart occurs while a client is changing maps, we need // to give them the correct time so that when they finish loading // they don't violate the backwards time check in cl_cgame.c for (i=0 ; i<sv_maxclients->integer ; i++) { if (svs.clients[i].state == CS_PRIMED) { svs.clients[i].oldServerTime = sv.restartTime; } } // reset all the vm data in place without changing memory allocation // note that we do NOT set sv.state = SS_LOADING, so configstrings that // had been changed from their default values will generate broadcast updates sv.state = SS_LOADING; sv.restarting = qtrue; SV_RestartGameProgs(); // run a few frames to allow everything to settle for (i = 0; i < 3; i++) { VM_Call (gvm, GAME_RUN_FRAME, sv.time); sv.time += 100; svs.time += 100; } sv.state = SS_GAME; sv.restarting = qfalse; // connect and begin all the clients for (i=0 ; i<sv_maxclients->integer ; i++) { client = &svs.clients[i]; // send the new gamestate to all connected clients if ( client->state < CS_CONNECTED) { continue; } if ( client->netchan.remoteAddress.type == NA_BOT ) { isBot = qtrue; } else { isBot = qfalse; } // add the map_restart command SV_AddServerCommand( client, -1, "map_restart\n" ); for ( j = 0; j < MAX_SPLITVIEW; j++ ) { player = client->localPlayers[j]; if ( !player ) continue; // setup entity before connecting SV_SetupPlayerEntity( player ); // connect the client again, without the firstTime flag denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_PLAYER_CONNECT, player - svs.players, qfalse, isBot, client - svs.clients, j ) ); player = client->localPlayers[j]; // may be NULL if game dropped player if ( denied ) { // this generally shouldn't happen, because the player // was connected before the level change if ( player != NULL ) { SV_DropPlayer( player, denied ); } Com_Printf( "SV_MapRestart_f: dropped client %i - denied!\n", i ); continue; } if(client->state == CS_ACTIVE) SV_PlayerEnterWorld( player, &player->lastUsercmd ); else { // If we don't reset player->lastUsercmd and are restarting during map load, // the client will hang because we'll use the last Usercmd from the previous map, // which is wrong obviously. SV_PlayerEnterWorld( player, NULL ); } } } // run another frame to allow things to look at all the players VM_Call (gvm, GAME_RUN_FRAME, sv.time); sv.time += 100; svs.time += 100; }
/* ================ SV_MapRestart_f Completely restarts a level, but doesn't send a new gamestate to the clients. This allows fair starts with variable load times. ================ */ static void SV_MapRestart_f( void ) { int i; client_t *client; char *denied; qboolean isBot; int delay = 0; gamestate_t new_gs, old_gs; // NERVE - SMF int worldspawnflags; // DHM - Nerve int nextgt; // DHM - Nerve sharedEntity_t *world; // make sure we aren't restarting twice in the same frame if ( com_frameTime == sv.serverId ) { return; } // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( sv.restartTime ) { return; } // DHM - Nerve :: Check for invalid gametype sv_gametype = Cvar_Get( "g_gametype", "5", CVAR_SERVERINFO | CVAR_LATCH ); nextgt = sv_gametype->integer; world = SV_GentityNum( ENTITYNUM_WORLD ); worldspawnflags = world->r.worldflags; if ( ( nextgt == GT_WOLF && ( worldspawnflags & 1 ) ) || ( nextgt == GT_WOLF_STOPWATCH && ( worldspawnflags & 2 ) ) || ( ( nextgt == GT_WOLF_CP || nextgt == GT_WOLF_CPH ) && ( worldspawnflags & 4 ) ) ) { if ( !( worldspawnflags & 1 ) ) { Cvar_Set( "g_gametype", "5" ); } else { Cvar_Set( "g_gametype", "7" ); } sv_gametype = Cvar_Get( "g_gametype", "5", CVAR_SERVERINFO | CVAR_LATCH ); } // dhm if ( Cmd_Argc() > 1 ) { delay = atoi( Cmd_Argv( 1 ) ); } if ( delay ) { sv.restartTime = svs.time + delay * 1000; SV_SetConfigstring( CS_WARMUP, va( "%i", sv.restartTime ) ); return; } // NERVE - SMF - read in gamestate or just default to GS_PLAYING old_gs = atoi( Cvar_VariableString( "gamestate" ) ); if ( Cmd_Argc() > 2 ) { new_gs = atoi( Cmd_Argv( 2 ) ); } else { new_gs = GS_PLAYING; } if ( !SV_TransitionGameState( new_gs, old_gs, delay ) ) { return; } // check for changes in variables that can't just be restarted // check for maxclients change if ( sv_maxclients->modified ) { char mapname[MAX_QPATH]; Com_Printf( "sv_maxclients variable change -- restarting.\n" ); // restart the map the slow way Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) ); SV_SpawnServer( mapname, qfalse ); return; } // toggle the server bit so clients can detect that a // map_restart has happened svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // generate a new serverid // TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) ); // reset all the vm data in place without changing memory allocation // note that we do NOT set sv.state = SS_LOADING, so configstrings that // had been changed from their default values will generate broadcast updates sv.state = SS_LOADING; sv.restarting = qtrue; Cvar_Set( "sv_serverRestarting", "1" ); SV_RestartGameProgs(); // run a few frames to allow everything to settle for ( i = 0 ; i < 3 ; i++ ) { VM_Call( gvm, GAME_RUN_FRAME, svs.time ); svs.time += 100; } sv.state = SS_GAME; sv.restarting = qfalse; // connect and begin all the clients for ( i = 0 ; i < sv_maxclients->integer ; i++ ) { client = &svs.clients[i]; // send the new gamestate to all connected clients if ( client->state < CS_CONNECTED ) { continue; } if ( client->netchan.remoteAddress.type == NA_BOT ) { isBot = qtrue; } else { isBot = qfalse; } // add the map_restart command SV_AddServerCommand( client, "map_restart\n" ); // connect the client again, without the firstTime flag denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) ); if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( client, denied ); Com_Printf( "SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i ); // bk010125 continue; } client->state = CS_ACTIVE; SV_ClientEnterWorld( client, &client->lastUsercmd ); } // run another frame to allow things to look at all the players VM_Call( gvm, GAME_RUN_FRAME, svs.time ); svs.time += 100; Cvar_Set( "sv_serverRestarting", "0" ); }
/* ================ SV_MapRestart_f Completely restarts a level, but doesn't send a new gamestate to the clients. This allows fair starts with variable load times. ================ */ static void SV_MapRestart_f(void) { int i, delay = 0; client_t *client; char *denied; qboolean isBot; gamestate_t new_gs, old_gs; // NERVE - SMF // make sure we aren't restarting twice in the same frame if(com_frameTime == sv.serverId) { return; } // make sure server is running if(!com_sv_running->integer) { Com_Printf("Server is not running.\n"); return; } if(Cmd_Argc() > 1) { delay = atoi(Cmd_Argv(1)); } if(delay) { sv.restartTime = svs.time + delay * 1000; SV_SetConfigstring(CS_WARMUP, va("%i", sv.restartTime)); return; } // NERVE - SMF - read in gamestate or just default to GS_PLAYING old_gs = (gamestate_t)atoi(Cvar_VariableString("gamestate")); if(SV_GameIsSinglePlayer() || SV_GameIsCoop()) { new_gs = GS_PLAYING; } else { if(Cmd_Argc() > 2) { new_gs = (gamestate_t)atoi(Cmd_Argv(2)); } else { new_gs = GS_PLAYING; } } if(!SV_TransitionGameState(new_gs, old_gs, delay)) { return; } // check for changes in variables that can't just be restarted // check for maxclients change if(sv_maxclients->modified) { char mapname[MAX_QPATH]; Com_Printf("sv_maxclients variable change -- restarting.\n"); // restart the map the slow way Q_strncpyz(mapname, Cvar_VariableString("mapname"), sizeof(mapname)); SV_SpawnServer(mapname, qfalse); return; } // Check for loading a saved game if(Cvar_VariableIntegerValue("savegame_loading")) { // open the current savegame, and find out what the time is, everything else we can ignore char savemap[MAX_QPATH], *cl_profileStr = Cvar_VariableString("cl_profile"); byte *buffer; int size, savegameTime; if(com_gameInfo.usesProfiles) { Com_sprintf(savemap, sizeof(savemap), "profiles/%s/save/current.sav", cl_profileStr); } else { Q_strncpyz(savemap, "save/current.sav", sizeof(savemap)); } size = FS_ReadFile(savemap, NULL); if(size < 0) { Com_Printf("Can't find savegame %s\n", savemap); return; } //buffer = Hunk_AllocateTempMemory(size); FS_ReadFile(savemap, (void **)&buffer); // the mapname is at the very start of the savegame file savegameTime = *(int *)(buffer + sizeof(int) + MAX_QPATH); if(savegameTime >= 0) { svs.time = savegameTime; } Hunk_FreeTempMemory(buffer); } // done. // toggle the server bit so clients can detect that a // map_restart has happened svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // generate a new serverid // TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart sv.serverId = com_frameTime; Cvar_Set("sv_serverid", va("%i", sv.serverId)); // reset all the vm data in place without changing memory allocation // note that we do NOT set sv.state = SS_LOADING, so configstrings that // had been changed from their default values will generate broadcast updates sv.state = SS_LOADING; sv.restarting = qtrue; Cvar_Set("sv_serverRestarting", "1"); SV_RestartGameProgs(); // run a few frames to allow everything to settle for(i = 0; i < GAME_INIT_FRAMES; i++) { VM_Call(gvm, GAME_RUN_FRAME, svs.time); svs.time += FRAMETIME; } // create a baseline for more efficient communications // Gordon: meh, this wont work here as the client doesn't know it has happened // SV_CreateBaseline (); sv.state = SS_GAME; sv.restarting = qfalse; // connect and begin all the clients for(i = 0; i < sv_maxclients->integer; i++) { client = &svs.clients[i]; // send the new gamestate to all connected clients if(client->state < CS_CONNECTED) { continue; } if(client->netchan.remoteAddress.type == NA_BOT) { if(SV_GameIsSinglePlayer() || SV_GameIsCoop()) { continue; // dont carry across bots in single player } isBot = qtrue; } else { isBot = qfalse; } // add the map_restart command SV_AddServerCommand(client, "map_restart\n"); // connect the client again, without the firstTime flag denied = (char*)VM_ExplicitArgPtr(gvm, VM_Call(gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot)); if(denied) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient(client, denied); if((!SV_GameIsSinglePlayer()) || (!isBot)) { Com_Printf("SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i); // bk010125 } continue; } client->state = CS_ACTIVE; SV_ClientEnterWorld(client, &client->lastUsercmd); } // run another frame to allow things to look at all the players VM_Call(gvm, GAME_RUN_FRAME, svs.time); svs.time += FRAMETIME; Cvar_Set("sv_serverRestarting", "0"); }
/* ================ SV_MapRestart_f Completely restarts a level, but doesn't send a new gamestate to the clients. This allows fair starts with variable load times. ================ */ static void SV_MapRestart_f(void) { int i; client_t *client; char *denied; qboolean isBot; int delay = 0; gamestate_t new_gs, old_gs; // make sure we aren't restarting twice in the same frame if (com_frameTime == sv.serverId) { return; } // make sure server is running if (!com_sv_running->integer) { Com_Printf("Server is not running.\n"); return; } if (Cmd_Argc() > 1) { delay = atoi(Cmd_Argv(1)); } if (delay) { sv.restartTime = svs.time + delay * 1000; SV_SetConfigstring(CS_WARMUP, va("%i", sv.restartTime)); return; } // read in gamestate or just default to GS_PLAYING old_gs = atoi(Cvar_VariableString("gamestate")); if (Cmd_Argc() > 2) { new_gs = atoi(Cmd_Argv(2)); } else { new_gs = GS_PLAYING; } if (!SV_TransitionGameState(new_gs, old_gs, delay)) { return; } // check for changes in variables that can't just be restarted // check for maxclients change if (sv_maxclients->modified) { char mapname[MAX_QPATH]; Com_Printf("sv_maxclients variable change -- restarting.\n"); // restart the map the slow way Q_strncpyz(mapname, Cvar_VariableString("mapname"), sizeof(mapname)); SV_SpawnServer(mapname); return; } SV_DemoStopAll(); // toggle the server bit so clients can detect that a // map_restart has happened svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // generate a new serverid // don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart sv.serverId = com_frameTime; Cvar_Set("sv_serverid", va("%i", sv.serverId)); // reset all the vm data in place without changing memory allocation // note that we do NOT set sv.state = SS_LOADING, so configstrings that // had been changed from their default values will generate broadcast updates sv.state = SS_LOADING; sv.restarting = qtrue; SV_RestartGameProgs(); // run a few frames to allow everything to settle for (i = 0; i < GAME_INIT_FRAMES; i++) { VM_Call(gvm, GAME_RUN_FRAME, svs.time); svs.time += FRAMETIME; } sv.state = SS_GAME; sv.restarting = qfalse; // connect and begin all the clients for (i = 0 ; i < sv_maxclients->integer ; i++) { client = &svs.clients[i]; // send the new gamestate to all connected clients if (client->state < CS_CONNECTED) { continue; } if (client->netchan.remoteAddress.type == NA_BOT) { isBot = qtrue; } else { isBot = qfalse; } // add the map_restart command SV_AddServerCommand(client, "map_restart\n"); // connect the client again, without the firstTime flag denied = VM_ExplicitArgPtr(gvm, VM_Call(gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot)); if (denied) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient(client, denied); if (!isBot) { Com_Printf("SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i); // bk010125 } continue; } // Player won't enter the world until the download is done if (client->download == 0) { if (client->state == CS_ACTIVE) { SV_ClientEnterWorld(client, &client->lastUsercmd); } else { // If we don't reset client->lastUsercmd and are restarting during map load, // the client will hang because we'll use the last Usercmd from the previous map, // which is wrong obviously. SV_ClientEnterWorld(client, NULL); } } } // run another frame to allow things to look at all the players VM_Call(gvm, GAME_RUN_FRAME, svs.time); svs.time += FRAMETIME; // start recording a demo if (sv_autoDemo->integer) { SV_DemoAutoDemoRecord(); } }