/// <summary> /// ED_ParseEdict /// Parses an edict out of the given string, returning the new position /// ed should be a properly initialized empty edict. /// Used for initial level load and for savegames. /// </summary> public static string ParseEdict(string data, edict_t ent) { bool init = false; // clear it if (ent != Server.sv.edicts[0]) // hack { ent.Clear(); } // go through all the dictionary pairs bool anglehack; while (true) { // parse key data = Common.Parse(data); if (Common.Token.StartsWith("}")) { break; } if (data == null) { Sys.Error("ED_ParseEntity: EOF without closing brace"); } string token = Common.Token; // anglehack is to allow QuakeEd to write single scalar angles // and allow them to be turned into vectors. (FIXME...) if (token == "angle") { token = "angles"; anglehack = true; } else { anglehack = false; } // FIXME: change light to _light to get rid of this hack if (token == "light") { token = "light_lev"; // hack for single light def } string keyname = token.TrimEnd(); // parse value data = Common.Parse(data); if (data == null) { Sys.Error("ED_ParseEntity: EOF without closing brace"); } if (Common.Token.StartsWith("}")) { Sys.Error("ED_ParseEntity: closing brace without data"); } init = true; // keynames with a leading underscore are used for utility comments, // and are immediately discarded by quake if (keyname[0] == '_') { continue; } ddef_t key = FindField(keyname); if (key == null) { Con.Print("'{0}' is not a field\n", keyname); continue; } token = Common.Token; if (anglehack) { token = "0 " + token + " 0"; } if (!ParsePair(ent, key, token)) { Host.Error("ED_ParseEdict: parse error"); } } if (!init) { ent.free = true; } return(data); }
/// <summary> /// Host_Loadgame_f /// </summary> static void Loadgame_f() { if (Cmd.Source != cmd_source_t.src_command) { return; } if (Cmd.Argc != 2) { Con.Print("load <savename> : load a game\n"); return; } Client.cls.demonum = -1; // stop demo loop in case this fails string name = Path.ChangeExtension(Path.Combine(Common.GameDir, Cmd.Argv(1)), ".sav"); // we can't call SCR_BeginLoadingPlaque, because too much stack space has // been used. The menu calls it before stuffing loadgame command // SCR_BeginLoadingPlaque (); Con.Print("Loading game from {0}...\n", name); FileStream fs = Sys.FileOpenRead(name); if (fs == null) { Con.Print("ERROR: couldn't open.\n"); return; } using (StreamReader reader = new StreamReader(fs, Encoding.ASCII)) { string line = reader.ReadLine(); int version = Common.atoi(line); if (version != SAVEGAME_VERSION) { Con.Print("Savegame is version {0}, not {1}\n", version, SAVEGAME_VERSION); return; } line = reader.ReadLine(); float[] spawn_parms = new float[Server.NUM_SPAWN_PARMS]; for (int i = 0; i < spawn_parms.Length; i++) { line = reader.ReadLine(); spawn_parms[i] = Common.atof(line); } // this silliness is so we can load 1.06 save files, which have float skill values line = reader.ReadLine(); float tfloat = Common.atof(line); Host.CurrentSkill = (int)(tfloat + 0.1); Cvar.Set("skill", (float)Host.CurrentSkill); string mapname = reader.ReadLine(); line = reader.ReadLine(); float time = Common.atof(line); Client.Disconnect_f(); Server.SpawnServer(mapname); if (!Server.sv.active) { Con.Print("Couldn't load map\n"); return; } Server.sv.paused = true; // pause until all clients connect Server.sv.loadgame = true; // load the light styles for (int i = 0; i < QDef.MAX_LIGHTSTYLES; i++) { line = reader.ReadLine(); Server.sv.lightstyles[i] = line; } // load the edicts out of the savegame file int entnum = -1; // -1 is the globals StringBuilder sb = new StringBuilder(32768); while (!reader.EndOfStream) { line = reader.ReadLine(); if (line == null) { Sys.Error("EOF without closing brace"); } sb.AppendLine(line); int idx = line.IndexOf('}'); if (idx != -1) { int length = 1 + sb.Length - (line.Length - idx); string data = Common.Parse(sb.ToString(0, length)); if (String.IsNullOrEmpty(Common.Token)) { break; // end of file } if (Common.Token != "{") { Sys.Error("First token isn't a brace"); } if (entnum == -1) { // parse the global vars Progs.ParseGlobals(data); } else { // parse an edict edict_t ent = Server.EdictNum(entnum); ent.Clear(); Progs.ParseEdict(data, ent); // link it into the bsp tree if (!ent.free) { Server.LinkEdict(ent, false); } } entnum++; sb.Remove(0, length); } } Server.sv.num_edicts = entnum; Server.sv.time = time; for (int i = 0; i < Server.NUM_SPAWN_PARMS; i++) { Server.svs.clients[0].spawn_parms[i] = spawn_parms[i]; } } if (Client.cls.state != cactive_t.ca_dedicated) { Client.EstablishConnection("local"); Reconnect_f(); } }