static void testMapLoading (void) { if (FS_CheckFile("maps/%s.bsp", mapName) != -1) { CM_LoadMap(mapName, qtrue, "", &mapData, &mapTiles); CM_LoadMap(mapName, qtrue, "", &mapData, &mapTiles); } else { UFO_CU_FAIL_MSG(va("Map resource '%s.bsp' for test is missing.", mapName)); } }
static void testMapLoading (void) { if (FS_CheckFile("maps/%s.bsp", mapName) != -1) { char entityString[MAX_TOKEN_CHARS]; CM_LoadMap(mapName, true, "", entityString, &mapData, &mapTiles); CM_LoadMap(mapName, true, "", entityString, &mapData, &mapTiles); } else { UFO_CU_FAIL_MSG(va("Map resource '%s.bsp' for test is missing.", mapName)); } }
void AAS_CalcReachAndClusters( struct quakefile_s *qf ) { float time; Log_Print( "loading collision map...\n" ); // if ( !qf->pakfile[0] ) { strcpy( qf->pakfile, qf->filename ); } //load the map CM_LoadMap( (char *) qf, qfalse, &( *aasworld ).bspchecksum ); //get a handle to the world model worldmodel = CM_InlineModel( 0 ); // 0 = world, 1 + are bmodels //initialize bot import structure AAS_InitBotImport(); //load the BSP entity string AAS_LoadBSPFile(); //init physics settings AAS_InitSettings(); //initialize AAS link heap AAS_InitAASLinkHeap(); //initialize the AAS linked entities for the new map AAS_InitAASLinkedEntities(); //reset all reachabilities and clusters ( *aasworld ).reachabilitysize = 0; ( *aasworld ).numclusters = 0; //set all view portals as cluster portals in case we re-calculate the reachabilities and clusters (with -reach) AAS_SetViewPortalsAsClusterPortals(); //calculate reachabilities AAS_InitReachability(); time = 0; while ( AAS_ContinueInitReachability( time ) ) time++; //calculate clusters AAS_InitClustering(); } //end of the function AAS_CalcReachAndClusters
static void CLQW_Model_NextDownload() { if ( clc.downloadNumber == 0 ) { common->Printf( "Checking models...\n" ); clc.downloadNumber = 1; } clc.downloadType = dl_model; for ( ; cl.qh_model_name[ clc.downloadNumber ][ 0 ] ; clc.downloadNumber++ ) { const char* s = cl.qh_model_name[ clc.downloadNumber ]; if ( s[ 0 ] == '*' ) { continue; // inline brush model } if ( !CL_CheckOrDownloadFile( s ) ) { return; // started a download } } CM_LoadMap( cl.qh_model_name[ 1 ], true, NULL ); cl.model_clip[ 1 ] = 0; R_LoadWorld( cl.qh_model_name[ 1 ] ); for ( int i = 2; i < MAX_MODELS_Q1; i++ ) { if ( !cl.qh_model_name[ i ][ 0 ] ) { break; } cl.model_draw[ i ] = CLQ1_RegisterModel( cl.qh_model_name[ i ] ); if ( cl.qh_model_name[ i ][ 0 ] == '*' ) { cl.model_clip[ i ] = CM_InlineModel( String::Atoi( cl.qh_model_name[ i ] + 1 ) ); } if ( !cl.model_draw[ i ] ) { common->Printf( "\nThe required model file '%s' could not be found or downloaded.\n\n", cl.qh_model_name[ i ] ); common->Printf( "You may need to download or purchase a %s client " "pack in order to play on this server.\n\n", fs_gamedir ); CL_Disconnect( true ); return; } } CLQW_CalcModelChecksum( "progs/player.mdl", "pmodel" ); CLQW_CalcModelChecksum( "progs/eyes.mdl", "emodel" ); // all done R_EndRegistration(); int CheckSum1; int CheckSum2; CM_MapChecksums( CheckSum1, CheckSum2 ); // done with modellist, request first of static signon messages CL_AddReliableCommand( va( "prespawn %i 0 %i", cl.servercount, CheckSum2 ) ); }
// Just adds default parameters that cgame doesn't need to know about void CLT3_CM_LoadMap( const char* mapname ) { if ( GGameType & ( GAME_WolfMP | GAME_ET ) && com_sv_running->integer ) { // TTimo // catch here when a local server is started to avoid outdated com_errorDiagnoseIP Cvar_Set( "com_errorDiagnoseIP", "" ); } int checksum; CM_LoadMap( mapname, true, &checksum ); }
void VM::VMInit() { // Allocate entities and clients shared memory region shmRegion = IPC::SharedMemory::Create(sizeof(gentity_t) * MAX_GENTITIES + sizeof(gclient_t) * MAX_CLIENTS); char* shmBase = reinterpret_cast<char*>(shmRegion.GetBase()); g_entities = reinterpret_cast<gentity_t*>(shmBase); g_clients = reinterpret_cast<gclient_t*>(shmBase + sizeof(gentity_t) * MAX_GENTITIES); // Load the map collision data std::string mapName = Cvar::GetValue("mapname"); CM_LoadMap(mapName); G_CM_ClearWorld(); }
/* ==================== CL_CM_LoadMap Just adds default parameters that cgame doesn't need to know about ==================== */ void CL_CM_LoadMap( const char *mapname ) { int checksum; // DHM - Nerve :: If we are not running the server, then set expected usage here if ( !com_sv_running->integer ) { CL_SetExpectedHunkUsage( mapname ); } else { // TTimo // catch here when a local server is started to avoid outdated com_errorDiagnoseIP Cvar_Set( "com_errorDiagnoseIP", "" ); } CM_LoadMap( mapname, qtrue, &checksum ); }
/** * @return @c true if are a compatible client and nothing else must be downloaded or no downloads are still running, * @c false if the start of the match must get a little bit postponed (running downloads). * @note throws ERR_DISCONNECT if we are not compatible to the server */ static bool CL_CanMultiplayerStart (void) { const int day = CL_GetConfigStringInteger(CS_LIGHTMAP); const char* serverVersion = CL_GetConfigString(CS_VERSION); /* checksum doesn't match with the one the server gave us via configstring */ if (!Q_streq(UFO_VERSION, serverVersion)) { Com_sprintf(popupText, sizeof(popupText), _("Local game version (%s) differs from the server version (%s)"), UFO_VERSION, serverVersion); UI_Popup(_("Error"), popupText); Com_Error(ERR_DISCONNECT, "Local game version (%s) differs from the server version (%s)", UFO_VERSION, serverVersion); /* amount of objects from script files doesn't match */ } else if (csi.numODs != CL_GetConfigStringInteger(CS_OBJECTAMOUNT)) { UI_Popup(_("Error"), _("Script files are not the same")); Com_Error(ERR_DISCONNECT, "Script files are not the same"); } /* activate the map loading screen for multiplayer, too */ SCR_BeginLoadingPlaque(); /* check download */ if (cls.downloadMaps) { /* confirm map */ if (CL_DownloadMap(CL_GetConfigString(CS_NAME))) return false; cls.downloadMaps = false; } /* map might still be downloading? */ if (CL_PendingHTTPDownloads()) return false; if (Com_GetScriptChecksum() != CL_GetConfigStringInteger(CS_UFOCHECKSUM)) Com_Printf("You are using modified ufo script files - might produce problems\n"); CM_LoadMap(CL_GetConfigString(CS_TILES), day, CL_GetConfigString(CS_POSITIONS), CL_GetConfigString(CS_ENTITYSTRING), cl.mapData, cl.mapTiles); #if 0 if (cl.mapData->mapChecksum != CL_GetConfigStringInteger(CS_MAPCHECKSUM)) { UI_Popup(_("Error"), _("Local map version differs from server")); Com_Error(ERR_DISCONNECT, "Local map version differs from server: %u != '%i'", cl.mapData->mapChecksum, CL_GetConfigStringInteger(CS_MAPCHECKSUM)); } #endif return true; }
// The server will send this command right // before allowing the client into the server static void CLQ2_Precache_f() { //Yet another hack to let old demos work //the old precache sequence if ( Cmd_Argc() < 2 ) { int map_checksum; // for detecting cheater maps CM_LoadMap( cl.q2_configstrings[ Q2CS_MODELS + 1 ], true, &map_checksum ); CLQ2_RegisterSounds(); CLQ2_PrepRefresh(); return; } clq2_precache_check = Q2CS_MODELS; clq2_precache_spawncount = String::Atoi( Cmd_Argv( 1 ) ); clq2_precache_model = 0; clq2_precache_model_skin = 0; CLQ2_RequestNextDownload(); }
/* * The server will send this command right * before allowing the client into the server */ void CL_Precache_f(void) { /* Yet another hack to let old demos work */ if (Cmd_Argc() < 2) { unsigned map_checksum; /* for detecting cheater maps */ CM_LoadMap(cl.configstrings[CS_MODELS + 1], true, &map_checksum); CL_RegisterSounds(); CL_PrepRefresh(); return; } precache_check = CS_MODELS; precache_spawncount = (int)strtol(Cmd_Argv(1), (char **)NULL, 10); precache_model = 0; precache_model_skin = 0; CL_RequestNextDownload(); }
/* ================ 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" ); }
/* ==================== CL_CM_LoadMap Just adds default parameters that cgame doesn't need to know about ==================== */ void CL_CM_LoadMap( const char *mapname ) { int checksum; CM_LoadMap( mapname, qtrue, &checksum ); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. ================ */ void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame) { int i; unsigned checksum; if (attractloop) Cvar_Set ("paused", "0"); Com_Printf ("------- Server Initialization -------\n"); Com_DPrintf ("SpawnServer: %s\n",server); if (sv.demofile) fclose (sv.demofile); svs.spawncount++; // any partially connected client will be // restarted sv.state = ss_dead; Com_SetServerState (sv.state); // wipe the entire per-level structure memset (&sv, 0, sizeof(sv)); svs.realtime = 0; sv.loadgame = loadgame; sv.attractloop = attractloop; // save name for levels that don't set message strcpy (sv.configstrings[CS_NAME], server); if (Cvar_VariableValue ("deathmatch")) { sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value); pm_airaccelerate = sv_airaccelerate->value; } else { strcpy(sv.configstrings[CS_AIRACCEL], "0"); pm_airaccelerate = 0; } SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf)); strcpy (sv.name, server); // leave slots at start for clients only for (i=0 ; i<maxclients->value ; i++) { // needs to reconnect if (svs.clients[i].state > cs_connected) svs.clients[i].state = cs_connected; svs.clients[i].lastframe = -1; } sv.time = 1000; strcpy (sv.name, server); strcpy (sv.configstrings[CS_NAME], server); if (serverstate != ss_game) { sv.models[1] = CM_LoadMap ("", false, &checksum); // no real map } else { Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]), "maps/%s.bsp", server); sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum); } Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]), "%i", checksum); // // clear physics interaction links // SV_ClearWorld (); for (i=1 ; i< CM_NumInlineModels() ; i++) { Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]), "*%i", i); sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]); } // // spawn the rest of the entities on the map // // precache and static commands can be issued during // map initialization sv.state = ss_loading; Com_SetServerState (sv.state); // load and spawn all other entities ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint ); // run two frames to allow everything to settle ge->RunFrame (); ge->RunFrame (); // all precaches are complete sv.state = serverstate; Com_SetServerState (sv.state); // create a baseline for more efficient communications SV_CreateBaseline (); // check for a savegame SV_CheckForSavegame (); // set serverinfo variable Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET); Com_Printf ("-------------------------------------\n"); }
/* * SV_SpawnServer * Change the server to a new map, taking all connected clients along with it. */ static void SV_SpawnServer( const char *server, qboolean devmap ) { unsigned checksum; int i; if( devmap ) Cvar_ForceSet( "sv_cheats", "1" ); Cvar_FixCheatVars(); Com_Printf( "------- Server Initialization -------\n" ); Com_Printf( "SpawnServer: %s\n", server ); svs.spawncount++; // any partially connected client will be restarted Com_SetServerState( ss_dead ); // wipe the entire per-level structure memset( &sv, 0, sizeof( sv ) ); SV_ResetClientFrameCounters(); svs.realtime = 0; svs.gametime = 0; SV_UpdateActivity(); Q_strncpyz( sv.mapname, server, sizeof( sv.mapname ) ); SV_SetServerConfigStrings(); sv.nextSnapTime = 1000; Q_snprintfz( sv.configstrings[CS_WORLDMODEL], sizeof( sv.configstrings[CS_WORLDMODEL] ), "maps/%s.bsp", server ); CM_LoadMap( svs.cms, sv.configstrings[CS_WORLDMODEL], qfalse, &checksum ); Q_snprintfz( sv.configstrings[CS_MAPCHECKSUM], sizeof( sv.configstrings[CS_MAPCHECKSUM] ), "%i", checksum ); // reserve the first modelIndexes for inline models for( i = 1; i < CM_NumInlineModels( svs.cms ); i++ ) Q_snprintfz( sv.configstrings[CS_MODELS + i], sizeof( sv.configstrings[CS_MODELS + i] ), "*%i", i ); // set serverinfo variable Cvar_FullSet( "mapname", sv.mapname, CVAR_SERVERINFO | CVAR_READONLY, qtrue ); // // spawn the rest of the entities on the map // // precache and static commands can be issued during // map initialization sv.state = ss_loading; Com_SetServerState( sv.state ); // set purelist SV_ReloadPureList(); // load and spawn all other entities ge->InitLevel( sv.mapname, CM_EntityString( svs.cms ), CM_EntityStringLen( svs.cms ), 0, svs.gametime, svs.realtime ); // run two frames to allow everything to settle ge->RunFrame( svc.snapFrameTime, svs.gametime ); ge->RunFrame( svc.snapFrameTime, svs.gametime ); SV_CreateBaseline(); // create a baseline for more efficient communications // all precaches are complete sv.state = ss_game; Com_SetServerState( sv.state ); Com_Printf( "-------------------------------------\n" ); }
/* ============================ CL_StartHunkUsers After the server has cleared the hunk, these will need to be restarted This is the only place that any of these functions are called from ============================ */ void CL_StartHunkUsers( void ) { if ( !com_cl_running->integer ) { return; } if ( !cls.rendererStarted ) { #ifdef _XBOX //if ((!com_sv_running->integer || com_errorEntered) && !vidRestartReloadMap) //{ // // free up some memory // extern void SV_ClearLastLevel(void); // SV_ClearLastLevel(); //} #endif cls.rendererStarted = qtrue; re.BeginRegistration( &cls.glconfig ); // load character sets // cls.charSetShader = re.RegisterShaderNoMip( "gfx/2d/bigchars" ); cls.charSetShader = re.RegisterShaderNoMip( "gfx/2d/charsgrid_med" ); cls.whiteShader = re.RegisterShader( "white" ); cls.consoleShader = re.RegisterShader( "console" ); g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2; kg.g_consoleField.widthInChars = g_console_field_width; #ifndef _IMMERSION //------- // The latest Immersion Force Feedback system initializes here, not through // win32 input system. Therefore, the window handle is valid :) //------- // now that the renderer has started up we know that the global hWnd is now valid, // so we can now go ahead and (re)setup the input stuff that needs hWnds for DI... // (especially Force feedback)... // static qboolean bOnceOnly = qfalse; // only do once, not every renderer re-start if (!bOnceOnly) { bOnceOnly = qtrue; extern void Sys_In_Restart_f( void ); Sys_In_Restart_f(); } #ifdef _XBOX if (vidRestartReloadMap) { int checksum; CM_LoadMap(va("maps/%s.bsp", cl_mapname->string), qfalse, &checksum); RE_LoadWorldMap(va("maps/%s.bsp", cl_mapname->string)); vidRestartReloadMap = qfalse; } #endif // _XBOX #endif // _IMMERSION } if ( !cls.soundStarted ) { cls.soundStarted = qtrue; S_Init(); } if ( !cls.soundRegistered ) { cls.soundRegistered = qtrue; S_BeginRegistration(); } #ifdef _IMMERSION if ( !cls.forceStarted ) { cls.forceStarted = qtrue; CL_InitFF(); } #endif // _IMMERSION #if !defined (_XBOX) //i guess xbox doesn't want the ui loaded all the time? //we require the ui to be loaded here or else it crashes trying to access the ui on command line map loads if ( !cls.uiStarted ) { cls.uiStarted = qtrue; CL_InitUI(); } #endif // if ( !cls.cgameStarted && cls.state > CA_CONNECTED && cls.state != CA_CINEMATIC ) { if ( !cls.cgameStarted && cls.state > CA_CONNECTED && (cls.state != CA_CINEMATIC && !CL_IsRunningInGameCinematic()) ) { cls.cgameStarted = qtrue; CL_InitCGame(); } }
static void CL_CM_LoadMap( const char *mapname, qboolean subBSP ) { if ( subBSP ) CM_LoadSubBSP( va( "maps/%s.bsp", mapname+1 ), qfalse ); else CM_LoadMap( mapname, qtrue, NULL ); }
/* ==================== CL_CM_LoadMap Just adds default parameters that cgame doesn't need to know about ==================== */ void CL_CM_LoadMap( const char *mapname, qboolean subBSP ) { int checksum; CM_LoadMap( mapname, qtrue, &checksum, subBSP ); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. This is only called from the SV_Map_f() function. ================ */ void SV_SpawnServer (char *mapname, qbool devmap, char* entityfile) { extern func_t ED_FindFunctionOffset (char *name); edict_t *ent; int i; extern cvar_t sv_loadentfiles, sv_loadentfiles_dir; char *entitystring; char oldmap[MAP_NAME_LEN]; extern qbool sv_allow_cheats; extern cvar_t sv_cheats, sv_paused, sv_bigcoords; #ifndef SERVERONLY extern void CL_ClearState (void); #endif // store old map name snprintf (oldmap, MAP_NAME_LEN, "%s", sv.mapname); Con_DPrintf ("SpawnServer: %s\n",mapname); #ifndef SERVERONLY // As client+server we do it here. // As serveronly we do it in NET_Init(). NET_InitServer(); #endif SV_SaveSpawnparms (); SV_LoadAccounts(); #ifdef USE_PR2 // remove bot clients for (i = 0; i < MAX_CLIENTS; i++) { if( sv_vm && svs.clients[i].isBot ) { svs.clients[i].old_frags = 0; svs.clients[i].edict->v.frags = 0.0; svs.clients[i].name[0] = 0; svs.clients[i].state = cs_free; Info_RemoveAll(&svs.clients[i]._userinfo_ctx_); Info_RemoveAll(&svs.clients[i]._userinfoshort_ctx_); SV_FullClientUpdate(&svs.clients[i], &sv.reliable_datagram); svs.clients[i].isBot = 0; } } #endif // Shutdown game. PR_GameShutDown(); PR_UnLoadProgs(); svs.spawncount++; // any partially connected client will be restarted #ifndef SERVERONLY com_serveractive = false; #endif sv.state = ss_dead; sv.paused = false; Cvar_SetROM(&sv_paused, "0"); Host_ClearMemory(); #ifdef FTE_PEXT_FLOATCOORDS if (sv_bigcoords.value) { msg_coordsize = 4; msg_anglesize = 2; } else { msg_coordsize = 2; msg_anglesize = 1; } #endif if ((int)coop.value) Cvar_Set (&deathmatch, "0"); current_skill = (int) (skill.value + 0.5); if (current_skill < 0) current_skill = 0; Cvar_Set (&skill, va("%d", current_skill)); if (current_skill > 3) current_skill = 3; if ((sv_cheats.value || devmap) && !sv_allow_cheats) { sv_allow_cheats = true; Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); } else if ((!sv_cheats.value && !devmap) && sv_allow_cheats) { sv_allow_cheats = false; Info_SetValueForStarKey (svs.info, "*cheats", "", MAX_SERVERINFO_STRING); } // wipe the entire per-level structure // NOTE: this also set sv.mvdrecording to false, so calling SV_MVD_Record() at end of function memset (&sv, 0, sizeof(sv)); sv.datagram.maxsize = sizeof(sv.datagram_buf); sv.datagram.data = sv.datagram_buf; sv.datagram.allowoverflow = true; sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); sv.reliable_datagram.data = sv.reliable_datagram_buf; sv.multicast.maxsize = sizeof(sv.multicast_buf); sv.multicast.data = sv.multicast_buf; sv.signon.maxsize = sizeof(sv.signon_buffers[0]); sv.signon.data = sv.signon_buffers[0]; sv.num_signon_buffers = 1; sv.time = 1.0; // load progs to get entity field count // which determines how big each edict is // and allocate edicts PR_LoadProgs (); #ifdef WITH_NQPROGS PR_InitPatchTables(); #endif PR_InitProg(); for (i = 0; i < MAX_EDICTS; i++) { ent = EDICT_NUM(i); ent->e = &sv.sv_edicts[i]; // assigning ->e field in each edict_t ent->e->entnum = i; ent->e->area.ed = ent; // yeah, pretty funny, but this help to find which edict_t own this area (link_t) } fofs_items2 = ED_FindFieldOffset ("items2"); // ZQ_ITEMS2 extension fofs_maxspeed = ED_FindFieldOffset ("maxspeed"); fofs_gravity = ED_FindFieldOffset ("gravity"); fofs_movement = ED_FindFieldOffset ("movement"); fofs_vw_index = ED_FindFieldOffset ("vw_index"); fofs_hideentity = ED_FindFieldOffset ("hideentity"); fofs_trackent = ED_FindFieldOffset ("trackent"); // find optional QC-exported functions. // we have it here, so we set it to NULL in case of PR2 progs. mod_SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect"); mod_SpectatorThink = ED_FindFunctionOffset ("SpectatorThink"); mod_SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect"); mod_ChatMessage = ED_FindFunctionOffset ("ChatMessage"); mod_UserInfo_Changed = ED_FindFunctionOffset ("UserInfo_Changed"); mod_ConsoleCmd = ED_FindFunctionOffset ("ConsoleCmd"); mod_UserCmd = ED_FindFunctionOffset ("UserCmd"); mod_localinfoChanged = ED_FindFunctionOffset ("localinfoChanged"); GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand"); GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic"); GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause"); // leave slots at start for clients only sv.num_edicts = MAX_CLIENTS+1; for (i=0 ; i<MAX_CLIENTS ; i++) { ent = EDICT_NUM(i+1); // restore client name. ent->v.netname = PR_SetString(svs.clients[i].name); // reserve edict. svs.clients[i].edict = ent; //ZOID - make sure we update frags right svs.clients[i].old_frags = 0; } // fill sv.mapname and sv.modelname with new map name strlcpy (sv.mapname, mapname, sizeof(sv.mapname)); snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname); #ifndef SERVERONLY // set cvar Cvar_ForceSet (&host_mapname, mapname); #endif if (!(sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2))) // true if bad map { Con_Printf ("Cant load map %s, falling back to %s\n", mapname, oldmap); // fill mapname, sv.mapname and sv.modelname with old map name strlcpy (sv.mapname, oldmap, sizeof(sv.mapname)); snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname); mapname = oldmap; // and re-load old map sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2); // this should never happen if (!sv.worldmodel) SV_Error ("CM_LoadMap: bad map"); } sv.map_checksum2 = Com_TranslateMapChecksum (sv.mapname, sv.map_checksum2); SV_ClearWorld (); // clear physics interaction links #ifdef USE_PR2 if ( sv_vm ) { sv.sound_precache[0] = ""; sv.model_precache[0] = ""; } else #endif { sv.sound_precache[0] = pr_strings; sv.model_precache[0] = pr_strings; } sv.model_precache[1] = sv.modelname; sv.models[1] = sv.worldmodel; for (i=1 ; i< CM_NumInlineModels() ; i++) { sv.model_precache[1+i] = localmodels[i]; sv.models[i+1] = CM_InlineModel (localmodels[i]); } //check player/eyes models for hacks sv.model_player_checksum = SV_CheckModel("progs/player.mdl"); sv.model_newplayer_checksum = SV_CheckModel("progs/newplayer.mdl"); sv.eyes_player_checksum = SV_CheckModel("progs/eyes.mdl"); // // spawn the rest of the entities on the map // // precache and static commands can be issued during // map initialization sv.state = ss_loading; #ifndef SERVERONLY com_serveractive = true; #endif ent = EDICT_NUM(0); ent->e->free = false; ent->v.model = PR_SetString(sv.modelname); ent->v.modelindex = 1; // world model ent->v.solid = SOLID_BSP; ent->v.movetype = MOVETYPE_PUSH; // information about the server ent->v.netname = PR_SetString(VersionStringFull()); ent->v.targetname = PR_SetString(SERVER_NAME); ent->v.impulse = VERSION_NUM; ent->v.items = pr_numbuiltins - 1; PR_GLOBAL(mapname) = PR_SetString(sv.mapname); // serverflags are for cross level information (sigils) PR_GLOBAL(serverflags) = svs.serverflags; if (pr_nqprogs) { pr_globals[35] = deathmatch.value; pr_globals[36] = coop.value; pr_globals[37] = teamplay.value; NQP_Reset (); } if (pr_nqprogs) { // register the cvars that NetQuake provides for mod use const char **var, *nqcvars[] = {"gamecfg", "scratch1", "scratch2", "scratch3", "scratch4", "saved1", "saved2", "saved3", "saved4", "savedgamecfg", "temp1", NULL}; for (var = nqcvars; *var; var++) Cvar_Create((char *)/*stupid const warning*/ *var, "0", 0); } // run the frame start qc function to let progs check cvars if (!pr_nqprogs) SV_ProgStartFrame (); // ********* External Entity support (.ent file(s) in gamedir/maps) pinched from ZQuake ********* // load and spawn all other entities entitystring = NULL; if ((int)sv_loadentfiles.value) { char ent_path[1024] = {0}; if (!entityfile || !entityfile[0]) entityfile = sv.mapname; // first try maps/sv_loadentfiles_dir/ if (sv_loadentfiles_dir.string[0]) { snprintf(ent_path, sizeof(ent_path), "maps/%s/%s.ent", sv_loadentfiles_dir.string, entityfile); entitystring = (char *) FS_LoadHunkFile(ent_path, NULL); } // try maps/ if not loaded yet. if (!entitystring) { snprintf(ent_path, sizeof(ent_path), "maps/%s.ent", entityfile); entitystring = (char *) FS_LoadHunkFile(ent_path, NULL); } if (entitystring) { Con_DPrintf ("Using entfile %s\n", ent_path); } } if (!entitystring) { entitystring = CM_EntityString(); } PR_LoadEnts(entitystring); // ********* End of External Entity support code ********* // look up some model indexes for specialized message compression SV_FindModelNumbers (); // all spawning is completed, any further precache statements // or prog writes to the signon message are errors sv.state = ss_active; // run two frames to allow everything to settle SV_Physics (); sv.time += 0.1; SV_Physics (); sv.time += 0.1; sv.old_time = sv.time; // save movement vars SV_SetMoveVars(); // create a baseline for more efficient communications SV_CreateBaseline (); sv.signon_buffer_size[sv.num_signon_buffers-1] = sv.signon.cursize; Info_SetValueForKey (svs.info, "map", sv.mapname, MAX_SERVERINFO_STRING); // calltimeofday. { extern void PF_calltimeofday (void); pr_global_struct->time = sv.time; pr_global_struct->self = 0; PF_calltimeofday(); } Con_DPrintf ("Server spawned.\n"); // we change map - clear whole demo struct and sent initial state to all dest if any (for QTV only I thought) SV_MVD_Record(NULL, true); #ifndef SERVERONLY CL_ClearState (); #endif }
/* ================ 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"); }
/* ================== NQD_ParseServerData ================== */ static void NQD_ParseServerData (void) { char *str; int i; int nummodels, numsounds; char mapname[MAX_QPATH]; int cs2; qbool gpl_map; #ifdef GLQUAKE extern qbool r_gpl_map; #endif Com_DPrintf ("Serverdata packet received.\n"); // // wipe the client_state_t struct // CL_ClearState (); // parse protocol version number i = MSG_ReadLong (); if (i != NQ_PROTOCOL_VERSION) Host_Error ("Server returned version %i, not %i", i, NQ_PROTOCOL_VERSION); // parse maxclients nq_maxclients = MSG_ReadByte (); if (nq_maxclients < 1 || nq_maxclients > NQ_MAX_CLIENTS) Host_Error ("Bad maxclients (%u) from server", nq_maxclients); // parse gametype cl.gametype = MSG_ReadByte() ? GAME_DEATHMATCH : GAME_COOP; // parse signon message str = MSG_ReadString (); strlcpy (cl.levelname, str, sizeof(cl.levelname)); // separate the printfs so the server message can have a color Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); Com_Printf ("%c%s\n", 2, str); // // first we go through and touch all of the precache data that still // happens to be in the cache, so precaching something else doesn't // needlessly purge it // // precache models for (nummodels=1 ; ; nummodels++) { str = MSG_ReadString (); if (!str[0]) break; if (nummodels == MAX_MODELS) Host_Error ("Server sent too many model precaches"); strlcpy (cl.model_name[nummodels], str, sizeof(cl.model_name[0])); Mod_TouchModel (str); } // precache sounds for (numsounds=1 ; ; numsounds++) { str = MSG_ReadString (); if (!str[0]) break; if (numsounds == MAX_SOUNDS) Host_Error ("Server sent too many sound precaches"); strlcpy (cl.sound_name[numsounds], str, sizeof(cl.sound_name[0])); S_TouchSound (str); } // // now we try to load everything else until a cache allocation fails // cl.clipmodels[1] = CM_LoadMap (cl.model_name[1], true, NULL, &cl.map_checksum2); COM_StripExtension (COM_SkipPath(cl.model_name[1]), mapname); cs2 = Com_TranslateMapChecksum (mapname, cl.map_checksum2); gpl_map = (cl.map_checksum2 != cs2); cl.map_checksum2 = cs2; #ifdef GLQUAKE r_gpl_map = gpl_map; #endif for (i = 1; i < nummodels; i++) { cl.model_precache[i] = Mod_ForName (cl.model_name[i], false, i == 1); if (cl.model_precache[i] == NULL) Host_Error ("Model %s not found", cl.model_name[i]); if (cl.model_name[i][0] == '*') cl.clipmodels[i] = CM_InlineModel(cl.model_name[i]); } for (i=1 ; i<numsounds ; i++) { cl.sound_precache[i] = S_PrecacheSound (cl.sound_name[i]); } // local state if (!cl.model_precache[1]) Host_Error ("NQD_ParseServerData: NULL worldmodel"); COM_StripExtension (COM_SkipPath (cl.model_name[1]), mapname); Cvar_ForceSet (&host_mapname, mapname); CL_ClearParticles (); CL_FindModelNumbers (); R_NewMap (cl.model_precache[1]); TP_NewMap (); Hunk_Check (); // make sure nothing is hurt nq_signon = 0; nq_num_entities = 0; nq_drawpings = false; // unless we have the ProQuake extension cl.servertime_works = true; cl.allow_fbskins = true; r_refdef2.allow_cheats = true; // why not cls.state = ca_onserver; }
/* ================ 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"); }
/* ================ 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"); }
/* ================ 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 CL_RequestNextDownload (void) { unsigned map_checksum; /* for detecting cheater maps */ char fn[MAX_OSPATH]; dmdl_t *pheader; if (cls.state != ca_connected) return; if (!allow_download->value && precache_check < ENV_CNT) precache_check = ENV_CNT; if (precache_check == CS_MODELS) { precache_check = CS_MODELS+2; if (allow_download_maps->value) if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1])) return; /* started a download */ } if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) { if (allow_download_models->value) { while (precache_check < CS_MODELS+MAX_MODELS && cl.configstrings[precache_check][0]) { if (cl.configstrings[precache_check][0] == '*' || cl.configstrings[precache_check][0] == '#') { precache_check++; continue; } if (precache_model_skin == 0) { if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) { precache_model_skin = 1; return; /* started a download */ } precache_model_skin = 1; } /* checking for skins in the model */ if (!precache_model) { FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model); if (!precache_model) { precache_model_skin = 0; precache_check++; continue; /* couldn't load it */ } if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) { /* not an alias model */ FS_FreeFile(precache_model); precache_model = 0; precache_model_skin = 0; precache_check++; continue; } pheader = (dmdl_t *)precache_model; if (LittleLong (pheader->version) != ALIAS_VERSION) { precache_check++; precache_model_skin = 0; continue; /* couldn't load it */ } } pheader = (dmdl_t *)precache_model; while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) { if (!CL_CheckOrDownloadFile((char *)precache_model + LittleLong(pheader->ofs_skins) + (precache_model_skin - 1)*MAX_SKINNAME)) { precache_model_skin++; return; /* started a download */ } precache_model_skin++; } if (precache_model) { FS_FreeFile(precache_model); precache_model = 0; } precache_model_skin = 0; precache_check++; } } precache_check = CS_SOUNDS; } if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS) { if (allow_download_sounds->value) { if (precache_check == CS_SOUNDS) precache_check++; while (precache_check < CS_SOUNDS+MAX_SOUNDS && cl.configstrings[precache_check][0]) { if (cl.configstrings[precache_check][0] == '*') { precache_check++; continue; } Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]); if (!CL_CheckOrDownloadFile(fn)) return; /* started a download */ } } precache_check = CS_IMAGES; } if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES) { if (precache_check == CS_IMAGES) precache_check++; while (precache_check < CS_IMAGES+MAX_IMAGES && cl.configstrings[precache_check][0]) { Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]); if (!CL_CheckOrDownloadFile(fn)) return; // started a download } precache_check = CS_PLAYERSKINS; } /* skins are special, since a player has three things to download: model, weapon model and skin so precache_check is now *3 */ if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) { if (allow_download_players->value) { while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) { int i, n; char model[MAX_QPATH], skin[MAX_QPATH], *p; i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT; n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT; if (!cl.configstrings[CS_PLAYERSKINS+i][0]) { precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT; continue; } if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL) p++; else p = cl.configstrings[CS_PLAYERSKINS+i]; strcpy(model, p); p = strchr(model, '/'); if (!p) p = strchr(model, '\\'); if (p) { *p++ = 0; strcpy(skin, p); } else *skin = 0; switch (n) { case 0: /* model */ Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model); if (!CL_CheckOrDownloadFile(fn)) { precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1; return; } n++; case 1: /* weapon model */ Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model); if (!CL_CheckOrDownloadFile(fn)) { precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2; return; } n++; case 2: /* weapon skin */ Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model); if (!CL_CheckOrDownloadFile(fn)) { precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3; return; } n++; case 3: /* skin */ Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin); if (!CL_CheckOrDownloadFile(fn)) { precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4; return; } n++; case 4: /* skin_i */ Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin); if (!CL_CheckOrDownloadFile(fn)) { precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5; return; // started a download } /* move on to next model */ precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT; } } } /* precache phase completed */ precache_check = ENV_CNT; } if (precache_check == ENV_CNT) { precache_check = ENV_CNT + 1; CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum); if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) { Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n", map_checksum, cl.configstrings[CS_MAPCHECKSUM]); return; } } if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) { if (allow_download->value && allow_download_maps->value) { while (precache_check < TEXTURE_CNT) { int n = precache_check++ - ENV_CNT - 1; if (n & 1) Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx", cl.configstrings[CS_SKY], env_suf[n/2]); else Com_sprintf(fn, sizeof(fn), "env/%s%s.tga", cl.configstrings[CS_SKY], env_suf[n/2]); if (!CL_CheckOrDownloadFile(fn)) return; } } precache_check = TEXTURE_CNT; } if (precache_check == TEXTURE_CNT) { precache_check = TEXTURE_CNT+1; precache_tex = 0; } /* confirm existance of textures, download any that don't exist */ if (precache_check == TEXTURE_CNT+1) { extern int numtexinfo; extern mapsurface_t map_surfaces[]; if (allow_download->value && allow_download_maps->value) { while (precache_tex < numtexinfo) { char fn[MAX_OSPATH]; sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname); if (!CL_CheckOrDownloadFile(fn)) return; /* started a download */ } } precache_check = TEXTURE_CNT+999; } CL_RegisterSounds (); CL_PrepRefresh (); MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) ); }
/* * Change the server to a new map, taking all connected * clients along with it. */ void SV_SpawnServer(char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame) { int i; unsigned checksum; if (attractloop) { Cvar_Set("paused", "0"); } Com_Printf("Server init\n"); Com_DPrintf("SpawnServer: %s\n", server); svs.spawncount++; /* any partially connected client will be restarted */ sv.state = ss_dead; Com_SetServerState(sv.state); /* wipe the entire per-level structure */ memset(&sv, 0, sizeof(sv)); svs.realtime = 0; sv.loadgame = loadgame; sv.attractloop = attractloop; /* save name for levels that don't set message */ strcpy(sv.configstrings[CS_NAME], server); if (Cvar_VariableValue("deathmatch")) { sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value); pm_airaccelerate = sv_airaccelerate->value; } else { strcpy(sv.configstrings[CS_AIRACCEL], "0"); pm_airaccelerate = 0; } SZ_Init(&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf)); strcpy(sv.name, server); /* leave slots at start for clients only */ for (i = 0; i < maxclients->value; i++) { /* needs to reconnect */ if (svs.clients[i].state > cs_connected) { svs.clients[i].state = cs_connected; } svs.clients[i].lastframe = -1; } sv.time = 1000; strcpy(sv.name, server); strcpy(sv.configstrings[CS_NAME], server); if (serverstate != ss_game) { sv.models[1] = CM_LoadMap("", false, &checksum); /* no real map */ } else { Com_sprintf(sv.configstrings[CS_MODELS + 1], sizeof(sv.configstrings[CS_MODELS + 1]), "maps/%s.bsp", server); sv.models[1] = CM_LoadMap(sv.configstrings[CS_MODELS + 1], false, &checksum); } Com_sprintf(sv.configstrings[CS_MAPCHECKSUM], sizeof(sv.configstrings[CS_MAPCHECKSUM]), "%i", checksum); /* clear physics interaction links */ SV_ClearWorld(); for (i = 1; i < CM_NumInlineModels(); i++) { Com_sprintf(sv.configstrings[CS_MODELS + 1 + i], sizeof(sv.configstrings[CS_MODELS + 1 + i]), "*%i", i); sv.models[i + 1] = CM_InlineModel(sv.configstrings[CS_MODELS + 1 + i]); } /* spawn the rest of the entities on the map */ sv.state = ss_loading; Com_SetServerState(sv.state); /* load and spawn all other entities */ SpawnEntities(sv.name, CM_EntityString(), spawnpoint); /* run two frames to allow everything to settle */ G_RunFrame(); G_RunFrame(); /* verify game didn't clobber important stuff */ if ((int) checksum != (int) strtol(sv.configstrings[CS_MAPCHECKSUM], (char **) NULL, 10)) { Com_Error(ERR_DROP, "Game DLL corrupted server configstrings"); } /* all precaches are complete */ sv.state = serverstate; Com_SetServerState(sv.state); /* create a baseline for more efficient communications */ SV_CreateBaseline(); /* set serverinfo variable */ Cvar_FullSet("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET); }
/* ================ 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(); }
static void testMove (void) { vec3_t vec; pos3_t pos; pos_t gridPos; if (FS_CheckFile("maps/%s.bsp", mapName) != -1) { char entityString[MAX_TOKEN_CHARS]; CM_LoadMap(mapName, true, "", entityString, &mapData, &mapTiles); CM_LoadMap(mapName, true, "", entityString, &mapData, &mapTiles); } else { UFO_CU_FAIL_MSG_FATAL(va("Map resource '%s.bsp' for test is missing.", mapName)); } VectorSet(vec, 16, 16, 48); VecToPos(vec, pos); CU_ASSERT_EQUAL(pos[0], 128); CU_ASSERT_EQUAL(pos[1], 128); CU_ASSERT_EQUAL(pos[2], 0); VectorSet(vec, 80, 16, 80); VecToPos(vec, pos); CU_ASSERT_EQUAL(pos[0], 130); CU_ASSERT_EQUAL(pos[1], 128); CU_ASSERT_EQUAL(pos[2], 1); gridPos = Grid_Fall(mapData.routing, ACTOR_SIZE_NORMAL, pos); CU_ASSERT_EQUAL(gridPos, 1); { const byte crouchingState = 0; const int maxTUs = MAX_ROUTE_TUS; int lengthStored; pos3_t to; pathing_t* path = Mem_AllocType(pathing_t); VectorSet(vec, 80, 80, 32); VecToPos(vec, pos); Grid_CalcPathing(mapData.routing, ACTOR_SIZE_NORMAL, path, pos, maxTUs, nullptr); Grid_MoveStore(path); /* move downwards */ { int lengthUnstored; VectorSet(vec, 80, 48, 32); VecToPos(vec, to); lengthUnstored = Grid_MoveLength(path, to, crouchingState, false); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthUnstored, lengthStored); CU_ASSERT_EQUAL(lengthStored, TU_MOVE_STRAIGHT); } /* try to move three steps upwards - there is a brush*/ { VectorSet(vec, 80, 176, 32); VecToPos(vec, to); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthStored, ROUTING_NOT_REACHABLE); } /* try move into the nodraw */ { VectorSet(vec, 48, 16, 32); VecToPos(vec, to); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthStored, ROUTING_NOT_REACHABLE); } /* move into the lightclip */ { VectorSet(vec, 48, 48, 32); VecToPos(vec, to); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthStored, TU_MOVE_DIAGONAL); } /* move into the passable */ { VectorSet(vec, 144, 48, 32); VecToPos(vec, to); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthStored, TU_MOVE_DIAGONAL + TU_MOVE_STRAIGHT); } /* go to the other side - diagonal, followed by six straight moves */ { VectorSet(vec, -16, 48, 32); VecToPos(vec, to); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthStored, 6 * TU_MOVE_STRAIGHT + TU_MOVE_DIAGONAL); } /* try to walk out of the map */ { VectorSet(vec, 48, 272, 32); VecToPos(vec, to); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthStored, ROUTING_NOT_REACHABLE); } /* walk to the map border */ { VectorSet(vec, 48, 240, 32); VecToPos(vec, to); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthStored, 4 * TU_MOVE_STRAIGHT + TU_MOVE_DIAGONAL); } /* walk a level upwards */ { VectorSet(vec, 240, 80, 96); VecToPos(vec, to); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthStored, 5 * TU_MOVE_STRAIGHT); } /* move to the door (not a func_door) */ { VectorSet(vec, 176, -80, 32); VecToPos(vec, to); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthStored, 4 * TU_MOVE_STRAIGHT + 2 * TU_MOVE_DIAGONAL); } /* move into the trigger_touch */ { VectorSet(vec, -48, -80, 32); VecToPos(vec, to); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthStored, 5 * TU_MOVE_STRAIGHT + 3 * TU_MOVE_DIAGONAL); } /* try to walk into the actorclip */ { VectorSet(vec, -48, -48, 32); VecToPos(vec, to); lengthStored = Grid_MoveLength(path, to, crouchingState, true); CU_ASSERT_EQUAL(lengthStored, ROUTING_NOT_REACHABLE); } } }
/* ================ 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" ); }
/** * @brief Change the server to a new map, taking all connected clients along with it. * @note the full syntax is: @code map [day|night] [+]<map> [<assembly>] @endcode * @sa SV_AssembleMap * @sa CM_LoadMap * @sa Com_SetServerState */ void SV_Map (qboolean day, const char *levelstring, const char *assembly) { int i; unsigned checksum = 0; char * map = SV_GetConfigString(CS_TILES); char * pos = SV_GetConfigString(CS_POSITIONS); mapInfo_t *randomMap = NULL; client_t *cl; /* any partially connected client will be restarted */ Com_SetServerState(ss_restart); /* the game is just starting */ SV_InitGame(); if (!svs.initialized) { Com_Printf("Could not spawn the server\n"); return; } assert(levelstring[0] != '\0'); Com_DPrintf(DEBUG_SERVER, "SpawnServer: %s\n", levelstring); /* save name for levels that don't set message */ SV_SetConfigString(CS_NAME, levelstring); SV_SetConfigString(CS_LIGHTMAP, day); Q_strncpyz(sv->name, levelstring, sizeof(sv->name)); /* set serverinfo variable */ sv_mapname = Cvar_FullSet("sv_mapname", sv->name, CVAR_SERVERINFO | CVAR_NOSET); /* notify the client in case of a listening server */ SCR_BeginLoadingPlaque(); if (assembly) Q_strncpyz(sv->assembly, assembly, sizeof(sv->assembly)); else sv->assembly[0] = '\0'; /* leave slots at start for clients only */ cl = NULL; while ((cl = SV_GetNextClient(cl)) != NULL) { /* needs to reconnect */ if (cl->state >= cs_spawning) SV_SetClientState(cl, cs_connected); } /* assemble and load the map */ if (levelstring[0] == '+') { randomMap = SV_AssembleMap(levelstring + 1, assembly, map, pos, 0); if (!randomMap) { Com_Printf("Could not load assembly for map '%s'\n", levelstring); return; } } else { SV_SetConfigString(CS_TILES, levelstring); SV_SetConfigString(CS_POSITIONS, assembly ? assembly : ""); } CM_LoadMap(map, day, pos, &sv->mapData, &sv->mapTiles); Com_Printf("checksum for the map '%s': %u\n", levelstring, sv->mapData.mapChecksum); SV_SetConfigString(CS_MAPCHECKSUM, sv->mapData.mapChecksum); checksum = Com_GetScriptChecksum(); Com_Printf("ufo script checksum %u\n", checksum); SV_SetConfigString(CS_UFOCHECKSUM, checksum); SV_SetConfigString(CS_OBJECTAMOUNT, csi.numODs); SV_SetConfigString(CS_VERSION, UFO_VERSION); SV_SetConfigString(CS_MAPTITLE, SV_GetMapTitle(randomMap, levelstring)); if (Q_strstart(SV_GetConfigString(CS_MAPTITLE), "b/")) { /* For base attack, CS_MAPTITLE contains too many chars */ SV_SetConfigString(CS_MAPTITLE, "Base attack"); SV_SetConfigString(CS_NAME, ".baseattack"); } /* clear random-map assembly data */ Mem_Free(randomMap); randomMap = NULL; /* clear physics interaction links */ SV_ClearWorld(); /* fix this! */ for (i = 1; i <= sv->mapData.numInline; i++) sv->models[i] = CM_InlineModel(&sv->mapTiles, va("*%i", i)); /* precache and static commands can be issued during map initialization */ Com_SetServerState(ss_loading); TH_MutexLock(svs.serverMutex); /* load and spawn all other entities */ svs.ge->SpawnEntities(sv->name, SV_GetConfigStringInteger(CS_LIGHTMAP), sv->mapData.mapEntityString); TH_MutexUnlock(svs.serverMutex); /* all precaches are complete */ Com_SetServerState(ss_game); Com_Printf("-------------------------------------\n"); Cbuf_CopyToDefer(); }
/** * @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(); } }