void FS_LoadBasePak() { Cmd::Args extrapaks(fs_extrapaks.Get()); for (const auto& x: extrapaks) { if (!FS_LoadPak(x.c_str())) Com_Error(errorParm_t::ERR_FATAL, "Could not load extra pak '%s'\n", x.c_str()); } if (!FS_LoadPak(fs_basepak.Get().c_str())) { Log::Notice("Could not load base pak '%s', falling back to default\n", fs_basepak.Get().c_str()); if (!FS_LoadPak(DEFAULT_BASE_PAK)) Com_Error(errorParm_t::ERR_FATAL, "Could not load default base pak '%s'", DEFAULT_BASE_PAK); } }
bool FS_LoadServerPaks(const char* paks, bool isDemo) { Cmd::Args args(paks); fs_missingPaks.clear(); for (auto& x: args) { std::string name, version; Util::optional<uint32_t> checksum; if (!FS::ParsePakName(x.data(), x.data() + x.size(), name, version, checksum)) { Com_Error(errorParm_t::ERR_DROP, "Invalid pak reference from server: %s", x.c_str()); } else if (!checksum) { if (isDemo || allowRemotePakDir.Get()) continue; Com_Error(errorParm_t::ERR_DROP, "The server is configured to load game data from a directory which makes it incompatible with remote clients."); } // Keep track of all missing paks const FS::PakInfo* pak = FS::FindPak(name, version, *checksum); if (!pak) fs_missingPaks.emplace_back(std::move(name), std::move(version), *checksum); else { try { FS::PakPath::LoadPakExplicit(*pak, *checksum); } catch (std::system_error&) { fs_missingPaks.emplace_back(std::move(name), std::move(version), *checksum); } } } // Load extra paks as well for demos if (isDemo) { Cmd::Args extrapaks(fs_extrapaks.Get()); for (auto& x: extrapaks) { if (!FS_LoadPak(x.c_str())) Com_Error(errorParm_t::ERR_FATAL, "Could not load extra pak '%s'\n", x.c_str()); } } return fs_missingPaks.empty(); }
/* ================ 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" ); }