/* ================ SV_Shutdown Called when each game quits, before Sys_Quit or Sys_Error ================ */ void SV_Shutdown( char *finalmsg ) { if ( !com_sv_running || !com_sv_running->integer ) { return; } // Com_Printf( "----- Server Shutdown -----\n" ); if ( svs.clients && !com_errorEntered ) { SV_FinalMessage( finalmsg ); } SV_RemoveOperatorCommands(); SV_MasterShutdown(); SV_ShutdownGameProgs(); svs.gameStarted = qfalse; /* Ghoul2 Insert Start */ // de allocate the snapshot entities if (svs.snapshotEntities) { delete[] svs.snapshotEntities; svs.snapshotEntities = NULL; } // free current level SV_ClearServer(); CM_ClearMap();//jfm: add a clear here since it's commented out in clearServer. This prevents crashing cmShaderTable on exit. // free server static data if ( svs.clients ) { Z_Free( svs.clients ); } Com_Memset( &svs, 0, sizeof( svs ) ); Cvar_Set( "sv_running", "0" ); Cvar_Set("ui_singlePlayerActive", "0"); // Com_Printf( "---------------------------\n" ); // disconnect any local clients if( sv_killserver->integer != 2 ) CL_Disconnect( qfalse ); }
/* ================ SV_Shutdown Called when each game quits, before Sys_Quit or Sys_Error ================ */ void SV_Shutdown( char* finalmsg ) { if ( !com_sv_running || !com_sv_running->integer ) { return; } Com_Printf( "----- Server Shutdown (%s) -----\n", finalmsg ); NET_LeaveMulticast6(); if ( svs.clients && !com_errorEntered ) { SV_FinalMessage( finalmsg ); } SV_RemoveOperatorCommands(); SV_MasterShutdown(); SV_ShutdownGameProgs(); SV_FreeMap(); // free current level SV_ClearServer(); // free server static data if ( svs.clients ) { int index; for ( index = 0; index < sv_maxclients->integer; index++ ) SV_FreeClient( &svs.clients[index] ); free( svs.clients ); } memset( &svs, 0, sizeof( svs ) ); Cvar_Set( "sv_running", "0" ); Cvar_Set( "ui_singlePlayerActive", "0" ); Com_Printf( "---------------------------\n" ); // disconnect any local clients if ( sv_killserver->integer != 2 ) CL_Disconnect( false ); }
/** * @brief Called when each game quits, before Sys_Quit or Sys_Error */ void SV_Shutdown(char *finalmsg) { // close attack log SV_CloseAttackLog(); if (!com_sv_running || !com_sv_running->integer) { return; } Com_Printf("----- Server Shutdown -----\n"); if (svs.clients && !com_errorEntered) { SV_FinalCommand(va("print \"%s\"", finalmsg), qtrue); } SV_RemoveOperatorCommands(); SV_MasterShutdown(); SV_ShutdownGameProgs(); // free current level SV_ClearServer(); // free server static data if (svs.clients) { //Z_Free( svs.clients ); free(svs.clients); // avoid trying to allocate large chunk on a fragmented zone } memset(&svs, 0, sizeof(svs)); svs.serverLoad = -1; Cvar_Set("sv_running", "0"); Com_Printf("---------------------------\n"); // disconnect any local clients CL_Disconnect(qfalse); #ifdef FEATURE_TRACKBASE TB_ServerStop(); #endif }
/* ================ SV_Shutdown Called when each game quits, before Sys_Quit or Sys_Error ================ */ void SV_Shutdown( char *finalmsg ) { if ( !com_sv_running || !com_sv_running->integer ) { return; } Com_Printf( "----- Server Shutdown -----\n" ); if ( svs.clients && !com_errorEntered ) { SV_FinalMessage( finalmsg ); } SV_RemoveOperatorCommands(); SV_MasterShutdown(); SV_ShutdownGameProgs(); /* Ghoul2 Insert Start */ // de allocate the snapshot entities if (svs.snapshotEntities) { delete[] svs.snapshotEntities; svs.snapshotEntities = NULL; } // free current level SV_ClearServer(); // free server static data if ( svs.clients ) { Z_Free( svs.clients ); } Com_Memset( &svs, 0, sizeof( svs ) ); Cvar_Set( "sv_running", "0" ); Cvar_Set("ui_singlePlayerActive", "0"); Com_Printf( "---------------------------\n" ); // disconnect any local clients CL_Disconnect( qfalse ); }
/* ================ SV_Shutdown Called when each game quits, before Sys_Quit or Sys_Error ================ */ void SV_Shutdown( char *finalmsg ) { if ( !com_sv_running || !com_sv_running->integer ) { return; } Com_Printf( "----- Server Shutdown (%s) -----\n", finalmsg ); // stop server-side demos (if any) Cbuf_ExecuteText(EXEC_NOW, "stopserverdemo all"); if ( svs.clients && !com_errorEntered ) { SV_FinalMessage( finalmsg ); } SV_RemoveOperatorCommands(); SV_MasterShutdown(); SV_ShutdownGameProgs(); // free current level SV_ClearServer(); #ifdef USE_SQLITE_BANS #ifdef DEDICATED SV_BansShutdown(); #endif #endif // free server static data if ( svs.clients ) { Z_Free( svs.clients ); } Com_Memset( &svs, 0, sizeof( svs ) ); Cvar_Set( "sv_running", "0" ); Cvar_Set("ui_singlePlayerActive", "0"); Com_Printf( "---------------------------\n" ); // disconnect any local clients if( sv_killserver->integer != 2 ) CL_Disconnect( qfalse ); }
/* ================ SV_Shutdown Called when each game quits, before Sys_Quit or Sys_Error ================ */ void SV_Shutdown( char *finalmsg ) { if ( !com_sv_running || !com_sv_running->integer ) { return; } Com_Printf( "----- Server Shutdown (%s) -----\n", finalmsg ); NET_LeaveMulticast6(); if ( svs.clients && !com_errorEntered ) { SV_FinalMessage( finalmsg ); } SV_MasterShutdown(); SV_ShutdownGameProgs(); // stop any demos if (sv.demoState == DS_RECORDING) SV_DemoStopRecord(); if (sv.demoState == DS_PLAYBACK) SV_DemoStopPlayback(); // free current level SV_ClearServer(); // free server static data if ( svs.clients ) { Z_Free( svs.clients ); } Com_Memset( &svs, 0, sizeof( svs ) ); Cvar_Set( "sv_running", "0" ); Cvar_Set("ui_singlePlayerActive", "0"); Com_Printf( "---------------------------\n" ); // disconnect any local clients if( sv_killserver->integer != 2 ) CL_Disconnect( qfalse ); }
/* ================ 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(); }
/** * @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( 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 ) ); } }
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 ); } }
/** * @brief Called when each game quits, before Sys_Quit or Sys_Error * @param[in] finalmsg */ void SV_Shutdown(const char *finalmsg) { #if defined(FEATURE_IRC_SERVER) && defined(DEDICATED) IRC_InitiateShutdown(); #endif // close attack log SV_CloseAttackLog(); if (!com_sv_running || !com_sv_running->integer) { return; } #if defined(FEATURE_IRC_SERVER) && defined(DEDICATED) Cmd_RemoveCommand("irc_connect"); Cmd_RemoveCommand("irc_disconnect"); Cmd_RemoveCommand("irc_say"); IRC_WaitShutdown(); #endif Com_Printf("----- Server Shutdown -----\n"); if (svs.clients && !com_errorEntered) { SV_FinalCommand(va("print \"%s\"", finalmsg), qtrue); } SV_RemoveOperatorCommands(); SV_MasterShutdown(); SV_ShutdownGameProgs(); SV_DemoStopAll(); // free current level SV_ClearServer(); // free server static data if (svs.clients) { int index; for (index = 0; index < sv_maxclients->integer; index++) { SV_Netchan_ClearQueue(&svs.clients[index]); } //Z_Free( svs.clients ); free(svs.clients); // avoid trying to allocate large chunk on a fragmented zone } memset(&svs, 0, sizeof(svs)); svs.serverLoad = -1; Cvar_Set("sv_running", "0"); Com_Printf("---------------------------\n"); // disconnect any local clients CL_Disconnect(qfalse); #ifdef FEATURE_TRACKER Tracker_ServerStop(); #endif }
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); } } }
void SV_SpawnServer( char *mapname, qboolean killBots, cb_context_t *after ) { int i; cb_context_t *context; spawnserver_data_t *data; // shut down the existing game if it is running SV_ShutdownGameProgs(); Com_Printf ("------ Server Initialization ------\n"); Com_Printf ("Server: %s\n",mapname); // 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(qfalse); // 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) ); 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"); // set serverinfo visible name Cvar_Set("mapname", mapname); // get a new checksum feed and restart the file system sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds(); // Setup callback context. context = cb_create_context( SV_SpawnServer_after_FS_Restart, spawnserver_data_t ); data = (spawnserver_data_t *)context->data; Q_strncpyz(data->mapname, mapname, MAX_QPATH); data->killBots = killBots; data->after = after; FS_Restart( sv.checksumFeed, context ); }
/* ================ 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. 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; 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_Shutdown Called when each game quits, before Sys_Quit or Sys_Error ================ */ void SV_Shutdown( char *finalmsg ) { if ( !com_sv_running || !com_sv_running->integer ) { return; } // Com_Printf( "----- Server Shutdown -----\n" ); //Replaced com_errorEntered check with a recursion check inside //SV_FinalMessage. How else can the clients know to disconnect? if ( svs.clients/* && !com_errorEntered*/ ) { SV_FinalMessage( finalmsg ); } SV_RemoveOperatorCommands(); #ifndef _XBOX // No master on Xbox SV_MasterShutdown(); #endif SV_ShutdownGameProgs(); /* Ghoul2 Insert Start */ // de allocate the snapshot entities if (svs.snapshotEntities) { delete[] svs.snapshotEntities; svs.snapshotEntities = NULL; } // free current level SV_ClearServer(); CM_ClearMap();//jfm: add a clear here since it's commented out in clearServer. This prevents crashing cmShaderTable on exit. // free server static data if ( svs.clients ) { Z_Free( svs.clients ); } Com_Memset( &svs, 0, sizeof( svs ) ); Cvar_Set( "sv_running", "0" ); Cvar_Set("ui_singlePlayerActive", "0"); // Com_Printf( "---------------------------\n" ); #ifdef _XBOX // If we were advertising on Live, remove the listing. This also unregisters // the server's key. SysLink keys are never unregistered, so we don't do anything // special here for them. if ( logged_on ) XBL_MM_Shutdown( true ); // Leave the voice session g_Voice.LeaveSession(); // Tear down voice now if we're on system link (Live keeps it active) if( !logged_on ) g_Voice.Shutdown(); if( logged_on ) { XBL_F_OnClientLeaveSession(); XBL_PL_OnClientLeaveSession(); } // Wipe our player list - this is important memset( &xbOnlineInfo, 0, sizeof(xbOnlineInfo) ); #endif // disconnect any local clients CL_Disconnect( qfalse ); }