/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. This is NOT called for map_restart ================ */ void SV_SpawnServer( char *server, qboolean killBots ) { int i; int checksum; qboolean isBot; char systemInfo[16384]; const char *p; // shut down the existing game if it is running SV_ShutdownGameProgs(); Com_Printf ("------ Server Initialization ------\n"); Com_Printf ("Server: %s\n",server); // if not running a dedicated server CL_MapLoading will connect the client to the server // also print some status stuff CL_MapLoading(); // make sure all the client stuff is unloaded CL_ShutdownAll(); // clear the whole hunk because we're (re)loading the server Hunk_Clear(); // clear collision map data CM_ClearMap(); // init client structures and svs.numSnapshotEntities if ( !Cvar_VariableValue("sv_running") ) { SV_Startup(); } else { // check for maxclients change if ( sv_maxclients->modified ) { SV_ChangeMaxClients(); } } // clear pak references FS_ClearPakReferences(0); // allocate the snapshot entities on the hunk svs.snapshotEntities = Hunk_Alloc( sizeof(entityState_t)*svs.numSnapshotEntities, h_high ); svs.nextSnapshotEntities = 0; // toggle the server bit so clients can detect that a // server has changed svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", "map_restart 0"); // Cvar_Set( "nextmap", va("map %s", server) ); // wipe the entire per-level structure SV_ClearServer(); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } // make sure we are not paused Cvar_Set("cl_paused", "0"); // get a new checksum feed and restart the file system srand(Com_Milliseconds()); sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds(); FS_Restart( sv.checksumFeed ); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; sv.restartedServerId = sv.serverId; // I suppose the init here is just to be safe sv.checksumFeedServerId = sv.serverId; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // don't allow a map_restart if game is modified sv_gametype->modified = qfalse; // run a few frames to allow everything to settle for ( i = 0 ; i < 3 ; i++ ) { VM_Call( gvm, GAME_RUN_FRAME, svs.time ); SV_BotFrame( svs.time ); svs.time += 100; } // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<sv_maxclients->integer ; i++) { // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; if ( svs.clients[i].netchan.remoteAddress.type == NA_BOT ) { if ( killBots ) { SV_DropClient( &svs.clients[i], "" ); continue; } isBot = qtrue; } else { isBot = qfalse; } // connect the client again denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) ); // firstTime = qfalse if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { if( !isBot ) { // when we get the next packet from a connected client, // the new gamestate will be sent svs.clients[i].state = CS_CONNECTED; } else { client_t *client; sharedEntity_t *ent; client = &svs.clients[i]; client->state = CS_ACTIVE; ent = SV_GentityNum( i ); ent->s.number = i; client->gentity = ent; client->deltaMessage = -1; client->nextSnapshotTime = svs.time; // generate a snapshot immediately VM_Call( gvm, GAME_CLIENT_BEGIN, i ); } } } } // run another frame to allow things to look at all the players VM_Call( gvm, GAME_RUN_FRAME, svs.time ); SV_BotFrame( svs.time ); svs.time += 100; if ( sv_pure->integer ) { // the server sends these to the clients so they will only // load pk3s also loaded at the server p = FS_LoadedPakChecksums(); Cvar_Set( "sv_paks", p ); if (strlen(p) == 0) { Com_Printf( "WARNING: sv_pure set but no PK3 files loaded\n" ); } p = FS_LoadedPakNames(); Cvar_Set( "sv_pakNames", p ); // if a dedicated pure server we need to touch the cgame because it could be in a // seperate pk3 file and the client will need to load the latest cgame.qvm if ( com_dedicated->integer ) { SV_TouchCGame(); } } else { Cvar_Set( "sv_paks", "" ); Cvar_Set( "sv_pakNames", "" ); } // the server sends these to the clients so they can figure // out which pk3s should be auto-downloaded p = FS_ReferencedPakChecksums(); Cvar_Set( "sv_referencedPaks", p ); p = FS_ReferencedPakNames(); Cvar_Set( "sv_referencedPakNames", p ); // save systeminfo and serverinfo strings Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SYSTEMINFO, systemInfo ); SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info SV_Heartbeat_f(); Hunk_SetMark(); Com_Printf ("-----------------------------------\n"); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. This is NOT called for map_restart ================ */ void SV_SpawnServer( char *server, qboolean killBots, ForceReload_e eForceReload ) { int i; int checksum; qboolean isBot; char systemInfo[16384]; const char *p; SV_StopAutoRecordDemos(); SV_SendMapChange(); re->RegisterMedia_LevelLoadBegin(server, eForceReload); // shut down the existing game if it is running SV_ShutdownGameProgs(); svs.gameStarted = qfalse; Com_Printf ("------ Server Initialization ------\n"); Com_Printf ("Server: %s\n",server); /* Ghoul2 Insert Start */ // de allocate the snapshot entities if (svs.snapshotEntities) { delete[] svs.snapshotEntities; svs.snapshotEntities = NULL; } /* Ghoul2 Insert End */ SV_SendMapChange(); // if not running a dedicated server CL_MapLoading will connect the client to the server // also print some status stuff CL_MapLoading(); #ifndef DEDICATED // make sure all the client stuff is unloaded CL_ShutdownAll( qfalse ); #endif CM_ClearMap(); // clear the whole hunk because we're (re)loading the server Hunk_Clear(); re->InitSkins(); re->InitShaders(qtrue); // init client structures and svs.numSnapshotEntities if ( !Cvar_VariableValue("sv_running") ) { SV_Startup(); } else { // check for maxclients change if ( sv_maxclients->modified ) { SV_ChangeMaxClients(); } } SV_SendMapChange(); /* Ghoul2 Insert Start */ // clear out those shaders, images and Models as long as this // isnt a dedicated server. /* if ( !com_dedicated->integer ) { #ifndef DEDICATED R_InitImages(); R_InitShaders(); R_ModelInit(); #endif } else */ if (com_dedicated->integer) { re->SVModelInit(); } SV_SendMapChange(); // clear pak references FS_ClearPakReferences(0); /* Ghoul2 Insert Start */ // allocate the snapshot entities on the hunk // svs.snapshotEntities = (struct entityState_s *)Hunk_Alloc( sizeof(entityState_t)*svs.numSnapshotEntities, h_high ); svs.nextSnapshotEntities = 0; // allocate the snapshot entities svs.snapshotEntities = new entityState_s[svs.numSnapshotEntities]; // we CAN afford to do this here, since we know the STL vectors in Ghoul2 are empty memset(svs.snapshotEntities, 0, sizeof(entityState_t)*svs.numSnapshotEntities); /* Ghoul2 Insert End */ // toggle the server bit so clients can detect that a // server has changed svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", "map_restart 0"); // Cvar_Set( "nextmap", va("map %s", server) ); for (i=0 ; i<sv_maxclients->integer ; i++) { // save when the server started for each client already connected if (svs.clients[i].state >= CS_CONNECTED) { svs.clients[i].oldServerTime = svs.time; } } // wipe the entire per-level structure SV_ClearServer(); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } //rww - RAGDOLL_BEGIN re->G2API_SetTime(sv.time,0); //rww - RAGDOLL_END // make sure we are not paused Cvar_Set("cl_paused", "0"); // get a new checksum feed and restart the file system srand(Com_Milliseconds()); sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds(); FS_Restart( sv.checksumFeed ); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); SV_SendMapChange(); // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; sv.restartedServerId = sv.serverId; // I suppose the init here is just to be safe Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); time( &sv.realMapTimeStarted ); sv.demosPruned = qfalse; // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // don't allow a map_restart if game is modified sv_gametype->modified = qfalse; // run a few frames to allow everything to settle for ( i = 0 ;i < 3 ; i++ ) { //rww - RAGDOLL_BEGIN re->G2API_SetTime(sv.time,0); //rww - RAGDOLL_END GVM_RunFrame( sv.time ); SV_BotFrame( sv.time ); sv.time += 100; svs.time += 100; } //rww - RAGDOLL_BEGIN re->G2API_SetTime(sv.time,0); //rww - RAGDOLL_END // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<sv_maxclients->integer ; i++) { // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; if ( svs.clients[i].netchan.remoteAddress.type == NA_BOT ) { if ( killBots ) { SV_DropClient( &svs.clients[i], "" ); continue; } isBot = qtrue; } else { isBot = qfalse; } // connect the client again denied = GVM_ClientConnect( i, qfalse, isBot ); // firstTime = qfalse if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { if( !isBot ) { // when we get the next packet from a connected client, // the new gamestate will be sent svs.clients[i].state = CS_CONNECTED; } else { client_t *client; sharedEntity_t *ent; client = &svs.clients[i]; client->state = CS_ACTIVE; ent = SV_GentityNum( i ); ent->s.number = i; client->gentity = ent; client->deltaMessage = -1; client->nextSnapshotTime = svs.time; // generate a snapshot immediately GVM_ClientBegin( i ); } } } } // run another frame to allow things to look at all the players GVM_RunFrame( sv.time ); SV_BotFrame( sv.time ); sv.time += 100; svs.time += 100; //rww - RAGDOLL_BEGIN re->G2API_SetTime(sv.time,0); //rww - RAGDOLL_END if ( sv_pure->integer ) { // the server sends these to the clients so they will only // load pk3s also loaded at the server p = FS_LoadedPakChecksums(); Cvar_Set( "sv_paks", p ); if (strlen(p) == 0) { Com_Printf( "WARNING: sv_pure set but no PK3 files loaded\n" ); } p = FS_LoadedPakNames(); Cvar_Set( "sv_pakNames", p ); // if a dedicated pure server we need to touch the cgame because it could be in a // seperate pk3 file and the client will need to load the latest cgame.qvm if ( com_dedicated->integer ) { SV_TouchCGame(); } } else { Cvar_Set( "sv_paks", "" ); Cvar_Set( "sv_pakNames", "" ); } // the server sends these to the clients so they can figure // out which pk3s should be auto-downloaded p = FS_ReferencedPakChecksums(); Cvar_Set( "sv_referencedPaks", p ); p = FS_ReferencedPakNames(); Cvar_Set( "sv_referencedPakNames", p ); // save systeminfo and serverinfo strings Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SYSTEMINFO, systemInfo ); SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info SV_Heartbeat_f(); Hunk_SetMark(); /* MrE: 2000-09-13: now called in CL_DownloadsComplete // don't call when running dedicated if ( !com_dedicated->integer ) { // note that this is called after setting the hunk mark with Hunk_SetMark CL_StartHunkUsers(); } */ for ( client_t *client = svs.clients; client - svs.clients < sv_maxclients->integer; client++) { // bots will not request gamestate, so it must be manually sent // cannot do this above where it says it will because mapname is not set at that time if ( client->netchan.remoteAddress.type == NA_BOT && client->demo.demorecording ) { SV_SendClientGameState( client ); } } SV_BeginAutoRecordDemos(); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. This is NOT called for map_restart ================ */ void SV_SpawnServer( char *server, qboolean killBots ) { int i; int checksum; qboolean isBot; const char *p; // shut down the existing game if it is running SV_ShutdownGameProgs(); Com_Printf( "------ Server Initialization ------\n" ); Com_Printf( "Server: %s\n", server ); // if not running a dedicated server CL_MapLoading will connect the client to the server // also print some status stuff CL_MapLoading(); // make sure all the client stuff is unloaded CL_ShutdownAll(); // clear the whole hunk because we're (re)loading the server Hunk_Clear(); // clear collision map data // (SA) NOTE: TODO: used in missionpack CM_ClearMap(); // wipe the entire per-level structure SV_ClearServer(); // MrE: main zone should be pretty much emtpy at this point // except for file system data and cached renderer data Z_LogHeap(); // allocate empty config strings for ( i = 0; i < MAX_CONFIGSTRINGS; i++ ) { sv.configstrings[ i ] = CopyString( "" ); sv.configstringsmodified[ i ] = qfalse; } // init client structures and svs.numSnapshotEntities if ( !Cvar_VariableValue( "sv_running" ) ) { SV_Startup(); } else { // check for maxclients change if ( sv_maxclients->modified ) { SV_ChangeMaxClients(); } #ifdef USE_HUB_SERVER // if sv_owHubHost was changed, resolve the address again if ( sv_owHubHost->modified ) { sv_owHubHost->modified = qfalse; SV_ResolveowHubHost(); } #endif } // clear pak references FS_ClearPakReferences( 0 ); // allocate the snapshot entities on the hunk svs.snapshotEntities = Hunk_Alloc( sizeof( entityState_t ) * svs.numSnapshotEntities, h_high ); svs.nextSnapshotEntities = 0; // toggle the server bit so clients can detect that a // server has changed svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", "map_restart 0" ); // Cvar_Set( "nextmap", va("map %s", server) ); // Ridah // DHM - Nerve :: We want to use the completion bar in multiplayer as well // Arnout: just always use it // if( !SV_GameIsSinglePlayer() ) { SV_SetExpectedHunkUsage( va( "maps/%s.bsp", server ) ); // } else { // just set it to a negative number,so the cgame knows not to draw the percent bar // Cvar_Set( "com_expectedhunkusage", "-1" ); // } // make sure we are not paused Cvar_Set( "cl_paused", "0" ); #if !defined( DO_LIGHT_DEDICATED ) // get a new checksum feed and restart the file system srand( Sys_Milliseconds() ); sv.checksumFeed = ( ( ( int ) rand() << 16 ) ^ rand() ) ^ Sys_Milliseconds(); // DO_LIGHT_DEDICATED // only comment out when you need a new pure checksum string and it's associated random feed //Com_DPrintf("SV_SpawnServer checksum feed: %p\n", sv.checksumFeed); #else // DO_LIGHT_DEDICATED implementation below // we are not able to randomize the checksum feed since the feed is used as key for pure_checksum computations // files.c 1776 : pack->pure_checksum = Com_BlockChecksumKey( fs_headerLongs, 4 * fs_numHeaderLongs, LittleLong(fs_checksumFeed) ); // we request a fake randomized feed, files.c knows the answer srand( Sys_Milliseconds() ); sv.checksumFeed = FS_RandChecksumFeed(); #endif FS_Restart( sv.checksumFeed ); CM_LoadMap( va( "maps/%s.bsp", server ), qfalse, &checksum ); // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va( "%i", checksum ) ); sv_newGameShlib = Cvar_Get( "sv_newGameShlib", "", CVAR_TEMP ); // serverid should be different each time sv.serverId = com_frameTime; sv.restartedServerId = sv.serverId; sv.checksumFeedServerId = sv.serverId; Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld(); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; Cvar_Set( "sv_serverRestarting", "1" ); // load and spawn all other entities SV_InitGameProgs(); // don't allow a map_restart if game is modified // Arnout: there isn't any check done against this, obsolete // sv_gametype->modified = qfalse; // 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 ); SV_BotFrame( svs.time ); svs.time += FRAMETIME; } // create a baseline for more efficient communications SV_CreateBaseline(); for ( i = 0; i < sv_maxclients->integer; i++ ) { // send the new gamestate to all connected clients if ( svs.clients[ i ].state >= CS_CONNECTED ) { char *denied; if ( svs.clients[ i ].netchan.remoteAddress.type == NA_BOT ) { if ( killBots || SV_GameIsSinglePlayer() || SV_GameIsCoop() ) { SV_DropClient( &svs.clients[ i ], "" ); continue; } isBot = qtrue; } else { isBot = qfalse; } // connect the client again denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) ); // firstTime = qfalse if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[ i ], denied ); } else { if ( !isBot ) { // when we get the next packet from a connected client, // the new gamestate will be sent svs.clients[ i ].state = CS_CONNECTED; } else { client_t *client; sharedEntity_t *ent; client = &svs.clients[ i ]; client->state = CS_ACTIVE; ent = SV_GentityNum( i ); ent->s.number = i; client->gentity = ent; client->deltaMessage = -1; client->nextSnapshotTime = svs.time; // generate a snapshot immediately VM_Call( gvm, GAME_CLIENT_BEGIN, i ); } } } } // run another frame to allow things to look at all the players VM_Call( gvm, GAME_RUN_FRAME, svs.time ); SV_BotFrame( svs.time ); svs.time += FRAMETIME; if ( sv_pure->integer ) { // the server sends these to the clients so they will only // load pk3s also loaded at the server p = FS_LoadedPakChecksums(); Cvar_Set( "sv_paks", p ); if ( strlen( p ) == 0 ) { Com_Printf( "WARNING: sv_pure set but no PK3 files loaded\n" ); } p = FS_LoadedPakNames(); Cvar_Set( "sv_pakNames", p ); // if a dedicated pure server we need to touch the cgame because it could be in a // seperate pk3 file and the client will need to load the latest cgame.qvm if ( com_dedicated->integer ) { SV_TouchCGame(); } } else { Cvar_Set( "sv_paks", "" ); Cvar_Set( "sv_pakNames", "" ); } // the server sends these to the clients so they can figure // out which pk3s should be auto-downloaded // NOTE: we consider the referencedPaks as 'required for operation' // we want the server to reference the mp_bin pk3 that the client is expected to load from SV_TouchCGameDLL(); p = FS_ReferencedPakChecksums(); Cvar_Set( "sv_referencedPaks", p ); p = FS_ReferencedPakNames(); Cvar_Set( "sv_referencedPakNames", p ); // save systeminfo and serverinfo strings cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString_Big( CVAR_SYSTEMINFO ) ); SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO | CVAR_SERVERINFO_NOUPDATE ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info SV_Heartbeat_f(); Hunk_SetMark(); SV_UpdateConfigStrings(); Cvar_Set( "sv_serverRestarting", "0" ); Com_Printf( "-----------------------------------\n" ); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. ================ */ void SV_SpawnServer( char *server, ForceReload_e eForceReload, qboolean bAllowScreenDissolve ) { int i; int checksum; // The following fixes for potential issues only work on Xbox #ifdef _XBOX extern qboolean stop_icarus; stop_icarus = qfalse; //Broken scripts may leave the player locked. I think that's always bad. extern qboolean player_locked; player_locked = qfalse; //If you quit while in Matrix Mode, this never gets cleared! extern qboolean MatrixMode; MatrixMode = qfalse; // Temporary code to turn on HDR effect for specific maps only if (!Q_stricmp(server, "t3_rift")) { Cvar_Set( "r_hdreffect", "1" ); } else { Cvar_Set( "r_hdreffect", "0" ); } #endif RE_RegisterMedia_LevelLoadBegin( server, eForceReload, bAllowScreenDissolve ); Cvar_SetValue( "cl_paused", 0 ); Cvar_Set( "timescale", "1" );//jic we were skipping // shut down the existing game if it is running SV_ShutdownGameProgs(qtrue); Com_Printf ("------ Server Initialization ------\n%s\n", com_version->string); Com_Printf ("Server: %s\n",server); #ifdef _XBOX // disable vsync during load for speed qglDisable(GL_VSYNC); #endif // don't let sound stutter and dump all stuff on the hunk CL_MapLoading(); if (!CM_SameMap(server)) { //rww - only clear if not loading the same map CM_ClearMap(); } #ifndef _XBOX else if (CM_HasTerrain()) { //always clear when going between maps with terrain CM_ClearMap(); } #endif // Miniheap never changes sizes, so I just put it really early in mem. G2VertSpaceServer->ResetHeap(); #ifdef _XBOX // Deletes all textures R_DeleteTextures(); #endif Hunk_Clear(); // Moved up from below to help reduce fragmentation if (svs.snapshotEntities) { Z_Free(svs.snapshotEntities); svs.snapshotEntities = NULL; } // wipe the entire per-level structure // Also moved up, trying to do all freeing before new allocs for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { if ( sv.configstrings[i] ) { Z_Free( sv.configstrings[i] ); sv.configstrings[i] = NULL; } } #ifdef _XBOX SV_ClearLastLevel(); #endif // Collect all the small allocations done by the cvar system // This frees, then allocates. Make it the last thing before other // allocations begin! Cvar_Defrag(); /* This is useful for debugging memory fragmentation. Please don't remove it. */ #ifdef _XBOX // We've over-freed the info array above, this puts it back into a working state Ghoul2InfoArray_Reset(); extern void Z_DumpMemMap_f(void); extern void Z_Details_f(void); extern void Z_TagPointers(memtag_t); Z_DumpMemMap_f(); // Z_TagPointers(TAG_ALL); Z_Details_f(); #endif // init client structures and svs.numSnapshotEntities // This is moved down quite a bit, but should be safe. And keeps // svs.clients right at the beginning of memory if ( !Cvar_VariableIntegerValue("sv_running") ) { SV_Startup(); } // clear out those shaders, images and Models R_InitImages(); R_InitShaders(); R_ModelInit(); // allocate the snapshot entities svs.snapshotEntities = (entityState_t *) Z_Malloc (sizeof(entityState_t)*svs.numSnapshotEntities, TAG_CLIENTS, qtrue ); Music_SetLevelName(server); // toggle the server bit so clients can detect that a // server has changed //!@ svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", va("map %s", server) ); memset (&sv, 0, sizeof(sv)); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } sv.time = 1000; G2API_SetTime(sv.time,G2T_SV_TIME); #ifdef _XBOX CL_StartHunkUsers(); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); RE_LoadWorldMap(va("maps/%s.bsp", server)); #else CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum, qfalse ); #endif // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // run a few frames to allow everything to settle for ( i = 0 ;i < 3 ; i++ ) { ge->RunFrame( sv.time ); sv.time += 100; G2API_SetTime(sv.time,G2T_SV_TIME); } #ifndef __NO_JK2 if(!Cvar_VariableIntegerValue("com_jk2")) #endif ge->ConnectNavs(sv_mapname->string, sv_mapChecksum->integer); // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<1 ; i++) { // clear all time counters, because we have reset sv.time svs.clients[i].lastPacketTime = 0; svs.clients[i].lastConnectTime = 0; svs.clients[i].nextSnapshotTime = 0; // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; // connect the client again denied = ge->ClientConnect( i, qfalse, eNO/*qfalse*/ ); // firstTime = qfalse, qbFromSavedGame if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { svs.clients[i].state = CS_CONNECTED; // when we get the next packet from a connected client, // the new gamestate will be sent } } } // run another frame to allow things to look at all connected clients ge->RunFrame( sv.time ); sv.time += 100; G2API_SetTime(sv.time,G2T_SV_TIME); // save systeminfo and serverinfo strings SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info svs.nextHeartbeatTime = -9999999; Hunk_SetMark(); Z_Validate(); Z_Validate(); Z_Validate(); Com_Printf ("-----------------------------------\n"); }
/** * @brief Change the server to a new map, taking all connected * clients along with it. * This is NOT called for map_restart */ void SV_SpawnServer(char *server) { int i; int checksum; qboolean isBot; const char *p; // broadcast a level change to all connected clients if (svs.clients && !com_errorEntered) { SV_FinalCommand("spawnserver", qfalse); } // shut down the existing game if it is running SV_ShutdownGameProgs(); Com_Printf("------ Server Initialization ------\n"); Com_Printf("Server: %s\n", server); // if not running a dedicated server CL_MapLoading will connect the client to the server // also print some status stuff CL_MapLoading(); // make sure all the client stuff is unloaded CL_ShutdownAll(); // clear the whole hunk because we're (re)loading the server Hunk_Clear(); // clear collision map data CM_ClearMap(); // wipe the entire per-level structure SV_ClearServer(); // main zone should be pretty much emtpy at this point // except for file system data and cached renderer data Z_LogHeap(); // allocate empty config strings for (i = 0 ; i < MAX_CONFIGSTRINGS ; i++) { sv.configstrings[i] = CopyString(""); sv.configstringsmodified[i] = qfalse; } // init client structures and svs.numSnapshotEntities if (!Cvar_VariableValue("sv_running")) { SV_Startup(); } else { // check for maxclients change if (sv_maxclients->modified) { // If we are playing/waiting to play/waiting to stop a demo, we use a specialized function that will move real clients slots (so that democlients will be put to their original slots they were affected at the time of the real game) if (sv.demoState == DS_WAITINGPLAYBACK || sv.demoState == DS_PLAYBACK || sv.demoState == DS_WAITINGSTOP) { SV_DemoChangeMaxClients(); } else { SV_ChangeMaxClients(); } } } // clear pak references FS_ClearPakReferences(0); // allocate the snapshot entities on the hunk svs.snapshotEntities = Hunk_Alloc(sizeof(entityState_t) * svs.numSnapshotEntities, h_high); svs.nextSnapshotEntities = 0; // toggle the server bit so clients can detect that a // server has changed svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set("nextmap", "map_restart 0"); SV_SetExpectedHunkUsage(va("maps/%s.bsp", server)); // make sure we are not paused Cvar_Set("cl_paused", "0"); // get a new checksum feed and restart the file system srand(Sys_Milliseconds()); sv.checksumFeed = (((int) rand() << 16) ^ rand()) ^ Sys_Milliseconds(); // only comment out when you need a new pure checksum string and it's associated random feed // Com_DPrintf("SV_SpawnServer checksum feed: %p\n", sv.checksumFeed); FS_Restart(sv.checksumFeed); CM_LoadMap(va("maps/%s.bsp", server), qfalse, &checksum); // set serverinfo visible name Cvar_Set("mapname", server); Cvar_Set("sv_mapChecksum", va("%i", checksum)); // serverid should be different each time sv.serverId = com_frameTime; sv.restartedServerId = sv.serverId; sv.checksumFeedServerId = sv.serverId; Cvar_Set("sv_serverid", va("%i", sv.serverId)); // clear physics interaction links SV_ClearWorld(); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // 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 SV_CreateBaseline(); for (i = 0 ; i < sv_maxclients->integer ; i++) { // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; if (svs.clients[i].netchan.remoteAddress.type == NA_BOT) { isBot = qtrue; } else { isBot = qfalse; } // connect the client again denied = VM_ExplicitArgPtr(gvm, VM_Call(gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot)); // firstTime = qfalse if (denied) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient(&svs.clients[i], denied); } else { if (!isBot) { // when we get the next packet from a connected client, // the new gamestate will be sent svs.clients[i].state = CS_CONNECTED; } else { client_t *client; sharedEntity_t *ent; client = &svs.clients[i]; client->state = CS_ACTIVE; ent = SV_GentityNum(i); ent->s.number = i; client->gentity = ent; client->deltaMessage = -1; client->nextSnapshotTime = svs.time; // generate a snapshot immediately VM_Call(gvm, GAME_CLIENT_BEGIN, i); } } } } // run another frame to allow things to look at all the players VM_Call(gvm, GAME_RUN_FRAME, svs.time); svs.time += FRAMETIME; if (sv_pure->integer) { // the server sends these to the clients so they will only // load pk3s also loaded at the server p = FS_LoadedPakChecksums(); Cvar_Set("sv_paks", p); if (strlen(p) == 0) { Com_Printf("WARNING: sv_pure set but no PK3 files loaded\n"); } p = FS_LoadedPakNames(); Cvar_Set("sv_pakNames", p); } else { Cvar_Set("sv_paks", ""); Cvar_Set("sv_pakNames", ""); } // the server sends these to the clients so they can figure // out which pk3s should be auto-downloaded // NOTE: we consider the referencedPaks as 'required for operation' // we want the server to reference the mod_bin pk3 that the client is expected to load from SV_TouchCGameDLL(); p = FS_ReferencedPakChecksums(); Cvar_Set("sv_referencedPaks", p); p = FS_ReferencedPakNames(); Cvar_Set("sv_referencedPakNames", p); // save systeminfo and serverinfo strings cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring(CS_SYSTEMINFO, Cvar_InfoString_Big(CVAR_SYSTEMINFO)); SV_SetConfigstring(CS_SERVERINFO, Cvar_InfoString(CVAR_SERVERINFO | CVAR_SERVERINFO_NOUPDATE)); cvar_modifiedFlags &= ~CVAR_SERVERINFO; SV_SetConfigstring(CS_WOLFINFO, Cvar_InfoString(CVAR_WOLFINFO)); cvar_modifiedFlags &= ~CVAR_WOLFINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info if (sv_advert->integer & SVA_MASTER) { SV_Heartbeat_f(); } else // let admin's know it's disabled { Com_Printf("Not sending heartbeats to master servers - disabled by sv_advert.\n"); } Hunk_SetMark(); SV_UpdateConfigStrings(); Com_Printf("-----------------------------------\n"); // start recording a demo if (sv_autoDemo->integer) { SV_DemoAutoDemoRecord(); } }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. This is NOT called for map_restart ================ */ void SV_SpawnServer( const char *server ) { int i; bool isBot; // shut down the existing game if it is running SV_ShutdownGameProgs(); PrintBanner( "Server Initialization" ) Com_Printf( "Server: %s\n", server ); // clear the whole hunk because we're (re)loading the server Hunk_Clear(); // if not running a dedicated server CL_MapLoading will connect the client to the server // also print some status stuff CL_MapLoading(); // clear collision map data CM_ClearMap(); // wipe the entire per-level structure SV_ClearServer(); // allocate empty config strings for ( i = 0; i < MAX_CONFIGSTRINGS; i++ ) { sv.configstrings[ i ] = CopyString( "" ); sv.configstringsmodified[ i ] = false; } // init client structures and svs.numSnapshotEntities if ( !Cvar_VariableValue( "sv_running" ) ) { SV_Startup(); } else { // check for maxclients change if ( sv_maxclients->modified ) { SV_ChangeMaxClients(); } } // allocate the snapshot entities on the hunk svs.snapshotEntities = ( entityState_t * ) Hunk_Alloc( sizeof( entityState_t ) * svs.numSnapshotEntities, h_high ); svs.nextSnapshotEntities = 0; // toggle the server bit so clients can detect that a // server has changed svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set sv_nextmap to the same map, but it may be overridden // by the game startup or another console command Cvar_Set( "sv_nextmap", "map_restart 0" ); // make sure we are not paused Cvar_Set( "cl_paused", "0" ); // get a new checksum feed and restart the file system srand( Sys_Milliseconds() ); sv.checksumFeed = ( ( rand() << 16 ) ^ rand() ) ^ Sys_Milliseconds(); FS::PakPath::ClearPaks(); FS_LoadBasePak(); if (!FS_LoadPak(va("map-%s", server))) Com_Error(ERR_DROP, "Could not load map pak\n"); CM_LoadMap(server); // set serverinfo visible name Cvar_Set( "mapname", server ); // serverid should be different each time sv.serverId = com_frameTime; sv.restartedServerId = sv.serverId; Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) ); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // run a few frames to allow everything to settle for ( i = 0; i < GAME_INIT_FRAMES; i++ ) { gvm.GameRunFrame( sv.time ); svs.time += FRAMETIME; sv.time += FRAMETIME; } // create a baseline for more efficient communications SV_CreateBaseline(); for ( i = 0; i < sv_maxclients->integer; i++ ) { // send the new gamestate to all connected clients if ( svs.clients[ i ].state >= CS_CONNECTED ) { bool denied; char reason[ MAX_STRING_CHARS ]; isBot = SV_IsBot(&svs.clients[i]); // connect the client again denied = gvm.GameClientConnect( reason, sizeof( reason ), i, false, isBot ); // firstTime = false if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[ i ], reason ); } else { if ( !isBot ) { // when we get the next packet from a connected client, // the new gamestate will be sent svs.clients[ i ].state = CS_CONNECTED; } else { client_t *client; sharedEntity_t *ent; client = &svs.clients[ i ]; client->state = CS_ACTIVE; ent = SV_GentityNum( i ); ent->s.number = i; client->gentity = ent; client->deltaMessage = -1; client->nextSnapshotTime = svs.time; // generate a snapshot immediately gvm.GameClientBegin( i ); } } } } // run another frame to allow things to look at all the players gvm.GameRunFrame( sv.time ); svs.time += FRAMETIME; sv.time += FRAMETIME; // the server sends these to the clients so they can figure // out which pk3s should be auto-downloaded Cvar_Set( "sv_paks", FS_LoadedPaks() ); // save systeminfo and serverinfo strings cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO, true ) ); SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO, false ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info SV_Heartbeat_f(); Hunk_SetMark(); SV_UpdateConfigStrings(); SV_AddOperatorCommands(); Com_Printf( "-----------------------------------\n" ); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. This is NOT called for map_restart ================ */ void SV_SpawnServer( char *server, qboolean killBots ) { int i; int checksum; char systemInfo[16384]; const char *p; // shut down the existing game if it is running SV_ShutdownGameProgs(); Com_Printf ("------ Server Initialization ------\n"); Com_Printf ("Server: %s\n",server); // if not running a dedicated server CL_MapLoading will connect the client to the server // also print some status stuff CL_MapLoading(); // make sure all the client stuff is unloaded CL_ShutdownAll(); // clear the whole hunk because we're (re)loading the server Hunk_Clear(); #ifndef DEDICATED // Restart renderer CL_StartHunkUsers( qtrue ); #endif // clear collision map data CM_ClearMap(); // init client structures and svs.numSnapshotEntities if ( !Cvar_VariableValue("sv_running") ) { SV_Startup(); } else { // check for maxclients or democlients change if ( sv_maxclients->modified || sv_democlients->modified ) { SV_ChangeMaxClients(); } } // clear pak references FS_ClearPakReferences(0); // allocate the snapshot entities on the hunk svs.snapshotEntities = Hunk_Alloc( sizeof(entityState_t)*svs.numSnapshotEntities, h_high ); svs.nextSnapshotEntities = 0; // toggle the server bit so clients can detect that a // server has changed svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; for (i=0 ; i<sv_maxclients->integer ; i++) { // save when the server started for each client already connected if (svs.clients[i].state >= CS_CONNECTED) { svs.clients[i].oldServerTime = sv.time; } } // wipe the entire per-level structure SV_ClearServer(); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } // make sure we are not paused Cvar_Set("cl_paused", "0"); // get a new checksum feed and restart the file system sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds(); FS_Restart( sv.checksumFeed ); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; sv.restartedServerId = sv.serverId; // I suppose the init here is just to be safe sv.checksumFeedServerId = sv.serverId; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // 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; } // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<sv_maxclients->integer ; i++) { // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; // connect the client again denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse ) ); // firstTime = qfalse if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { // when we get the next packet from a connected client, // the new gamestate will be sent svs.clients[i].state = CS_CONNECTED; } } } // 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; // if a dedicated server we need to touch the cgame because it could be in a // seperate pk3 file and the client will need to load the latest cgame.qvm if ( com_dedicated->integer ) { SV_TouchCGame(); } // the server sends these to the clients so they will only // load pk3s also loaded at the server Cvar_Set( "sv_paks", sv_pure->integer ? FS_LoadedPakChecksums() : "" ); Cvar_Set( "sv_pakNames", sv_pure->integer ? FS_LoadedPakNames() : "" ); // the server sends these to the clients so they can figure // out which pk3s should be auto-downloaded p = FS_ReferencedPakChecksums(); Cvar_Set( "sv_referencedPaks", p ); p = FS_ReferencedPakNames(); Cvar_Set( "sv_referencedPakNames", p ); // save systeminfo and serverinfo strings Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SYSTEMINFO, systemInfo ); SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info SV_Heartbeat_f(); Hunk_SetMark(); Com_Printf ("-----------------------------------\n"); // start recording a demo if ( sv_autoDemo->integer ) { qtime_t now; Com_RealTime( &now ); Cbuf_AddText( va( "demo_record %04d%02d%02d%02d%02d%02d-%s\n", 1900 + now.tm_year, 1 + now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec, server ) ); } }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. ================ */ void SV_SpawnServer( char *server, ForceReload_e eForceReload, qboolean bAllowScreenDissolve ) { int i; int checksum; RE_RegisterMedia_LevelLoadBegin( server, eForceReload, bAllowScreenDissolve ); Cvar_SetValue( "cl_paused", 0 ); Cvar_Set( "timescale", "1" );//jic we were skipping // shut down the existing game if it is running SV_ShutdownGameProgs(); Com_Printf ("------ Server Initialization ------\n%s\n", com_version->string); Com_Printf ("Server: %s\n",server); // init client structures and svs.numSnapshotEntities if ( !Cvar_VariableIntegerValue("sv_running") ) { SV_Startup(); } // don't let sound stutter and dump all stuff on the hunk CL_MapLoading(); Hunk_Clear(); // clear out those shaders, images and Models R_InitImages(); R_InitShaders(); R_ModelInit(); // create a heap for Ghoul2 to use for game side model vertex transforms used in collision detection if (!G2VertSpaceServer) { static const int MiniHeapSize=128 * 1024; // maxsize of ghoul2 miniheap G2VertSpaceServer = new CMiniHeap(MiniHeapSize); } if (svs.snapshotEntities) { Z_Free(svs.snapshotEntities); } // allocate the snapshot entities svs.snapshotEntities = (entityState_t *) Z_Malloc (sizeof(entityState_t)*svs.numSnapshotEntities, TAG_CLIENTS, qtrue ); Music_SetLevelName(server); // toggle the server bit so clients can detect that a // server has changed //!@ svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", va("map %s", server) ); // wipe the entire per-level structure for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { if ( sv.configstrings[i] ) { Z_Free( sv.configstrings[i] ); } } memset (&sv, 0, sizeof(sv)); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } sv.time = 1000; G2API_SetTime(sv.time,G2T_SV_TIME); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // run a few frames to allow everything to settle for ( i = 0 ;i < 3 ; i++ ) { ge->RunFrame( sv.time ); sv.time += 100; G2API_SetTime(sv.time,G2T_SV_TIME); } // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<1 ; i++) { // clear all time counters, because we have reset sv.time svs.clients[i].lastPacketTime = 0; svs.clients[i].lastConnectTime = 0; svs.clients[i].nextSnapshotTime = 0; // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; // connect the client again denied = ge->ClientConnect( i, qfalse, eNO/*qfalse*/ ); // firstTime = qfalse, qbFromSavedGame if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { svs.clients[i].state = CS_CONNECTED; // when we get the next packet from a connected client, // the new gamestate will be sent } } } // run another frame to allow things to look at all connected clients ge->RunFrame( sv.time ); sv.time += 100; G2API_SetTime(sv.time,G2T_SV_TIME); // save systeminfo and serverinfo strings SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info svs.nextHeartbeatTime = -9999999; Hunk_SetMark(); Com_Printf ("-----------------------------------\n"); }
void SV_SpawnServer( char *server, qboolean killBots, ForceReload_e eForceReload ) { int i; int checksum; qboolean isBot; char systemInfo[16384]; const char *p; Com_Printf("------ Server Initialization ------\n"); Com_Printf("Server: %s\n", server); SV_SendMapChange(); RE_RegisterMedia_LevelLoadBegin(server, eForceReload); // shut down the existing game if it is running SV_ShutdownGameProgs(); FixGhoul2InfoLeaks(false,true); /* Ghoul2 Insert Start */ // de allocate the snapshot entities if (svs.snapshotEntities) { delete[] svs.snapshotEntities; svs.snapshotEntities = NULL; } /* Ghoul2 Insert End */ SV_SendMapChange(); // if not running a dedicated server CL_MapLoading will connect the client to the server // also print some status stuff CL_MapLoading(); #ifndef DEDICATED // make sure all the client stuff is unloaded CL_ShutdownAll(); #endif CM_ClearMap(); // clear the whole hunk because we're (re)loading the server Hunk_Clear(); /* Ghoul2 Insert Start */ // clear out those shaders, images and Models as long as this // isnt a dedicated server. if ( !com_dedicated->integer ) { #ifndef DEDICATED R_InitImages(); R_InitShaders(); R_ModelInit(); #endif } else { R_SVModelInit(); #ifdef G2_COLLISION_ENABLED if (!G2VertSpaceServer) { G2VertSpaceServer = new CMiniHeap(G2_VERT_SPACE_SERVER_SIZE * 1024); } #endif } SV_SendMapChange(); // init client structures and svs.numSnapshotEntities if ( !Cvar_VariableValue("sv_running") ) { SV_Startup(); } else { // check for maxclients change if ( sv_maxclients->modified ) { SV_ChangeMaxClients(); } } SV_SendMapChange(); // clear pak references FS_ClearPakReferences(0); /* Ghoul2 Insert Start */ // allocate the snapshot entities on the hunk // svs.snapshotEntities = (struct entityState_s *)Hunk_Alloc( sizeof(entityState_t)*svs.numSnapshotEntities, h_high ); svs.nextSnapshotEntities = 0; // allocate the snapshot entities svs.snapshotEntities = new entityState_s[svs.numSnapshotEntities]; // we CAN afford to do this here, since we know the STL vectors in Ghoul2 are empty memset(svs.snapshotEntities, 0, sizeof(entityState_t)*svs.numSnapshotEntities); /* Ghoul2 Insert End */ // toggle the server bit so clients can detect that a // server has changed svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", "map_restart 0"); // Cvar_Set( "nextmap", va("map %s", server) ); // wipe the entire per-level structure SV_ClearServer(); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } // decide which serverversion to host mv_serverversion = Cvar_Get("mv_serverversion", "1.04", CVAR_ARCHIVE | CVAR_LATCH | CVAR_GLOBAL); if (FS_AllPath_Base_FileExists("assets5.pk3") && (!strcmp(mv_serverversion->string, "auto") || !strcmp(mv_serverversion->string, "1.04"))) { Com_Printf("serverversion set to 1.04\n"); MV_SetCurrentGameversion(VERSION_1_04); } else if (FS_AllPath_Base_FileExists("assets2.pk3") && (!strcmp(mv_serverversion->string, "auto") || !strcmp(mv_serverversion->string, "1.03"))) { Com_Printf("serverversion set to 1.03\n"); MV_SetCurrentGameversion(VERSION_1_03); } else { Com_Printf("serverversion set to 1.02\n"); MV_SetCurrentGameversion(VERSION_1_02); } Cvar_Set("protocol", va("%i", MV_GetCurrentProtocol())); // make sure we are not paused Cvar_Set("cl_paused", "0"); // get a new checksum feed and restart the file system srand(Com_Milliseconds()); sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds(); FS_PureServerSetReferencedPaks("", ""); FS_Restart( sv.checksumFeed ); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); SV_SendMapChange(); // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; sv.restartedServerId = sv.serverId; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // don't allow a map_restart if game is modified sv_gametype->modified = qfalse; // run a few frames to allow everything to settle for ( i = 0 ;i < 3 ; i++ ) { VM_Call( gvm, GAME_RUN_FRAME, svs.time ); SV_BotFrame( svs.time ); svs.time += 100; } // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<sv_maxclients->integer ; i++) { // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; if ( svs.clients[i].netchan.remoteAddress.type == NA_BOT ) { if ( killBots ) { SV_DropClient( &svs.clients[i], "" ); continue; } isBot = qtrue; } else { isBot = qfalse; } // connect the client again denied = (char *)VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) ); // firstTime = qfalse if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { if( !isBot ) { // when we get the next packet from a connected client, // the new gamestate will be sent svs.clients[i].state = CS_CONNECTED; } else { client_t *client; sharedEntity_t *ent; client = &svs.clients[i]; client->state = CS_ACTIVE; ent = SV_GentityNum( i ); ent->s.number = i; client->gentity = ent; client->deltaMessage = -1; client->nextSnapshotTime = svs.time; // generate a snapshot immediately VM_Call( gvm, GAME_CLIENT_BEGIN, i ); } } } } // run another frame to allow things to look at all the players VM_Call( gvm, GAME_RUN_FRAME, svs.time ); SV_BotFrame( svs.time ); svs.time += 100; if ( sv_pure->integer ) { // the server sends these to the clients so they will only // load pk3s also loaded at the server p = FS_LoadedPakChecksums(); Cvar_Set( "sv_paks", p ); if (strlen(p) == 0) { Com_Printf( "WARNING: sv_pure set but no PK3 files loaded\n" ); } p = FS_LoadedPakNames(); Cvar_Set( "sv_pakNames", p ); // if a dedicated pure server we need to touch the cgame because it could be in a // seperate pk3 file and the client will need to load the latest cgame.qvm if ( com_dedicated->integer ) { SV_TouchCGame(); } } else { Cvar_Set( "sv_paks", "" ); Cvar_Set( "sv_pakNames", "" ); } // the server sends these to the clients so they can figure // out which pk3s should be auto-downloaded p = FS_ReferencedPakChecksums(); Cvar_Set( "sv_referencedPaks", p ); p = FS_ReferencedPakNames(); Cvar_Set( "sv_referencedPakNames", p ); // save systeminfo and serverinfo strings Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SYSTEMINFO, systemInfo ); SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info SV_Heartbeat_f(); Hunk_SetMark(); Com_Printf ("-----------------------------------\n"); /* MrE: 2000-09-13: now called in CL_DownloadsComplete // don't call when running dedicated if ( !com_dedicated->integer ) { // note that this is called after setting the hunk mark with Hunk_SetMark CL_StartHunkUsers(); } */ // shutdown webserver if (mgsrv && ((mv_httpdownloads->latchedString && !atoi(mv_httpdownloads->latchedString)) || mv_httpserverport->latchedString)) { SV_MV_Websrv_Shutdown(); } // here because latched mv_httpdownloads = Cvar_Get("mv_httpdownloads", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH); mv_httpserverport = Cvar_Get("mv_httpserverport", "0", CVAR_ARCHIVE | CVAR_LATCH); // start webserver if (mv_httpdownloads->integer) { if (Q_stristr(mv_httpserverport->string, "http://")) { Com_Printf("HTTP Downloads: redirecting to %s\n", mv_httpserverport->string); } else if (!mgsrv) { const char *err = NULL; int port; mgsrv = mg_create_server(NULL, SV_MV_Websrv_Request_ExtThread); mg_set_option(mgsrv, "document_root", Cvar_Get("fs_basepath", "", 0)->string); if (mv_httpserverport->integer) { port = mv_httpserverport->integer; err = mg_set_option(mgsrv, "listening_port", va("%i", port)); } else { for (port = HTTPSRV_STDPORT; port <= HTTPSRV_STDPORT + 15; port++) { err = mg_set_option(mgsrv, "listening_port", va("%i", port)); if (!err) { break; } } } if (!err) { sv.http_port = port; Com_Printf("HTTP Downloads: webserver running on port %i...\n", port); } else { Com_Error(ERR_DROP, "HTTP Downloads: webserver startup failed: %s", err); } mg_start_thread(SV_MV_Websrv_Loop_ExtThread, mgsrv); } } }
static void SV_SpawnServer_after_FS_Restart( cb_context_t *context, int status ) { int i; int checksum; qboolean isBot; char systemInfo[16384]; const char *p; spawnserver_data_t *data; cb_context_t *after; char mapname[MAX_QPATH]; qboolean killBots; data = (spawnserver_data_t*)context->data; Q_strncpyz(mapname, data->mapname, MAX_QPATH); killBots = data->killBots; after = data->after; cb_free_context(context); CM_LoadMap( va("maps/%s.bsp", mapname), qfalse, &checksum ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; sv.restartedServerId = sv.serverId; // I suppose the init here is just to be safe sv.checksumFeedServerId = sv.serverId; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // don't allow a map_restart if game is modified sv_gametype->modified = qfalse; // run a few frames to allow everything to settle for (i = 0;i < 3; i++) { VM_Call (gvm, GAME_RUN_FRAME, sv.time); SV_BotFrame (sv.time); sv.time += 100; svs.time += 100; } // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<sv_maxclients->integer ; i++) { // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; if ( svs.clients[i].netchan.remoteAddress.type == NA_BOT ) { if ( killBots ) { SV_DropClient( &svs.clients[i], "" ); continue; } isBot = qtrue; } else { isBot = qfalse; } // connect the client again denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) ); // firstTime = qfalse if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { if( !isBot ) { // when we get the next packet from a connected client, // the new gamestate will be sent svs.clients[i].state = CS_CONNECTED; } else { client_t *client; sharedEntity_t *ent; client = &svs.clients[i]; client->state = CS_ACTIVE; ent = SV_GentityNum( i ); ent->s.number = i; client->gentity = ent; client->deltaMessage = -1; client->lastSnapshotTime = 0; // generate a snapshot immediately VM_Call( gvm, GAME_CLIENT_BEGIN, i ); } } } } // run another frame to allow things to look at all the players VM_Call (gvm, GAME_RUN_FRAME, sv.time); SV_BotFrame (sv.time); sv.time += 100; svs.time += 100; if ( sv_pure->integer ) { // the server sends these to the clients so they will only // load pk3s also loaded at the server p = FS_LoadedPakChecksums(); Cvar_Set( "sv_paks", p ); if (strlen(p) == 0) { Com_Printf( "WARNING: sv_pure set but no PK3 files loaded\n" ); } p = FS_LoadedPakNames(); Cvar_Set( "sv_pakNames", p ); // if a dedicated pure server we need to touch the cgame because it could be in a // seperate pk3 file and the client will need to load the latest cgame.qvm if ( com_dedicated->integer ) { SV_TouchCGame(); } } else { Cvar_Set( "sv_paks", "" ); Cvar_Set( "sv_pakNames", "" ); } // the server sends these to the clients so they can figure // out which pk3s should be auto-downloaded p = FS_ReferencedPakChecksums(); Cvar_Set( "sv_referencedPaks", p ); p = FS_ReferencedPakNames(); Cvar_Set( "sv_referencedPakNames", p ); // save systeminfo and serverinfo strings Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SYSTEMINFO, systemInfo ); SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info SV_Heartbeat_f(); Hunk_SetMark(); #ifndef DEDICATED if ( com_dedicated->integer ) { // restart renderer in order to show console for dedicated servers // launched through the regular binary CL_StartHunkUsers( qtrue ); } #endif Com_Printf ("-----------------------------------\n"); if (after) { cb_run(after, 0); } }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. ================ */ void SV_SpawnServer( const char *server, ForceReload_e eForceReload, qboolean bAllowScreenDissolve ) { int i; int checksum; re.RegisterMedia_LevelLoadBegin( server, eForceReload, bAllowScreenDissolve ); Cvar_SetValue( "cl_paused", 0 ); Cvar_Set( "timescale", "1" );//jic we were skipping // shut down the existing game if it is running SV_ShutdownGameProgs(qtrue); Com_Printf ("------ Server Initialization ------\n%s\n", com_version->string); Com_Printf ("Server: %s\n",server); // Moved up from below to help reduce fragmentation if (svs.snapshotEntities) { Z_Free(svs.snapshotEntities); svs.snapshotEntities = NULL; } // don't let sound stutter and dump all stuff on the hunk CL_MapLoading(); if (!CM_SameMap(server)) { //rww - only clear if not loading the same map CM_ClearMap(); } else if (CM_HasTerrain()) { //always clear when going between maps with terrain CM_ClearMap(); } // Miniheap never changes sizes, so I just put it really early in mem. G2VertSpaceServer->ResetHeap(); Hunk_Clear(); // wipe the entire per-level structure // Also moved up, trying to do all freeing before new allocs for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { if ( sv.configstrings[i] ) { Z_Free( sv.configstrings[i] ); sv.configstrings[i] = NULL; } } // Collect all the small allocations done by the cvar system // This frees, then allocates. Make it the last thing before other // allocations begin! Cvar_Defrag(); /* This is useful for debugging memory fragmentation. Please don't remove it. */ // init client structures and svs.numSnapshotEntities // This is moved down quite a bit, but should be safe. And keeps // svs.clients right at the beginning of memory if ( !Cvar_VariableIntegerValue("sv_running") ) { SV_Startup(); } // clear out those shaders, images and Models /*R_InitImages(); R_InitShaders(); R_ModelInit();*/ re.SVModelInit(); // allocate the snapshot entities svs.snapshotEntities = (entityState_t *) Z_Malloc (sizeof(entityState_t)*svs.numSnapshotEntities, TAG_CLIENTS, qtrue ); Music_SetLevelName(server); // toggle the server bit so clients can detect that a // server has changed //!@ svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", va("map %s", server) ); memset (&sv, 0, sizeof(sv)); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } sv.time = 1000; re.G2API_SetTime(sv.time,G2T_SV_TIME); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum, qfalse ); // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // run a few frames to allow everything to settle for ( i = 0 ;i < 3 ; i++ ) { ge->RunFrame( sv.time ); sv.time += 100; re.G2API_SetTime(sv.time,G2T_SV_TIME); } #ifndef JK2_MODE ge->ConnectNavs(sv_mapname->string, sv_mapChecksum->integer); #endif // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<1 ; i++) { // clear all time counters, because we have reset sv.time svs.clients[i].lastPacketTime = 0; svs.clients[i].lastConnectTime = 0; svs.clients[i].nextSnapshotTime = 0; // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; // connect the client again denied = ge->ClientConnect( i, qfalse, eNO/*qfalse*/ ); // firstTime = qfalse, qbFromSavedGame if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { svs.clients[i].state = CS_CONNECTED; // when we get the next packet from a connected client, // the new gamestate will be sent } } } // run another frame to allow things to look at all connected clients ge->RunFrame( sv.time ); sv.time += 100; re.G2API_SetTime(sv.time,G2T_SV_TIME); // save systeminfo and serverinfo strings SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; Hunk_SetMark(); Z_Validate(); Z_Validate(); Z_Validate(); Com_Printf ("-----------------------------------\n"); }
void SV_SpawnServer( char *server, qboolean killBots, ForceReload_e eForceReload ) { int i; int checksum; qboolean isBot; char systemInfo[16384]; const char *p; SV_SendMapChange(); RE_RegisterMedia_LevelLoadBegin(server, eForceReload); // shut down the existing game if it is running SV_ShutdownGameProgs(); Com_Printf ("------ Server Initialization ------\n"); Com_Printf ("Server: %s\n",server); /* Ghoul2 Insert Start */ // de allocate the snapshot entities if (svs.snapshotEntities) { delete[] svs.snapshotEntities; svs.snapshotEntities = NULL; } /* Ghoul2 Insert End */ SV_SendMapChange(); #ifdef _XBOX // disable vsync during load for speed qglDisable(GL_VSYNC); #endif // if not running a dedicated server CL_MapLoading will connect the client to the server // also print some status stuff CL_MapLoading(); #ifndef DEDICATED // make sure all the client stuff is unloaded CL_ShutdownAll(); #endif CM_ClearMap(); #ifdef _XBOX R_DeleteTextures(); #endif // clear the whole hunk because we're (re)loading the server Hunk_Clear(); #ifdef _XBOX SV_ClearLastLevel(); ClientManager::ActivateClient(0); #endif R_InitSkins(); R_InitShaders(qtrue); // This was in SV_DedicatedSpawn, but it gets in the way of my memory maps: if( com_dedicated->integer ) { // Textures have been blown away - need to kill font system so it // will re-register shaders when UI re-scans menu files below: extern void R_ShutdownFonts( void ); R_ShutdownFonts(); } ClientManager::ClientActiveRelocate( !com_dedicated->integer && !ClientManager::splitScreenMode ); #if defined(_XBOX) && !defined(FINAL_BUILD) //Useful for memory debugging. Please don't delete. Comment out if //necessary. extern void Z_DisplayLevelMemory(int, int, int); extern void Z_Details_f(void); extern void Z_TagPointers(memtag_t); Z_DisplayLevelMemory(0, 0, 0); Z_TagPointers( TAG_ALL ); Z_Details_f(); #endif // init client structures and svs.numSnapshotEntities if ( !Cvar_VariableValue("sv_running") ) { SV_Startup(); } else { // check for maxclients change if ( sv_maxclients->modified ) { SV_ChangeMaxClients(); } } // Do dedicated server-specific startup if ( com_dedicated->integer ) { SV_DedicatedSpawn(server); } // Xbox - Correct various problems with broken rules settings when people // change gametype in-game, etc... SV_FixBrokenRules(); SV_SendMapChange(); /* Ghoul2 Insert Start */ // clear out those shaders, images and Models as long as this // isnt a dedicated server. /* if ( !com_dedicated->integer ) { #ifndef DEDICATED R_InitImages(); R_InitShaders(); R_ModelInit(); #endif } else */ if (com_dedicated->integer) { R_SVModelInit(); } SV_SendMapChange(); // clear pak references FS_ClearPakReferences(0); /* Ghoul2 Insert Start */ // allocate the snapshot entities on the hunk // svs.snapshotEntities = (struct entityState_s *)Hunk_Alloc( sizeof(entityState_t)*svs.numSnapshotEntities, h_high ); svs.nextSnapshotEntities = 0; // allocate the snapshot entities svs.snapshotEntities = new entityState_s[svs.numSnapshotEntities]; // we CAN afford to do this here, since we know the STL vectors in Ghoul2 are empty memset(svs.snapshotEntities, 0, sizeof(entityState_t)*svs.numSnapshotEntities); /* Ghoul2 Insert End */ // toggle the server bit so clients can detect that a // server has changed svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", "map_restart 0"); // Cvar_Set( "nextmap", va("map %s", server) ); // wipe the entire per-level structure SV_ClearServer(); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } //rww - RAGDOLL_BEGIN G2API_SetTime(svs.time,0); //rww - RAGDOLL_END // make sure we are not paused Cvar_Set("cl_paused", "0"); // get a new checksum feed and restart the file system srand(Com_Milliseconds()); sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds(); FS_Restart( sv.checksumFeed ); #ifdef _XBOX CL_StartHunkUsers(); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); // RE_LoadWorldMap(va("maps/%s.bsp", server)); // Start up voice system if it isn't running yet. (ie, if we're on syslink) if( !logged_on ) g_Voice.Initialize(); #else CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); #endif SV_SendMapChange(); // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; sv.restartedServerId = sv.serverId; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // don't allow a map_restart if game is modified sv_gametype->modified = qfalse; // run a few frames to allow everything to settle for ( i = 0 ;i < 3 ; i++ ) { //rww - RAGDOLL_BEGIN G2API_SetTime(svs.time,0); //rww - RAGDOLL_END VM_Call( gvm, GAME_RUN_FRAME, svs.time ); SV_BotFrame( svs.time ); svs.time += 100; } //rww - RAGDOLL_BEGIN G2API_SetTime(svs.time,0); //rww - RAGDOLL_END // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<sv_maxclients->integer ; i++) { // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; if ( svs.clients[i].netchan.remoteAddress.type == NA_BOT ) { if ( killBots ) { SV_DropClient( &svs.clients[i], "" ); continue; } isBot = qtrue; } else { isBot = qfalse; } // connect the client again denied = (char *)VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) ); // firstTime = qfalse if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change // SV_DropClient( &svs.clients[i], denied ); SV_DropClient( &svs.clients[i], "@MENUS_LOST_CONNECTION" ); } else { if( !isBot ) { // when we get the next packet from a connected client, // the new gamestate will be sent svs.clients[i].state = CS_CONNECTED; } else { client_t *client; sharedEntity_t *ent; client = &svs.clients[i]; client->state = CS_ACTIVE; ent = SV_GentityNum( i ); ent->s.number = i; client->gentity = ent; client->deltaMessage = -1; client->nextSnapshotTime = svs.time; // generate a snapshot immediately VM_Call( gvm, GAME_CLIENT_BEGIN, i ); } } } } // run another frame to allow things to look at all the players VM_Call( gvm, GAME_RUN_FRAME, svs.time ); SV_BotFrame( svs.time ); svs.time += 100; //rww - RAGDOLL_BEGIN G2API_SetTime(svs.time,0); //rww - RAGDOLL_END if ( sv_pure->integer ) { // the server sends these to the clients so they will only // load pk3s also loaded at the server p = FS_LoadedPakChecksums(); Cvar_Set( "sv_paks", p ); if (strlen(p) == 0) { Com_Printf( "WARNING: sv_pure set but no PK3 files loaded\n" ); } p = FS_LoadedPakNames(); Cvar_Set( "sv_pakNames", p ); // if a dedicated pure server we need to touch the cgame because it could be in a // seperate pk3 file and the client will need to load the latest cgame.qvm if ( com_dedicated->integer ) { SV_TouchCGame(); } } else { Cvar_Set( "sv_paks", "" ); Cvar_Set( "sv_pakNames", "" ); } // the server sends these to the clients so they can figure // out which pk3s should be auto-downloaded p = FS_ReferencedPakChecksums(); Cvar_Set( "sv_referencedPaks", p ); p = FS_ReferencedPakNames(); Cvar_Set( "sv_referencedPakNames", p ); // save systeminfo and serverinfo strings Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SYSTEMINFO, systemInfo ); SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info SV_Heartbeat_f(); Hunk_SetMark(); /* MrE: 2000-09-13: now called in CL_DownloadsComplete // don't call when running dedicated if ( !com_dedicated->integer ) { // note that this is called after setting the hunk mark with Hunk_SetMark CL_StartHunkUsers(); } */ // Xbox - Dedicated servers need to do extra work here. Most of this is done in // cl_parse normally, but that never runs in this case: if ( com_dedicated->integer ) { // Normally, we start advertising when we get the first snapshot. // Do it now. This is also necessary so that Net_GetXNKID works below. XBL_MM_Advertise(); // We need to put ourselves into the playerlist. xbOnlineInfo.localIndex = DEDICATED_SERVER_INDEX; XBPlayerInfo *plyrInfo = &xbOnlineInfo.xbPlayerList[DEDICATED_SERVER_INDEX]; memset( plyrInfo, 0, sizeof(XBPlayerInfo) ); // We get the first refIndex plyrInfo->refIndex = svs.clientRefNum++; // Address information plyrInfo->xbAddr = *Net_GetXNADDR( NULL ); XNetXnAddrToInAddr( &plyrInfo->xbAddr, Net_GetXNKID(), &plyrInfo->inAddr ); // Gamertag and XUID Q_strncpyz( plyrInfo->name, Cvar_VariableString("name"), sizeof(plyrInfo->name) ); XONLINE_USER *pUser; if (logged_on && (pUser = &XBLLoggedOnUsers[ IN_GetMainController() ]) && (pUser->hr == S_OK)) plyrInfo->xuid = pUser->xuid; else plyrInfo->xuid.qwUserID = plyrInfo->refIndex; plyrInfo->isActive = true; // Start up the voice chat session g_Voice.JoinSession(); // And mark ourselves as playing, so that others can join our game: XBL_F_SetState( XONLINE_FRIENDSTATE_FLAG_PLAYING, true ); } }