/* * @brief Entry point for spawning a new server or changing maps / demos. Brings any * connected clients along for the ride by broadcasting a reconnect before * clearing state. Special effort is made to ensure that a locally connected * client sees the reconnect message immediately. */ void Sv_InitServer(const char *server, sv_state_t state) { #ifdef BUILD_CLIENT extern void Cl_Disconnect(void); #endif char path[MAX_QPATH]; Com_Debug("Sv_InitServer: %s (%d)\n", server, state); Cbuf_CopyToDefer(); // ensure that the requested map or demo exists if (state == SV_ACTIVE_DEMO) g_snprintf(path, sizeof(path), "demos/%s.dem", server); else g_snprintf(path, sizeof(path), "maps/%s.bsp", server); if (!Fs_Exists(path)) { Com_Print("Couldn't open %s\n", path); return; } // inform any connected clients to reconnect to us Sv_ShutdownMessage("Server restarting...\n", true); #ifdef BUILD_CLIENT // disconnect any local client, they'll immediately reconnect Cl_Disconnect(); #endif // clear the sv_server_t structure Sv_ClearState(); Com_Print("Server initialization...\n"); // initialize the clients, loading the game module if we need it Sv_InitClients(); // load the map or demo and related media Sv_LoadMedia(server, state); sv.state = state; Sb_Init(&sv.multicast, sv.multicast_buffer, sizeof(sv.multicast_buffer)); Com_Print("Server initialized\n"); Com_InitSubsystem(Q2W_SERVER); svs.initialized = true; }
void SV_Map(qboolean attractloop, char *levelstring, qboolean loadgame) { char spawnpoint[1]; spawnpoint[0] = 0; sv.loadgame = loadgame; sv.attractloop = attractloop; if ((sv.state == ss_dead) && !sv.loadgame) { SV_InitGame(); /* the game is just starting */ } Cvar_Set("nextserver", ""); #ifndef DEDICATED_ONLY SCR_BeginLoadingPlaque(); /* for local system */ #endif SV_BroadcastCommand("changing\n"); SV_SendClientMessages(); SV_SpawnServer(levelstring, spawnpoint, ss_game, attractloop, loadgame); Cbuf_CopyToDefer(); SV_BroadcastCommand("reconnect\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(); }
/* ====================== SV_Map the full syntax is: map [*]<map>$<startspot>+<nextserver> command from the console or progs. Map can also be a.cin, .pcx, or .dm2 file Nextserver is used to allow a cinematic to play, then proceed to another level: map tram.cin+jail_e3 ====================== */ void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame) { char level[MAX_QPATH]; char *ch; int l; char spawnpoint[MAX_QPATH]; sv.loadgame = loadgame; sv.attractloop = attractloop; if (sv.state == ss_dead && !sv.loadgame) SV_InitGame (); // the game is just starting strcpy (level, levelstring); // if there is a + in the map, set nextserver to the remainder ch = strstr(level, "+"); if (ch) { *ch = 0; Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1)); } else Cvar_Set ("nextserver", ""); //ZOID special hack for end game screen in coop mode if (Cvar_VariableValue ("coop") && !Q_stricmp(level, "victory.pcx")) Cvar_Set ("nextserver", "gamemap \"*base1\""); // if there is a $, use the remainder as a spawnpoint ch = strstr(level, "$"); if (ch) { *ch = 0; strcpy (spawnpoint, ch+1); } else spawnpoint[0] = 0; // skip the end-of-unit flag if necessary if (level[0] == '*') strcpy (level, level+1); l = strlen(level); if (l > 4 && !strcmp (level+l-4, ".cin") ) { SCR_BeginLoadingPlaque (); // for local system SV_BroadcastCommand ("changing\n"); SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame); } else if (l > 4 && !strcmp (level+l-4, ".dm2") ) { SCR_BeginLoadingPlaque (); // for local system SV_BroadcastCommand ("changing\n"); SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame); } else if (l > 4 && !strcmp (level+l-4, ".pcx") ) { SCR_BeginLoadingPlaque (); // for local system SV_BroadcastCommand ("changing\n"); SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame); } else { SCR_BeginLoadingPlaque (); // for local system SV_BroadcastCommand ("changing\n"); SV_SendClientMessages (); SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame); Cbuf_CopyToDefer (); } SV_BroadcastCommand ("reconnect\n"); }
/* * ====================== * SV_Map * * the full syntax is: * * map [*]<map>$<startspot>+<nextserver> * * command from the console or progs. * Map can also be a.cin, .pcx, or .dm2 file * Nextserver is used to allow a cinematic to play, then proceed to * another level: * * map tram.cin+jail_e3 * ====================== */ void SV_Map(qboolean attractloop, char *levelstring, qboolean loadgame) { char level[MAX_QPATH]; char *ch; int l; char spawnpoint[MAX_QPATH]; sv.loadgame = loadgame; sv.attractloop = attractloop; if ((sv.state == ss_dead) && !sv.loadgame) { SV_InitGame(); // the game is just starting } // r1ch fix: buffer overflow // strcpy (level, levelstring); strncpy(level, levelstring, sizeof(level) - 1); // if there is a + in the map, set nextserver to the remainder ch = strstr(level, "+"); if (ch) { *ch = 0; Cvar_Set("nextserver", va("gamemap \"%s\"", ch + 1)); } else { Cvar_Set("nextserver", ""); } //ZOID special hack for end game screen in coop mode if (Cvar_VariableValue("coop") && !Q_strcasecmp(level, "victory.pcx")) { Cvar_Set("nextserver", "gamemap \"*base1\""); } // if there is a $, use the remainder as a spawnpoint ch = strstr(level, "$"); if (ch) { *ch = 0; strcpy(spawnpoint, ch + 1); } else { spawnpoint[0] = 0; } // skip the end-of-unit flag if necessary if (level[0] == '*') { strcpy(level, level + 1); } l = strlen(level); #ifdef ROQ_SUPPORT if ((l > 4) && (!strcmp(level + l - 4, ".cin") || !strcmp(level + l - 4, ".roq"))) #else if ((l > 4) && !strcmp(level + l - 4, ".cin")) #endif // ROQ_SUPPORT { if (!dedicated->value) { #ifndef DEDICATED_ONLY SCR_BeginLoadingPlaque(); // for local system #endif } SV_BroadcastCommand("changing\n"); SV_SpawnServer(level, spawnpoint, ss_cinematic, attractloop, loadgame); } else if ((l > 4) && !strcmp(level + l - 4, ".dm2")) { if (!dedicated->value) { #ifndef DEDICATED_ONLY SCR_BeginLoadingPlaque(); // for local system #endif } SV_BroadcastCommand("changing\n"); SV_SpawnServer(level, spawnpoint, ss_demo, attractloop, loadgame); } else if ((l > 4) && !strcmp(level + l - 4, ".pcx")) { if (!dedicated->value) { #ifndef DEDICATED_ONLY SCR_BeginLoadingPlaque(); // for local system #endif } SV_BroadcastCommand("changing\n"); SV_SpawnServer(level, spawnpoint, ss_pic, attractloop, loadgame); } else { if (!dedicated->value) { #ifndef DEDICATED_ONLY SCR_BeginLoadingPlaque(); // for local system #endif } SV_BroadcastCommand("changing\n"); SV_SendClientMessages(); SV_SpawnServer(level, spawnpoint, ss_game, attractloop, loadgame); Cbuf_CopyToDefer(); } SV_BroadcastCommand("reconnect\n"); }
/* ====================== SV_Map the full syntax is: map [*]<map>$<startspot>+<nextserver> command from the console or progs. Map can also be a.cin, .pcx, or .dm2 file Nextserver is used to allow a cinematic to play, then proceed to another level: map tram.cin+jail_e3 ====================== */ void SV_Map (qboolean attractloop, const char *levelstring, qboolean loadgame) { char level[MAX_QPATH]; char *ch; int l; char spawnpoint[MAX_QPATH]; strcpy(level, levelstring); // jit - copy level string before it gets modified by other commands (since it's a command argument) sv.loadgame = loadgame; sv.attractloop = attractloop; if (sv.state == ss_dead && !sv.loadgame) SV_InitGame(); // the game is just starting // if there is a + in the map, set nextserver to the remainder ch = strstr(level, "+"); if (ch) { *ch = 0; Cvar_Set("nextserver", va("gamemap \"%s\"", ch + 1)); } else { Cvar_Set("nextserver", ""); } //ZOID special hack for end game screen in coop mode if (Cvar_VariableValue("coop") && Q_strcaseeq(level, "victory.pcx")) Cvar_Set("nextserver", "gamemap \"*base1\""); // if there is a $, use the remainder as a spawnpoint ch = strstr(level, "$"); if (ch) { *ch = 0; strcpy(spawnpoint, ch + 1); } else { spawnpoint[0] = 0; } // skip the end-of-unit flag if necessary if (level[0] == '*') strcpy (level, level+1); l = strlen(level); if (l > 4 && Q_streq(level + l - 4, ".cin")) { SCR_BeginLoadingPlaque(NULL); // for local system SV_BroadcastCommand("changing\n"); SV_SpawnServer(level, spawnpoint, ss_cinematic, attractloop, loadgame); } else if (l > 4 && Q_streq(level + l - 4, ".dm2")) { SCR_BeginLoadingPlaque(NULL); // for local system SV_BroadcastCommand("changing\n"); SV_SpawnServer(level, spawnpoint, ss_demo, attractloop, loadgame); } else if (l > 4 && Q_streq(level + l - 4, ".pcx")) { SCR_BeginLoadingPlaque(NULL); // for local system SV_BroadcastCommand("changing\n"); SV_SpawnServer(level, spawnpoint, ss_pic, attractloop, loadgame); } else { char changing_cmd[1024]; if (!dedicated->value) SCR_BeginLoadingPlaque(level); // for local system Com_sprintf(changing_cmd, sizeof(changing_cmd), "changing \"%s\"\n", level); SV_BroadcastCommand(changing_cmd); SV_SendClientMessages(); SV_SpawnServer(level, spawnpoint, ss_game, attractloop, loadgame); Cbuf_CopyToDefer(); } SV_BroadcastCommand("reconnect\n"); }