diff options
Diffstat (limited to 'src/jake2/server/SV_INIT.java')
-rw-r--r-- | src/jake2/server/SV_INIT.java | 962 |
1 files changed, 484 insertions, 478 deletions
diff --git a/src/jake2/server/SV_INIT.java b/src/jake2/server/SV_INIT.java index 2325f22..0c1c5ae 100644 --- a/src/jake2/server/SV_INIT.java +++ b/src/jake2/server/SV_INIT.java @@ -1,493 +1,499 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 14.01.2004 by RST. -// $Id: SV_INIT.java,v 1.8 2004-08-29 21:39:25 hzi Exp $ - +// $Id: SV_INIT.java,v 1.9 2004-09-22 19:22:12 salomo Exp $ package jake2.server; +import jake2.Defines; import jake2.Globals; import jake2.client.CL; import jake2.client.SCR; import jake2.game.*; import jake2.qcommon.*; import jake2.sys.NET; +import jake2.util.Lib; +import jake2.util.Math3D; import java.io.IOException; import java.io.RandomAccessFile; -public class SV_INIT extends Globals { - - public static server_static_t svs= new server_static_t(); // persistant server info - public static server_t sv= new server_t(); // local server - - /* - ================ - SV_FindIndex - - ================ - */ - public static int SV_FindIndex(String name, int start, int max, boolean create) { - int i; - - if (name == null || name.length() == 0) - return 0; - - for (i= 1; i < max && sv.configstrings[start + i] != null; i++) - if (0 == strcmp(sv.configstrings[start + i], name)) - return i; - - if (!create) - return 0; - - if (i == max) - Com.Error(ERR_DROP, "*Index: overflow"); - - //strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i])); - sv.configstrings[start + i]= name; - - if (sv.state != ss_loading) { // send the update to everyone - SZ.Clear(sv.multicast); - MSG.WriteChar(sv.multicast, svc_configstring); - MSG.WriteShort(sv.multicast, start + i); - MSG.WriteString(sv.multicast, name); - SV_SEND.SV_Multicast(Game.vec3_origin, MULTICAST_ALL_R); - } - - return i; - } - - public static int SV_ModelIndex(String name) { - return SV_FindIndex(name, CS_MODELS, MAX_MODELS, true); - } - - public static int SV_SoundIndex(String name) { - return SV_FindIndex(name, CS_SOUNDS, MAX_SOUNDS, true); - } - - public static int SV_ImageIndex(String name) { - return SV_FindIndex(name, CS_IMAGES, MAX_IMAGES, true); - } - - /* - ================ - SV_CreateBaseline - - Entity baselines are used to compress the update messages - to the clients -- only the fields that differ from the - baseline will be transmitted - ================ - */ - public static void SV_CreateBaseline() { - edict_t svent; - int entnum; - - for (entnum= 1; entnum < GameBase.num_edicts; entnum++) { - //svent = EDICT_NUM(entnum); - svent= GameBase.g_edicts[entnum]; - - if (!svent.inuse) - continue; - if (0 == svent.s.modelindex && 0 == svent.s.sound && 0 == svent.s.effects) - continue; - svent.s.number= entnum; - - // - // take current state as baseline - // - VectorCopy(svent.s.origin, svent.s.old_origin); - // rst: bugfix - sv.baselines[entnum].set(svent.s); // = svent.s.getClone(); - } - } - - /* - ================= - SV_CheckForSavegame - ================= - */ - public static void SV_CheckForSavegame() { - - String name; - RandomAccessFile f; - - int i; - - if (SV_MAIN.sv_noreload.value != 0) - return; - - if (Cvar.VariableValue("deathmatch") != 0) - return; - - name= FS.Gamedir() + "/save/current/" + sv.name + ".sav"; - try { - f= new RandomAccessFile(name, "r"); - } - - catch (Exception e) { - return; - } - - try { - f.close(); - } - catch (IOException e1) { - e1.printStackTrace(); - } - - SV_WORLD.SV_ClearWorld(); - - // get configstrings and areaportals - SV_CCMDS.SV_ReadLevelFile(); - - if (!sv.loadgame) { // coming back to a level after being in a different - // level, so run it for ten seconds - - // rlava2 was sending too many lightstyles, and overflowing the - // reliable data. temporarily changing the server state to loading - // prevents these from being passed down. - int previousState; // PGM - - previousState= sv.state; // PGM - sv.state= ss_loading; // PGM - for (i= 0; i < 100; i++) - Game.G_RunFrame(); - - sv.state= previousState; // PGM - } - } - - /* - ================ - SV_SpawnServer - - Change the server to a new map, taking all connected - clients along with it. - - ================ - */ - public static void SV_SpawnServer(String server, String spawnpoint, int serverstate, boolean attractloop, boolean loadgame) { - int i; - int checksum= 0; - - if (attractloop) - Cvar.Set("paused", "0"); - - Com.Printf("------- Server Initialization -------\n"); - - Com.DPrintf("SpawnServer: " + server + "\n"); - if (sv.demofile != null) - try { - sv.demofile.close(); - } - catch (Exception e) { - } - - svs.spawncount++; // any partially connected client will be - // restarted - - sv.state= ss_dead; - - Globals.server_state= sv.state; - - // wipe the entire per-level structure - //memset(sv, 0, sizeof(sv)); - sv= new server_t(); - - svs.realtime= 0; - sv.loadgame= loadgame; - sv.attractloop= attractloop; - - // save name for levels that don't set message - sv.configstrings[CS_NAME]= server; - - if (Cvar.VariableValue("deathmatch") != 0) { - sv.configstrings[CS_AIRACCEL]= "" + SV_MAIN.sv_airaccelerate.value; - PMove.pm_airaccelerate= SV_MAIN.sv_airaccelerate.value; - } - else { - sv.configstrings[CS_AIRACCEL]= "0"; - PMove.pm_airaccelerate= 0; - } - - SZ.Init(sv.multicast, sv.multicast_buf, sv.multicast_buf.length); - - sv.name= server; - - // leave slots at start for clients only - for (i= 0; i < SV_MAIN.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; - - sv.name= server; - sv.configstrings[CS_NAME]= server; - - int iw[]= { checksum }; - - if (serverstate != ss_game) { - sv.models[1]= CM.CM_LoadMap("", false, iw); // no real map - } - else { - sv.configstrings[CS_MODELS + 1]= "maps/" + server + ".bsp"; - sv.models[1]= CM.CM_LoadMap(sv.configstrings[CS_MODELS + 1], false, iw); - } - checksum= iw[0]; - sv.configstrings[CS_MAPCHECKSUM]= "" + checksum; - - // - // clear physics interaction links - // - SV_WORLD.SV_ClearWorld(); - - for (i= 1; i < CM.CM_NumInlineModels(); i++) { - sv.configstrings[CS_MODELS + 1 + i]= "*" + i; - // copy references - 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; - Globals.server_state= sv.state; - - // load and spawn all other entities - Game.SpawnEntities(sv.name, CM.CM_EntityString(), spawnpoint); - - // run two frames to allow everything to settle - Game.G_RunFrame(); - Game.G_RunFrame(); - - // all precaches are complete - sv.state= serverstate; - Globals.server_state= 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_InitGame - - A brand new game has been started - ============== - */ - public static void SV_InitGame() { - int i; - edict_t ent; - //char idmaster[32]; - String idmaster; - - if (svs.initialized) { - // cause any connected clients to reconnect - SV_MAIN.SV_Shutdown("Server restarted\n", true); - } - else { - // make sure the client is down - CL.Drop(); - SCR.BeginLoadingPlaque(); - } - - // get any latched variable changes (maxclients, etc) - Cvar.GetLatchedVars(); - - svs.initialized= true; - - if (Cvar.VariableValue("coop") != 0 && Cvar.VariableValue("deathmatch") != 0) { - Com.Printf("Deathmatch and Coop both set, disabling Coop\n"); - Cvar.FullSet("coop", "0", CVAR_SERVERINFO | CVAR_LATCH); - } - - // dedicated servers are can't be single player and are usually DM - // so unless they explicity set coop, force it to deathmatch - if (dedicated.value != 0) { - if (0 == Cvar.VariableValue("coop")) - Cvar.FullSet("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH); - } - - // init clients - if (Cvar.VariableValue("deathmatch") != 0) { - if (SV_MAIN.maxclients.value <= 1) - Cvar.FullSet("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH); - else if (SV_MAIN.maxclients.value > MAX_CLIENTS) - Cvar.FullSet("maxclients", "" + MAX_CLIENTS, CVAR_SERVERINFO | CVAR_LATCH); - } - else if (Cvar.VariableValue("coop") != 0) { - if (SV_MAIN.maxclients.value <= 1 || SV_MAIN.maxclients.value > 4) - Cvar.FullSet("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); - - } - else // non-deathmatch, non-coop is one player - { - Cvar.FullSet("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH); - } - - svs.spawncount= rand(); - //svs.clients = Z_Malloc(sizeof(client_t) * maxclients.value); - svs.clients= new client_t[(int) SV_MAIN.maxclients.value]; - for (int n= 0; n < svs.clients.length; n++) - svs.clients[n]= new client_t(); - - svs.num_client_entities= ((int) SV_MAIN.maxclients.value) * UPDATE_BACKUP * 64; //ok. - - //svs.client_entities = Z_Malloc(sizeof(entity_state_t) * svs.num_client_entities); - svs.client_entities= new entity_state_t[svs.num_client_entities]; - for (int n= 0; n < svs.client_entities.length; n++) - svs.client_entities[n]= new entity_state_t(null); - - // init network stuff - NET.Config((SV_MAIN.maxclients.value > 1)); //ok! - - // heartbeats will always be sent to the id master - svs.last_heartbeat= -99999; // send immediately - idmaster= "192.246.40.37:" + PORT_MASTER; - NET.StringToAdr(idmaster, SV_MAIN.master_adr[0]); - - // init game - SV_GAME.SV_InitGameProgs(); // bis hier alles ok! - - for (i= 0; i < SV_MAIN.maxclients.value; i++) { - ent= GameBase.g_edicts[i + 1]; - - //ent.s.number = i + 1; //dont need this, ent.s.number already set. - svs.clients[i].edict= ent; - //memset(& svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd)); - svs.clients[i].lastcmd= new usercmd_t(); - } - } - - /* - ====================== - 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 - ====================== - */ - public static void SV_Map(boolean attractloop, String levelstring, boolean loadgame) { - //char level[MAX_QPATH]; - //char *ch; - int l; - //char spawnpoint[MAX_QPATH]; - - String level, ch, spawnpoint; - - sv.loadgame= loadgame; - sv.attractloop= attractloop; - - if (sv.state == ss_dead && !sv.loadgame) - SV_InitGame(); // the game is just starting - - level= levelstring; // bis hier her ok. - - // if there is a + in the map, set nextserver to the remainder - - //was: - // ch = strstr(level, "+"); - // if (ch) - // { - // *ch = 0; - // Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1)); - // } - // else - // Cvar_Set ("nextserver", ""); - - int c= level.indexOf('+'); - if (c != -1) { - Cvar.Set("nextserver", "gamemap \"" + level.substring(c + 1) + "\""); - level= level.substring(0, c); - } - else { - Cvar.Set("nextserver", ""); - } - - //ZOID special hack for end game screen in coop mode - if (Cvar.VariableValue("coop") != 0 && !level.equals("victory.pcx")) - Cvar.Set("nextserver", "gamemap \"*base1\""); - - // if there is a $, use the remainder as a spawnpoint - int pos= level.indexOf('$'); - if (pos != -1) { - //* ch = 0; - spawnpoint= level.substring(pos + 1); - level= level.substring(0, pos); - - } - else - //spawnpoint[0] = 0; - spawnpoint= ""; - - // skip the end-of-unit flag if necessary - if (level.charAt(0) == '*') - level= level.substring(1); - - l= level.length(); - if (l > 4 && level.endsWith(".cin")) { - SCR.BeginLoadingPlaque(); // for local system - SV_SEND.SV_BroadcastCommand("changing\n"); - SV_SpawnServer(level, spawnpoint, ss_cinematic, attractloop, loadgame); - } - else if (l > 4 && level.endsWith(".dm2")) { - SCR.BeginLoadingPlaque(); // for local system - SV_SEND.SV_BroadcastCommand("changing\n"); - SV_SpawnServer(level, spawnpoint, ss_demo, attractloop, loadgame); - } - else if (l > 4 && level.endsWith(".pcx")) { - SCR.BeginLoadingPlaque(); // for local system - SV_SEND.SV_BroadcastCommand("changing\n"); - SV_SpawnServer(level, spawnpoint, ss_pic, attractloop, loadgame); - } - else { - SCR.BeginLoadingPlaque(); // for local system - SV_SEND.SV_BroadcastCommand("changing\n"); - SV_SEND.SV_SendClientMessages(); - SV_SpawnServer(level, spawnpoint, ss_game, attractloop, loadgame); - Cbuf.CopyToDefer(); - } - - SV_SEND.SV_BroadcastCommand("reconnect\n"); - } -} +public class SV_INIT { + + /* + * ================ SV_FindIndex + * + * ================ + */ + public static int SV_FindIndex(String name, int start, int max, + boolean create) { + int i; + + if (name == null || name.length() == 0) + return 0; + + for (i = 1; i < max && sv.configstrings[start + i] != null; i++) + if (0 == Lib.strcmp(sv.configstrings[start + i], name)) + return i; + + if (!create) + return 0; + + if (i == max) + Com.Error(Defines.ERR_DROP, "*Index: overflow"); + + //strncpy (sv.configstrings[start+i], name, + // sizeof(sv.configstrings[i])); + sv.configstrings[start + i] = name; + + if (sv.state != Defines.ss_loading) { // send the update to everyone + SZ.Clear(sv.multicast); + MSG.WriteChar(sv.multicast, Defines.svc_configstring); + MSG.WriteShort(sv.multicast, start + i); + MSG.WriteString(sv.multicast, name); + SV_SEND.SV_Multicast(Globals.vec3_origin, Defines.MULTICAST_ALL_R); + } + + return i; + } + + public static int SV_ModelIndex(String name) { + return SV_FindIndex(name, Defines.CS_MODELS, Defines.MAX_MODELS, true); + } + + public static int SV_SoundIndex(String name) { + return SV_FindIndex(name, Defines.CS_SOUNDS, Defines.MAX_SOUNDS, true); + } + + public static int SV_ImageIndex(String name) { + return SV_FindIndex(name, Defines.CS_IMAGES, Defines.MAX_IMAGES, true); + } + + /* + * ================ SV_CreateBaseline + * + * Entity baselines are used to compress the update messages to the clients -- + * only the fields that differ from the baseline will be transmitted + * ================ + */ + public static void SV_CreateBaseline() { + edict_t svent; + int entnum; + + for (entnum = 1; entnum < GameBase.num_edicts; entnum++) { + //svent = EDICT_NUM(entnum); + svent = GameBase.g_edicts[entnum]; + + if (!svent.inuse) + continue; + if (0 == svent.s.modelindex && 0 == svent.s.sound + && 0 == svent.s.effects) + continue; + svent.s.number = entnum; + + // + // take current state as baseline + // + Math3D.VectorCopy(svent.s.origin, svent.s.old_origin); + // rst: bugfix + sv.baselines[entnum].set(svent.s); // = svent.s.getClone(); + } + } + + /* + * ================= SV_CheckForSavegame ================= + */ + public static void SV_CheckForSavegame() { + + String name; + RandomAccessFile f; + + int i; + + if (SV_MAIN.sv_noreload.value != 0) + return; + + if (Cvar.VariableValue("deathmatch") != 0) + return; + + name = FS.Gamedir() + "/save/current/" + sv.name + ".sav"; + try { + f = new RandomAccessFile(name, "r"); + } + + catch (Exception e) { + return; + } + + try { + f.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + + SV_WORLD.SV_ClearWorld(); + + // get configstrings and areaportals + SV_CCMDS.SV_ReadLevelFile(); + + if (!sv.loadgame) { // coming back to a level after being in a different + // level, so run it for ten seconds + + // rlava2 was sending too many lightstyles, and overflowing the + // reliable data. temporarily changing the server state to loading + // prevents these from being passed down. + int previousState; // PGM + + previousState = sv.state; // PGM + sv.state = Defines.ss_loading; // PGM + for (i = 0; i < 100; i++) + GameBase.G_RunFrame(); + + sv.state = previousState; // PGM + } + } + + /* + * ================ SV_SpawnServer + * + * Change the server to a new map, taking all connected clients along with + * it. + * + * ================ + */ + public static void SV_SpawnServer(String server, String spawnpoint, + int serverstate, boolean attractloop, boolean loadgame) { + int i; + int checksum = 0; + + if (attractloop) + Cvar.Set("paused", "0"); + + Com.Printf("------- Server Initialization -------\n"); + + Com.DPrintf("SpawnServer: " + server + "\n"); + if (sv.demofile != null) + try { + sv.demofile.close(); + } catch (Exception e) { + } + + svs.spawncount++; // any partially connected client will be + // restarted + + sv.state = Defines.ss_dead; + + Globals.server_state = sv.state; + + // wipe the entire per-level structure + //memset(sv, 0, sizeof(sv)); + sv = new server_t(); + + svs.realtime = 0; + sv.loadgame = loadgame; + sv.attractloop = attractloop; + + // save name for levels that don't set message + sv.configstrings[Defines.CS_NAME] = server; + + if (Cvar.VariableValue("deathmatch") != 0) { + sv.configstrings[Defines.CS_AIRACCEL] = "" + + SV_MAIN.sv_airaccelerate.value; + PMove.pm_airaccelerate = SV_MAIN.sv_airaccelerate.value; + } else { + sv.configstrings[Defines.CS_AIRACCEL] = "0"; + PMove.pm_airaccelerate = 0; + } + + SZ.Init(sv.multicast, sv.multicast_buf, sv.multicast_buf.length); + + sv.name = server; + + // leave slots at start for clients only + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + // needs to reconnect + if (svs.clients[i].state > Defines.cs_connected) + svs.clients[i].state = Defines.cs_connected; + svs.clients[i].lastframe = -1; + } + + sv.time = 1000; + + sv.name = server; + sv.configstrings[Defines.CS_NAME] = server; + + int iw[] = { checksum }; + + if (serverstate != Defines.ss_game) { + sv.models[1] = CM.CM_LoadMap("", false, iw); // no real map + } else { + sv.configstrings[Defines.CS_MODELS + 1] = "maps/" + server + ".bsp"; + sv.models[1] = CM.CM_LoadMap( + sv.configstrings[Defines.CS_MODELS + 1], false, iw); + } + checksum = iw[0]; + sv.configstrings[Defines.CS_MAPCHECKSUM] = "" + checksum; + + // + // clear physics interaction links + // + SV_WORLD.SV_ClearWorld(); + + for (i = 1; i < CM.CM_NumInlineModels(); i++) { + sv.configstrings[Defines.CS_MODELS + 1 + i] = "*" + i; + // copy references + sv.models[i + 1] = CM + .InlineModel(sv.configstrings[Defines.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 = Defines.ss_loading; + Globals.server_state = sv.state; + + // load and spawn all other entities + GameSpawn.SpawnEntities(sv.name, CM.CM_EntityString(), spawnpoint); + + // run two frames to allow everything to settle + GameBase.G_RunFrame(); + GameBase.G_RunFrame(); + + // all precaches are complete + sv.state = serverstate; + Globals.server_state = 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, Defines.CVAR_SERVERINFO + | Defines.CVAR_NOSET); + + //Com.Printf("-------------------------------------\n"); + } + + /* + * ============== SV_InitGame + * + * A brand new game has been started ============== + */ + public static void SV_InitGame() { + int i; + edict_t ent; + //char idmaster[32]; + String idmaster; + + if (svs.initialized) { + // cause any connected clients to reconnect + SV_MAIN.SV_Shutdown("Server restarted\n", true); + } else { + // make sure the client is down + CL.Drop(); + SCR.BeginLoadingPlaque(); + } + + // get any latched variable changes (maxclients, etc) + Cvar.GetLatchedVars(); + + svs.initialized = true; + + if (Cvar.VariableValue("coop") != 0 + && Cvar.VariableValue("deathmatch") != 0) { + Com.Printf("Deathmatch and Coop both set, disabling Coop\n"); + Cvar.FullSet("coop", "0", Defines.CVAR_SERVERINFO + | Defines.CVAR_LATCH); + } + + // dedicated servers are can't be single player and are usually DM + // so unless they explicity set coop, force it to deathmatch + if (Globals.dedicated.value != 0) { + if (0 == Cvar.VariableValue("coop")) + Cvar.FullSet("deathmatch", "1", Defines.CVAR_SERVERINFO + | Defines.CVAR_LATCH); + } + + // init clients + if (Cvar.VariableValue("deathmatch") != 0) { + if (SV_MAIN.maxclients.value <= 1) + Cvar.FullSet("maxclients", "8", Defines.CVAR_SERVERINFO + | Defines.CVAR_LATCH); + else if (SV_MAIN.maxclients.value > Defines.MAX_CLIENTS) + Cvar.FullSet("maxclients", "" + Defines.MAX_CLIENTS, + Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH); + } else if (Cvar.VariableValue("coop") != 0) { + if (SV_MAIN.maxclients.value <= 1 || SV_MAIN.maxclients.value > 4) + Cvar.FullSet("maxclients", "4", Defines.CVAR_SERVERINFO + | Defines.CVAR_LATCH); + + } else // non-deathmatch, non-coop is one player + { + Cvar.FullSet("maxclients", "1", Defines.CVAR_SERVERINFO + | Defines.CVAR_LATCH); + } + + svs.spawncount = Lib.rand(); + //svs.clients = Z_Malloc(sizeof(client_t) * maxclients.value); + svs.clients = new client_t[(int) SV_MAIN.maxclients.value]; + for (int n = 0; n < svs.clients.length; n++) + svs.clients[n] = new client_t(); + + svs.num_client_entities = ((int) SV_MAIN.maxclients.value) + * Defines.UPDATE_BACKUP * 64; //ok. + + //svs.client_entities = Z_Malloc(sizeof(entity_state_t) * + // svs.num_client_entities); + svs.client_entities = new entity_state_t[svs.num_client_entities]; + for (int n = 0; n < svs.client_entities.length; n++) + svs.client_entities[n] = new entity_state_t(null); + + // init network stuff + NET.Config((SV_MAIN.maxclients.value > 1)); //ok! + + // heartbeats will always be sent to the id master + svs.last_heartbeat = -99999; // send immediately + idmaster = "192.246.40.37:" + Defines.PORT_MASTER; + NET.StringToAdr(idmaster, SV_MAIN.master_adr[0]); + + // init game + SV_GAME.SV_InitGameProgs(); // bis hier alles ok! + + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + ent = GameBase.g_edicts[i + 1]; + + //ent.s.number = i + 1; //dont need this, ent.s.number already set. + svs.clients[i].edict = ent; + //memset(& svs.clients[i].lastcmd, 0, + // sizeof(svs.clients[i].lastcmd)); + svs.clients[i].lastcmd = new usercmd_t(); + } + } + + /* + * ====================== 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 ====================== + */ + public static void SV_Map(boolean attractloop, String levelstring, + boolean loadgame) { + //char level[MAX_QPATH]; + //char *ch; + int l; + //char spawnpoint[MAX_QPATH]; + + String level, ch, spawnpoint; + + sv.loadgame = loadgame; + sv.attractloop = attractloop; + + if (sv.state == Defines.ss_dead && !sv.loadgame) + SV_InitGame(); // the game is just starting + + level = levelstring; // bis hier her ok. + + // if there is a + in the map, set nextserver to the remainder + + //was: + // ch = strstr(level, "+"); + // if (ch) + // { + // *ch = 0; + // Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1)); + // } + // else + // Cvar_Set ("nextserver", ""); + + int c = level.indexOf('+'); + if (c != -1) { + Cvar + .Set("nextserver", "gamemap \"" + level.substring(c + 1) + + "\""); + level = level.substring(0, c); + } else { + Cvar.Set("nextserver", ""); + } + + //ZOID special hack for end game screen in coop mode + if (Cvar.VariableValue("coop") != 0 && !level.equals("victory.pcx")) + Cvar.Set("nextserver", "gamemap \"*base1\""); + + // if there is a $, use the remainder as a spawnpoint + int pos = level.indexOf('$'); + if (pos != -1) { + //* ch = 0; + spawnpoint = level.substring(pos + 1); + level = level.substring(0, pos); + + } else + //spawnpoint[0] = 0; + spawnpoint = ""; + + // skip the end-of-unit flag if necessary + if (level.charAt(0) == '*') + level = level.substring(1); + + l = level.length(); + if (l > 4 && level.endsWith(".cin")) { + SCR.BeginLoadingPlaque(); // for local system + SV_SEND.SV_BroadcastCommand("changing\n"); + SV_SpawnServer(level, spawnpoint, Defines.ss_cinematic, + attractloop, loadgame); + } else if (l > 4 && level.endsWith(".dm2")) { + SCR.BeginLoadingPlaque(); // for local system + SV_SEND.SV_BroadcastCommand("changing\n"); + SV_SpawnServer(level, spawnpoint, Defines.ss_demo, attractloop, + loadgame); + } else if (l > 4 && level.endsWith(".pcx")) { + SCR.BeginLoadingPlaque(); // for local system + SV_SEND.SV_BroadcastCommand("changing\n"); + SV_SpawnServer(level, spawnpoint, Defines.ss_pic, attractloop, + loadgame); + } else { + SCR.BeginLoadingPlaque(); // for local system + SV_SEND.SV_BroadcastCommand("changing\n"); + SV_SEND.SV_SendClientMessages(); + SV_SpawnServer(level, spawnpoint, Defines.ss_game, attractloop, + loadgame); + Cbuf.CopyToDefer(); + } + + SV_SEND.SV_BroadcastCommand("reconnect\n"); + } + + public static server_static_t svs = new server_static_t(); // persistant + // server info + + public static server_t sv = new server_t(); // local server +}
\ No newline at end of file |