/// <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> /// Since memory block containing original edict_t plus additional data /// is split into two fiels - edict_t.v and edict_t.fields we must check key.ofs /// to choose between thistwo parts. /// Warning: Key offset is in integers not bytes! /// </summary> static unsafe bool ParsePair(edict_t ent, ddef_t key, string s) { int offset1; if (ent.IsV(key.ofs, out offset1)) { fixed (entvars_t* ptr = &ent.v) { return ParsePair((int*)ptr + offset1, key, s); } } else fixed (float* ptr = ent.fields) { return ParsePair(ptr + offset1, key, s); } }
/// <summary> /// ED_ParseEpair /// Can parse either fields or globals returns false if error /// Uze: Warning! value pointer is already with correct offset (value = base + key.ofs)! /// </summary> static unsafe bool ParsePair(void* value, ddef_t key, string s) { void* d = value;// (void *)((int *)base + key->ofs); switch ((etype_t)(key.type & ~DEF_SAVEGLOBAL)) { case etype_t.ev_string: *(int*)d = NewString(s);// - pr_strings; break; case etype_t.ev_float: *(float*)d = Common.atof(s); break; case etype_t.ev_vector: string[] vs = s.Split(' '); ((float*)d)[0] = Common.atof(vs[0]); ((float*)d)[1] = (vs.Length > 1 ? Common.atof(vs[1]) : 0); ((float*)d)[2] = (vs.Length > 2 ? Common.atof(vs[2]) : 0); break; case etype_t.ev_entity: *(int*)d = Server.EdictToProg(Server.EdictNum(Common.atoi(s))); break; case etype_t.ev_field: int f = IndexOfField(s); if (f == -1) { Con.Print("Can't find field {0}\n", s); return false; } *(int*)d = GetInt32(_FieldDefs[f].ofs); break; case etype_t.ev_function: int func = IndexOfFunction(s); if (func == -1) { Con.Print("Can't find function {0}\n", s); return false; } *(int*)d = func;// - pr_functions; break; default: break; } return true; }
static unsafe bool ParseGlobalPair(ddef_t key, string value) { int offset; if (IsGlobalStruct(key.ofs, out offset)) { return ParsePair((float*)_GlobalStructAddr + offset, key, value); } return ParsePair((float*)_GlobalsAddr + offset, key, value); }