// This reads the vertices private Dictionary <int, Vertex> ReadVertices(MapSet map, UniversalParser textmap) { Dictionary <int, Vertex> link; // Get list of entries List <UniversalCollection> collections = GetNamedCollections(textmap.Root, "vertex"); // Create lookup table link = new Dictionary <int, Vertex>(collections.Count); // Go for all collections map.SetCapacity(map.Vertices.Count + collections.Count, 0, 0, 0, 0); for (int i = 0; i < collections.Count; i++) { // Read fields UniversalCollection c = collections[i]; string where = "vertex " + i; float x = GetCollectionEntry <float>(c, "x", true, 0.0f, where); float y = GetCollectionEntry <float>(c, "y", true, 0.0f, where); // Create new item Vertex v = map.CreateVertex(new Vector2D(x, y)); if (v != null) { // Custom fields ReadCustomFields(c, v, "vertex"); // Add it to the lookup table link.Add(i, v); } } // Return lookup table return(link); }
// This will load a configuration from string public bool InputConfiguration(string data) { // Remove returns and tabs because the // parser only uses newline for new lines. data = data.Replace("\r", ""); data = data.Replace("\t", ""); // Clear errors ClearError(); // Parse the data to the root structure int pos = 0; int line = 1; root = InputStructure(ref data, ref pos, ref line); // Return true when done, false when errors occurred if (cpErrorResult == 0) { return(true); } else { return(false); } }
// This reads a single sidedef and connects it to the given linedef private void ReadSidedef(MapSet map, UniversalCollection sc, Linedef ld, bool front, Dictionary <int, Sector> sectorlink, int index) { // Read fields string where = "linedef " + ld.Index + (front ? " front sidedef " : " back sidedef ") + index; int offsetx = GetCollectionEntry <int>(sc, "offsetx", false, 0, where); int offsety = GetCollectionEntry <int>(sc, "offsety", false, 0, where); string thigh = GetCollectionEntry <string>(sc, "texturetop", false, "-", where); string tlow = GetCollectionEntry <string>(sc, "texturebottom", false, "-", where); string tmid = GetCollectionEntry <string>(sc, "texturemiddle", false, "-", where); int sector = GetCollectionEntry <int>(sc, "sector", true, 0, where); // Create sidedef if (sectorlink.ContainsKey(sector)) { Sidedef s = map.CreateSidedef(ld, front, sectorlink[sector]); if (s != null) { s.Update(offsetx, offsety, thigh, tmid, tlow); // Custom fields ReadCustomFields(sc, s, "sidedef"); } } else { General.ErrorLogger.Add(ErrorType.Warning, "Sidedef references invalid sector " + sector + ". Sidedef has been removed."); } }
// This adds sectors private void WriteSectors(ICollection <Sector> sectors, UniversalParser textmap) { // Go for all sectors foreach (Sector s in sectors) { // Make collection UniversalCollection coll = new UniversalCollection(); coll.Add("heightfloor", s.FloorHeight); coll.Add("heightceiling", s.CeilHeight); coll.Add("texturefloor", s.FloorTexture); coll.Add("textureceiling", s.CeilTexture); coll.Add("lightlevel", s.Brightness); if (s.Effect != 0) { coll.Add("special", s.Effect); } if (s.Tag != 0) { coll.Add("id", s.Tag); } coll.Comment = s.Index.ToString(); // Add custom fields AddCustomFields(s, "sector", coll); // Store textmap.Root.Add("sector", coll); } }
// This adds vertices private void WriteVertices(ICollection <Vertex> vertices, UniversalParser textmap) { // Go for all vertices foreach (Vertex v in vertices) { // Make collection UniversalCollection coll = new UniversalCollection(); coll.Add("x", v.Position.x); coll.Add("y", v.Position.y); if (!float.IsNaN(v.ZCeiling)) { coll.Add("zceiling", v.ZCeiling); //mxd } if (!float.IsNaN(v.ZFloor)) { coll.Add("zfloor", v.ZFloor); //mxd } coll.Comment = v.Index.ToString(); // Add custom fields AddCustomFields(v, "vertex", coll); // Store textmap.Root.Add("vertex", coll); } }
// ano - this returns all the unidentified data for preservation private void ReadUnidentifiedEntries(MapSet map, UniversalParser textmap) { UniversalCollection root = textmap.Root; UniversalCollection unidentified = new UniversalCollection(); foreach (UniversalEntry e in root) { switch (e.Key) { case "namespace": case "vertex": case "thing": case "linedef": case "sector": case "sidedef": break; default: unidentified.Add(e); break; } // switch } // foreach map.UnidentifiedUDMF = unidentified; } // ReadUnidentifiedEntries
// This reads the sectors private Dictionary <int, Sector> ReadSectors(MapSet map, UniversalParser textmap) { Dictionary <int, Sector> link; // Get list of entries List <UniversalCollection> collections = GetNamedCollections(textmap.Root, "sector"); // Create lookup table link = new Dictionary <int, Sector>(collections.Count); // Go for all collections map.SetCapacity(0, 0, 0, map.Sectors.Count + collections.Count, 0); for (int i = 0; i < collections.Count; i++) { // Read fields UniversalCollection c = collections[i]; string where = "sector " + i; int[] colors = new int[Sector.NUM_COLORS]; int hfloor = GetCollectionEntry <int>(c, "heightfloor", false, 0, where); int hceil = GetCollectionEntry <int>(c, "heightceiling", false, 0, where); string tfloor = GetCollectionEntry <string>(c, "texturefloor", true, "-", where); string tceil = GetCollectionEntry <string>(c, "textureceiling", true, "-", where); int bright = GetCollectionEntry <int>(c, "lightlevel", false, 160, where); int special = GetCollectionEntry <int>(c, "special", false, 0, where); int tag = GetCollectionEntry <int>(c, "id", false, 0, where); // villsa 9/14/11 (builder64) colors[0] = GetCollectionEntry <int>(c, "color1", false, 0, where); colors[1] = GetCollectionEntry <int>(c, "color2", false, 0, where); colors[2] = GetCollectionEntry <int>(c, "color3", false, 0, where); colors[3] = GetCollectionEntry <int>(c, "color4", false, 0, where); colors[4] = GetCollectionEntry <int>(c, "color5", false, 0, where); // villsa 9/13/11 - Flags Dictionary <string, bool> stringflags = new Dictionary <string, bool>(); foreach (KeyValuePair <string, string> flag in General.Map.Config.SectorFlags) { stringflags[flag.Key] = GetCollectionEntry <bool>(c, flag.Key, false, false, where); } // Create new item Sector s = map.CreateSector(); if (s != null) { s.Update(stringflags, hfloor, hceil, tfloor, tceil, special, tag, colors); // Custom fields ReadCustomFields(c, s, "sector"); // Add it to the lookup table link.Add(i, s); } } // Return lookup table return(link); }
// This reads the things private void ReadThings(MapSet map, UniversalParser textmap) { // Get list of entries List <UniversalCollection> collections = GetNamedCollections(textmap.Root, "thing"); // Go for all collections map.SetCapacity(0, 0, 0, 0, map.Things.Count + collections.Count); for (int i = 0; i < collections.Count; i++) { // Read fields UniversalCollection c = collections[i]; int[] args = new int[Linedef.NUM_ARGS]; string where = "thing " + i; float x = GetCollectionEntry <float>(c, "x", true, 0.0f, where); float y = GetCollectionEntry <float>(c, "y", true, 0.0f, where); float height = GetCollectionEntry <float>(c, "height", false, 0.0f, where); int tag = GetCollectionEntry <int>(c, "id", false, 0, where); int angledeg = GetCollectionEntry <int>(c, "angle", false, 0, where); int type = GetCollectionEntry <int>(c, "type", true, 0, where); int special = GetCollectionEntry <int>(c, "special", false, 0, where); args[0] = GetCollectionEntry <int>(c, "arg0", false, 0, where); args[1] = GetCollectionEntry <int>(c, "arg1", false, 0, where); args[2] = GetCollectionEntry <int>(c, "arg2", false, 0, where); args[3] = GetCollectionEntry <int>(c, "arg3", false, 0, where); args[4] = GetCollectionEntry <int>(c, "arg4", false, 0, where); // Flags Dictionary <string, bool> stringflags = new Dictionary <string, bool>(); foreach (KeyValuePair <string, string> flag in General.Map.Config.ThingFlags) { stringflags[flag.Key] = GetCollectionEntry <bool>(c, flag.Key, false, false, where); } foreach (FlagTranslation ft in General.Map.Config.ThingFlagsTranslation) { foreach (string field in ft.Fields) { stringflags[field] = GetCollectionEntry <bool>(c, field, false, false, where); } } // Create new item Thing t = map.CreateThing(); if (t != null) { t.Update(type, x, y, height, angledeg, stringflags, tag, special, args); // Custom fields ReadCustomFields(c, t, "thing"); } } }
// This validates and returns an entry private T GetCollectionEntry <T>(UniversalCollection c, string entryname, bool required, T defaultvalue, string where) { T result = default(T); bool found = false; // Find the entry foreach (UniversalEntry e in c) { // Check if matches if (e.Key == entryname) { // Let's be kind and cast any int to a float if needed if ((typeof(T) == typeof(float)) && (e.Value.GetType() == typeof(int))) { // Make it a float object fvalue = (float)(int)e.Value; result = (T)fvalue; } else { // Verify type e.ValidateType(typeof(T)); // Found it! result = (T)e.Value; } // Done found = true; } } // Not found? if (!found) { // Report error when entry is required! if (required) { General.ErrorLogger.Add(ErrorType.Error, "Error while reading UDMF map data: Missing required field '" + entryname + "' at " + where + "."); } // Make default entry result = defaultvalue; } // Return result return(result); }
// This makes a list of all collections with the given name private List <UniversalCollection> GetNamedCollections(UniversalCollection collection, string entryname) { List <UniversalCollection> list = new List <UniversalCollection>(); // Make list foreach (UniversalEntry e in collection) { if ((e.Value is UniversalCollection) && (e.Key == entryname)) { list.Add(e.Value as UniversalCollection); } } return(list); }
// This makes a list of all collections with the given name private static List <UniversalCollection> GetNamedCollections(UniversalCollection collection, string entryname) { List <UniversalCollection> list = new List <UniversalCollection>(); // Make list foreach (UniversalEntry e in collection) { UniversalCollection uc = e.Value as UniversalCollection; if (uc != null && e.Key == entryname) { list.Add(uc); } } return(list); }
// This will load a configuration from string public bool InputConfiguration(string[] data) { // Clear errors ClearError(); // Parse the data to the root structure int pos = 0; int line = 0; //mxd matches = new Dictionary <string, UniversalEntry>(StringComparer.Ordinal); //mxd key = new StringBuilder(16); //mxd val = new StringBuilder(16); //mxd root = InputStructure(ref data, ref pos, ref line, true); // Return true when done, false when errors occurred return(cpErrorResult == 0); }
// This adds sectors private void WriteSectors(ICollection <Sector> sectors, UniversalParser textmap) { // Go for all sectors foreach (Sector s in sectors) { // Make collection UniversalCollection coll = new UniversalCollection(); coll.Add("heightfloor", s.FloorHeight); coll.Add("heightceiling", s.CeilHeight); coll.Add("texturefloor", s.FloorTexture); coll.Add("textureceiling", s.CeilTexture); coll.Add("lightlevel", s.Brightness); if (s.Effect != 0) { coll.Add("special", s.Effect); } if (s.Tag != 0) { coll.Add("id", s.Tag); } // villsa 9/14/11 (builder64) coll.Add("color1", s.FloorColor.color.ToInt()); coll.Add("color2", s.CeilColor.color.ToInt()); coll.Add("color3", s.ThingColor.color.ToInt()); coll.Add("color4", s.TopColor.color.ToInt()); coll.Add("color5", s.LowerColor.color.ToInt()); // villsa 9/13/11 - Flags foreach (KeyValuePair <string, bool> flag in s.Flags) { if (flag.Value) { coll.Add(flag.Key, flag.Value); } } coll.Comment = s.Index.ToString(); // Add custom fields AddCustomFields(s, "sector", coll); // Store textmap.Root.Add("sector", coll); } }
// This adds sidedefs private void WriteSidedefs(ICollection <Sidedef> sidedefs, UniversalParser textmap, IDictionary <Sector, int> sectorids) { // Go for all sidedefs foreach (Sidedef s in sidedefs) { // Make collection UniversalCollection coll = new UniversalCollection(); if (s.OffsetX != 0) { coll.Add("offsetx", s.OffsetX); } if (s.OffsetY != 0) { coll.Add("offsety", s.OffsetY); } if (s.LongHighTexture != MapSet.EmptyLongName) { coll.Add("texturetop", s.HighTexture); } if (s.LongLowTexture != MapSet.EmptyLongName) { coll.Add("texturebottom", s.LowTexture); } if (s.LongMiddleTexture != MapSet.EmptyLongName) { coll.Add("texturemiddle", s.MiddleTexture); } coll.Add("sector", sectorids[s.Sector]); coll.Comment = s.Index.ToString(); //mxd. Flags foreach (KeyValuePair <string, bool> flag in s.Flags) { if (flag.Value) { coll.Add(flag.Key, flag.Value); } } // Add custom fields AddCustomFields(s, "sidedef", coll); // Store textmap.Root.Add("sidedef", coll); } }
// This reads the vertices private Dictionary <int, Vertex> ReadVertices(MapSet map, UniversalParser textmap) { // Get list of entries List <UniversalCollection> collections = GetNamedCollections(textmap.Root, "vertex"); // Create lookup table Dictionary <int, Vertex> link = new Dictionary <int, Vertex>(collections.Count); // Go for all collections map.SetCapacity(map.Vertices.Count + collections.Count, 0, 0, 0, 0); for (int i = 0; i < collections.Count; i++) { // Read fields UniversalCollection c = collections[i]; string where = "vertex " + i; float x = GetCollectionEntry(c, "x", true, 0.0f, where); float y = GetCollectionEntry(c, "y", true, 0.0f, where); // [ZZ] Correct location if it's NaN. Note that there cannot be any meaningful value here, so I just reset it to 0,0 to avoid triggering the NaN exception // TODO: remove once the cause of NaN is reported if (float.IsNaN(x) || float.IsNaN(y)) { x = y = 0f; General.ErrorLogger.Add(ErrorType.Warning, string.Format("Vertex {0} has NaN coordinates, resetting to 0,0", i)); } // Create new item Vertex v = map.CreateVertex(new Vector2D(x, y)); if (v != null) { //mxd. zoffsets v.ZCeiling = GetCollectionEntry(c, "zceiling", false, float.NaN, where); //mxd v.ZFloor = GetCollectionEntry(c, "zfloor", false, float.NaN, where); //mxd // Custom fields ReadCustomFields(c, v, "vertex"); // Add it to the lookup table link.Add(i, v); } } // Return lookup table return(link); }
// This adds vertices private void WriteVertices(ICollection <Vertex> vertices, UniversalParser textmap) { // Go for all vertices foreach (Vertex v in vertices) { // Make collection UniversalCollection coll = new UniversalCollection(); coll.Add("x", v.Position.x); coll.Add("y", v.Position.y); coll.Comment = v.Index.ToString(); // Add custom fields AddCustomFields(v, "vertex", coll); // Store textmap.Root.Add("vertex", coll); } }
// This adds custom fields from a map element to a collection private void AddCustomFields(MapElement element, string elementname, UniversalCollection collection) { // Add custom fields foreach (KeyValuePair <string, UniValue> f in element.Fields) { // Not a managed field? if (!config.SettingExists("managedfields." + elementname + "." + f.Key)) { // Add type information to DBS file for map if (remembercustomtypes) { General.Map.Options.SetUniversalFieldType(elementname, f.Key, f.Value.Type); } // Store field collection.Add(f.Key, f.Value.Value); } } }
// This reads the sectors private Dictionary <int, Sector> ReadSectors(MapSet map, UniversalParser textmap) { Dictionary <int, Sector> link; // Get list of entries List <UniversalCollection> collections = GetNamedCollections(textmap.Root, "sector"); // Create lookup table link = new Dictionary <int, Sector>(collections.Count); // Go for all collections map.SetCapacity(0, 0, 0, map.Sectors.Count + collections.Count, 0); for (int i = 0; i < collections.Count; i++) { // Read fields UniversalCollection c = collections[i]; string where = "sector " + i; int hfloor = GetCollectionEntry <int>(c, "heightfloor", false, 0, where); int hceil = GetCollectionEntry <int>(c, "heightceiling", false, 0, where); string tfloor = GetCollectionEntry <string>(c, "texturefloor", true, "-", where); string tceil = GetCollectionEntry <string>(c, "textureceiling", true, "-", where); int bright = GetCollectionEntry <int>(c, "lightlevel", false, 160, where); int special = GetCollectionEntry <int>(c, "special", false, 0, where); int tag = GetCollectionEntry <int>(c, "id", false, 0, where); // Create new item Sector s = map.CreateSector(); if (s != null) { s.Update(hfloor, hceil, tfloor, tceil, special, tag, bright); // Custom fields ReadCustomFields(c, s, "sector"); // Add it to the lookup table link.Add(i, s); } } // Return lookup table return(link); }
// This reads custom fields from a collection and adds them to a map element private void ReadCustomFields(UniversalCollection collection, MapElement element, string elementname) { element.Fields.BeforeFieldsChange(); // Go for all the elements in the collection foreach (UniversalEntry e in collection) { // Check if not a managed field if (!config.SettingExists("managedfields." + elementname + "." + e.Key)) { int type = (int)UniversalType.Integer; // Determine default type if (e.Value.GetType() == typeof(int)) { type = (int)UniversalType.Integer; } else if (e.Value.GetType() == typeof(float)) { type = (int)UniversalType.Float; } else if (e.Value.GetType() == typeof(bool)) { type = (int)UniversalType.Boolean; } else if (e.Value.GetType() == typeof(string)) { type = (int)UniversalType.String; } // Try to find the type from configuration if (setknowncustomtypes) { type = General.Map.Options.GetUniversalFieldType(elementname, e.Key, type); } // Make custom field element.Fields[e.Key] = new UniValue(type, e.Value); } } }
// This adds things private void WriteThings(ICollection <Thing> things, UniversalParser textmap) { // Go for all things foreach (Thing t in things) { // Make collection UniversalCollection coll = new UniversalCollection(); if (t.Tag != 0) { coll.Add("id", t.Tag); } coll.Add("x", t.Position.x); coll.Add("y", t.Position.y); if (t.Position.z != 0.0f) { coll.Add("height", (float)t.Position.z); } coll.Add("angle", t.AngleDoom); coll.Add("type", t.Type); if (t.Action != 0) { coll.Add("special", t.Action); } if (t.Args[0] != 0) { coll.Add("arg0", t.Args[0]); } if (t.Args[1] != 0) { coll.Add("arg1", t.Args[1]); } if (t.Args[2] != 0) { coll.Add("arg2", t.Args[2]); } if (t.Args[3] != 0) { coll.Add("arg3", t.Args[3]); } if (t.Args[4] != 0) { coll.Add("arg4", t.Args[4]); } coll.Comment = t.Index.ToString(); // Flags foreach (KeyValuePair <string, bool> flag in t.Flags) { if (flag.Value) { coll.Add(flag.Key, flag.Value); } } // Add custom fields AddCustomFields(t, "thing", coll); // Store textmap.Root.Add("thing", coll); } }
// This writes the structures to a stream // NOTE: writenamespace may be null to omit writing the namespace to the stream. // NOTE: The given structures must be complete, with the exception of the sidedefs. // If there are missing sidedefs, their reference will be removed from the linedefs. public void Write(ICollection <Vertex> vertices, ICollection <Linedef> linedefs, ICollection <Sidedef> sidedefs, ICollection <Sector> sectors, ICollection <Thing> things, Stream stream, string writenamespace, UniversalCollection unidentified = null) { UniversalParser textmap = new UniversalParser(); // Begin with fields that must be at the top if (writenamespace != null) { textmap.Root.Add("namespace", writenamespace); } // ano - write unidentified fields to be preserved here if (unidentified != null) { foreach (UniversalEntry entry in unidentified) { textmap.Root.Add(entry); } } Dictionary <Vertex, int> vertexids = new Dictionary <Vertex, int>(); Dictionary <Sidedef, int> sidedefids = new Dictionary <Sidedef, int>(); Dictionary <Sector, int> sectorids = new Dictionary <Sector, int>(); // Index the elements in the data structures foreach (Vertex v in vertices) { vertexids.Add(v, vertexids.Count); } foreach (Sidedef sd in sidedefs) { sidedefids.Add(sd, sidedefids.Count); } foreach (Sector s in sectors) { sectorids.Add(s, sectorids.Count); } // If we write the custom field types again, then forget // all previous field types (this gets rid of unused field types) if (remembercustomtypes) { General.Map.Options.ForgetUniversalFieldTypes(); } // Write the data structures to textmap WriteVertices(vertices, textmap); WriteLinedefs(linedefs, textmap, sidedefids, vertexids); WriteSidedefs(sidedefs, textmap, sectorids); WriteSectors(sectors, textmap); WriteThings(things, textmap); // Get the textmap as string string textmapstr = textmap.OutputConfiguration(); // Write to stream StreamWriter writer = new StreamWriter(stream, Encoding.ASCII); writer.Write(textmapstr); writer.Flush(); }
// This adds linedefs private void WriteLinedefs(ICollection <Linedef> linedefs, UniversalParser textmap, IDictionary <Sidedef, int> sidedefids, IDictionary <Vertex, int> vertexids) { // Go for all linedefs foreach (Linedef l in linedefs) { // Make collection UniversalCollection coll = new UniversalCollection(); if (l.Tag != 0) { coll.Add("id", l.Tag); } coll.Add("v1", vertexids[l.Start]); coll.Add("v2", vertexids[l.End]); coll.Comment = l.Index.ToString(); // Sidedef references if ((l.Front != null) && sidedefids.ContainsKey(l.Front)) { coll.Add("sidefront", sidedefids[l.Front]); } else { coll.Add("sidefront", -1); } if ((l.Back != null) && sidedefids.ContainsKey(l.Back)) { coll.Add("sideback", sidedefids[l.Back]); } else { coll.Add("sideback", -1); } // Special if (l.Action != 0) { coll.Add("special", l.Action); } if (l.Args[0] != 0) { coll.Add("arg0", l.Args[0]); } if (l.Args[1] != 0) { coll.Add("arg1", l.Args[1]); } if (l.Args[2] != 0) { coll.Add("arg2", l.Args[2]); } if (l.Args[3] != 0) { coll.Add("arg3", l.Args[3]); } if (l.Args[4] != 0) { coll.Add("arg4", l.Args[4]); } // Flags foreach (KeyValuePair <string, bool> flag in l.Flags) { if (flag.Value) { coll.Add(flag.Key, flag.Value); } } // Add custom fields AddCustomFields(l, "linedef", coll); // Store textmap.Root.Add("linedef", coll); } }
// This creates a new configuration public void NewConfiguration() { // Create new configuration root = new UniversalCollection(); }
// This will create a data structure from the given object private string OutputStructure(UniversalCollection cs, int level, string newline, bool whitespace) { string leveltabs = ""; string spacing = ""; StringBuilder db = new StringBuilder(""); // Check if this ConfigStruct is not empty if (cs.Count > 0) { // Create whitespace if (whitespace) { for (int i = 0; i < level; i++) { leveltabs += "\t"; } spacing = " "; } // Go for each item for (int i = 0; i < cs.Count; i++) { // Check if the value if of collection type if (cs[i].Value is UniversalCollection) { UniversalCollection c = (UniversalCollection)cs[i].Value; // Output recursive structure if (whitespace) { db.Append(leveltabs); db.Append(newline); } db.Append(leveltabs); db.Append(cs[i].Key); if (!string.IsNullOrEmpty(c.Comment)) { if (whitespace) { db.Append("\t"); } db.Append("// " + c.Comment); } db.Append(newline); db.Append(leveltabs); db.Append("{"); db.Append(newline); db.Append(OutputStructure(c, level + 1, newline, whitespace)); db.Append(leveltabs); db.Append("}"); db.Append(newline); //if(whitespace) { db.Append(leveltabs); db.Append(newline); } //mxd. Let's save a few Kbs by using single line breaks... } // Check if the value is of boolean type else if (cs[i].Value is bool) { db.Append(leveltabs); db.Append(cs[i].Key); db.Append(spacing); db.Append("="); db.Append(spacing); db.Append((bool)cs[i].Value ? "true;" : "false;"); db.Append(newline); } // Check if value is of float type else if (cs[i].Value is float) { // Output the value as float (3 decimals) float f = (float)cs[i].Value; db.Append(leveltabs); db.Append(cs[i].Key); db.Append(spacing); db.Append("="); db.Append(spacing); db.Append(f.ToString("0.000", CultureInfo.InvariantCulture)); db.Append(";"); db.Append(newline); } //mxd. Check if value is of double type else if (cs[i].Value is double) { // Output the value as double (7 decimals) double d = (double)cs[i].Value; db.Append(leveltabs); db.Append(cs[i].Key); db.Append(spacing); db.Append("="); db.Append(spacing); db.Append(d.ToString("0.0##############", CultureInfo.InvariantCulture)); /* db.Append(d.ToString("0.0000000", CultureInfo.InvariantCulture)); */ db.Append(";"); db.Append(newline); } // Check if value is of other numeric type else if (cs[i].Value.GetType().IsPrimitive) { // Output the value unquoted db.Append(leveltabs); db.Append(cs[i].Key); db.Append(spacing); db.Append("="); db.Append(spacing); db.Append(String.Format(CultureInfo.InvariantCulture, "{0}", cs[i].Value)); db.Append(";"); db.Append(newline); } else { // Output the value with quotes and escape characters db.Append(leveltabs); db.Append(cs[i].Key); db.Append(spacing); db.Append("="); db.Append(spacing); db.Append("\""); db.Append(EscapedString(cs[i].Value.ToString())); db.Append("\";"); db.Append(newline); } } } // Return the structure return(db.ToString()); }
// This parses a structure in the given data starting // from the given pos and line and updates pos and line. private UniversalCollection InputStructure(ref string[] data, ref int pos, ref int line, bool topLevel) { int pm = PM_NOTHING; // current parse mode key.Remove(0, key.Length); val.Remove(0, val.Length); bool escape = false; // escape sequence? bool endofstruct = false; // true as soon as this level struct ends UniversalCollection cs = new UniversalCollection(); // Go through all of the data until // the end or until the struct closes // or when an arror occurred while ((cpErrorResult == 0) && (endofstruct == false)) { // Get current character if (line == data.Length - 1) { break; } if (pos > data[line].Length - 1) { pos = 0; line++; if (string.IsNullOrEmpty(data[line])) { continue; //mxd. Skip empty lines here so correct line number is displayed on errors } } char c = data[line][pos]; // current data character // ================ What parse mode are we at? if (pm == PM_NOTHING) { // Now check what character this is switch (c) { case '{': // Begin of new struct // Validate key string s = key.ToString().Trim(); if (ValidateKey(s, line)) { // Next character pos++; // Parse this struct and add it cs.Add(new UniversalEntry(s.ToLowerInvariant(), InputStructure(ref data, ref pos, ref line, false))); // Check the last character pos--; // Reset the key key.Remove(0, key.Length); } // Leave switch break; case '}': // End of this struct // Stop parsing in this struct endofstruct = true; // Leave the loop break; case '=': // Assignment // Validate key if (ValidateKey(key.ToString().Trim(), line)) { // Now parsing assignment pm = PM_ASSIGNMENT; } // Leave switch break; case ';': // Terminator // Validate key if (ValidateKey(key.ToString().Trim(), line)) { // Error: No value RaiseError(line, ERROR_KEYWITHOUTVALUE); } // Leave switch break; case '\n': // New line // Count the line line++; pos = -1; // Add this to the key as a space. // Spaces are not allowed, but it will be trimmed // when its the first or last character. key.Append(" "); // Leave switch break; case '\\': // Possible comment case '/': // Check for the line comment // if (data[line].Substring(pos, 2) == "//") { // Skip everything on this line pos = -1; // Have next line? if (line < data.Length - 1) { line++; } } // Check for the block comment /* */ else if (data[line].Substring(pos, 2) == "/*") { // Block comment closes on the same line?.. (mxd) int np = data[line].IndexOf("*/", pos); if (np > -1) { pos = np + 1; } else { // Find the next closing block comment line++; while ((np = data[line].IndexOf("*/", 0)) == -1) { if (line == data.Length - 1) { break; } line++; } // Closing block comment found? if (np > -1) { // Skip everything in this block pos = np + 1; } } } // Leave switch break; default: // Everything else if (!topLevel && pos == 0) { while (matches.ContainsKey(data[line])) { cs.Add(matches[data[line]].Key, matches[data[line]].Value); line++; pos = -1; } } // Add character to key if (pos != -1) { key.Append(c); } // Leave switch break; } } // ================ Parsing an assignment else if (pm == PM_ASSIGNMENT) { // Check for string opening if (c == '\"') { // Now parsing string pm = PM_STRING; //numbers } // Check for numeric character numbers else if (Configuration.NUMBERS2.IndexOf(c) > -1) { // Now parsing number pm = PM_NUMBER; // Go one byte back, because this // byte is part of the number! pos--; } // Check for new line else if (c == '\n') { // Count the new line line++; } // Check if assignment ends else if (c == ';') { // End of assignment pm = PM_NOTHING; // Remove this if it causes problems key.Remove(0, key.Length); val.Remove(0, val.Length); } // Otherwise (if not whitespace) it will be a keyword else if ((c != ' ') && (c != '\t')) { // Now parsing a keyword pm = PM_KEYWORD; // Go one byte back, because this // byte is part of the keyword! pos--; } } // ================ Parsing a number else if (pm == PM_NUMBER) { // Check if number ends here if (c == ';') { // Hexadecimal? string s = val.ToString(); if ((s.Length > 2) && s.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { // Convert to int try { // Convert to value int ival = Convert.ToInt32(s.Substring(2).Trim(), 16); // Add it to struct UniversalEntry entry = new UniversalEntry(key.ToString().Trim().ToLowerInvariant(), ival); cs.Add(entry); if (!matches.ContainsKey(data[line])) { matches.Add(data[line], entry); } } catch (OverflowException) { // Too large for Int32, try Int64 try { // Convert to value long lval = Convert.ToInt64(s.Substring(2).Trim(), 16); // Add it to struct UniversalEntry entry = new UniversalEntry(key.ToString().Trim().ToLowerInvariant(), lval); cs.Add(entry); if (!matches.ContainsKey(data[line])) { matches.Add(data[line], entry); } } catch (OverflowException) { // Too large for Int64, return error RaiseError(line, ERROR_VALUETOOBIG); } catch (FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\""); } } catch (FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\""); } } // Floating point? //mxd. Can be in scientific notation (like "1E-06") else if (s.IndexOf('.') > -1 || s.ToLowerInvariant().Contains("e-")) { double fval = 0; // Convert to float (remove the f first) try { fval = Convert.ToDouble(s.Trim(), CultureInfo.InvariantCulture); } catch (FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\""); } // Add it to struct UniversalEntry entry = new UniversalEntry(key.ToString().Trim().ToLowerInvariant(), fval); cs.Add(entry); if (!matches.ContainsKey(data[line])) { matches.Add(data[line], entry); } } else { // Convert to int try { // Convert to value int ival = Convert.ToInt32(s.Trim(), CultureInfo.InvariantCulture); // Add it to struct UniversalEntry entry = new UniversalEntry(key.ToString().Trim().ToLowerInvariant(), ival); cs.Add(entry); if (!matches.ContainsKey(data[line])) { matches.Add(data[line], entry); } } catch (OverflowException) { // Too large for Int32, try Int64 try { // Convert to value long lval = Convert.ToInt64(s.Trim(), CultureInfo.InvariantCulture); // Add it to struct UniversalEntry entry = new UniversalEntry(key.ToString().Trim().ToLowerInvariant(), lval); cs.Add(entry); if (!matches.ContainsKey(data[line])) { matches.Add(data[line], entry); } } catch (OverflowException) { // Too large for Int64, return error RaiseError(line, ERROR_VALUETOOBIG); } catch (FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\""); } } catch (FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\""); } } // Reset key and value key.Remove(0, key.Length); val.Remove(0, val.Length); // End of assignment pm = PM_NOTHING; } // Check for new line else if (c == '\n') { // Count the new line line++; pos = -1; } // Everything else is part of the value else { val.Append(c); } } // ================ Parsing a string else if (pm == PM_STRING) { // Check if in an escape sequence if (escape) { // What character? switch (c) { case '\\': val.Append('\\'); break; case 'n': val.Append(newline); break; case '\"': val.Append('\"'); break; case 'r': val.Append('\r'); break; case 't': val.Append('\t'); break; default: // Is it a number? if (Configuration.NUMBERS.IndexOf(c) > -1) { int vv = 0; char vc = '0'; // Convert the next 3 characters to a number string v = data[line].Substring(pos, 3); try { vv = Convert.ToInt32(v.Trim(), CultureInfo.InvariantCulture); } catch (FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + v.Trim() + "\""); } // Convert the number to a char try { vc = Convert.ToChar(vv, CultureInfo.InvariantCulture); } catch (FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + v.Trim() + "\""); } // Add the char val.Append(vc); } else { // Add the character as it is val.Append(c); } // Leave switch break; } // End of escape sequence escape = false; } else { // Check for sequence start if (c == '\\') { // Next character is of escape sequence escape = true; } // Check if string ends else if (c == '\"') { // Add string to struct UniversalEntry entry = new UniversalEntry(key.ToString().Trim().ToLowerInvariant(), val.ToString()); cs.Add(entry); if (!matches.ContainsKey(data[line])) { matches.Add(data[line], entry); } // End of assignment pm = PM_ASSIGNMENT; // Reset key and value key.Remove(0, key.Length); val.Remove(0, val.Length); } // Check for new line else if (c == '\n') { // Count the new line line++; pos = -1; } // Everything else is just part of string else { // Add to value val.Append(c); } } } // ================ Parsing a keyword else if (pm == PM_KEYWORD) { // Check if keyword ends if (c == ';') { // Add to the struct depending on the keyword switch (val.ToString().Trim().ToLowerInvariant()) { case "true": // Add boolean true UniversalEntry t = new UniversalEntry(key.ToString().Trim().ToLowerInvariant(), true); cs.Add(t); if (!matches.ContainsKey(data[line])) { matches.Add(data[line], t); } break; case "false": // Add boolean false UniversalEntry f = new UniversalEntry(key.ToString().Trim().ToLowerInvariant(), false); cs.Add(f); if (!matches.ContainsKey(data[line])) { matches.Add(data[line], f); } break; case "nan": // Add float value UniversalEntry nan = new UniversalEntry(key.ToString().Trim().ToLowerInvariant(), double.NaN); // Do not add NaN, just drop it with a warning // cs.Add(nan); warnings.Add("UDMF map data line " + (line + 1) + ": value of field " + key.ToString().Trim().ToLowerInvariant() + " has a value of NaN (not a number). Field is being dropped permanently."); if (!matches.ContainsKey(data[line])) { matches.Add(data[line], nan); } break; default: // Unknown keyword RaiseError(line, ERROR_KEYWORDUNKNOWN + "\n\nUnrecognized token: \"" + val.ToString().Trim() + "\""); break; } // End of assignment pm = PM_NOTHING; // Reset key and value key.Remove(0, key.Length); val.Remove(0, val.Length); } // Check for new line else if (c == '\n') { // Count the new line line++; pos = -1; } // Everything else is just part of keyword else { // Add to value val.Append(c); } } // Next character pos++; } // Return the parsed result return(cs); }
// This will create a data structure from the given object private string OutputStructure(UniversalCollection cs, int level, string newline, bool whitespace) { string leveltabs = ""; string spacing = ""; StringBuilder db = new StringBuilder(""); // Check if this ConfigStruct is not empty if (cs.Count > 0) { // Create whitespace if (whitespace) { for (int i = 0; i < level; i++) { leveltabs += "\t"; } spacing = " "; } // Get enumerator IEnumerator <UniversalEntry> de = cs.GetEnumerator(); // Go for each item for (int i = 0; i < cs.Count; i++) { // Go to next item de.MoveNext(); // Check if the value if of collection type if (de.Current.Value is UniversalCollection) { UniversalCollection c = (UniversalCollection)de.Current.Value; // Output recursive structure if (whitespace) { db.Append(leveltabs); db.Append(newline); } db.Append(leveltabs); db.Append(de.Current.Key); if (!string.IsNullOrEmpty(c.Comment)) { if (whitespace) { db.Append("\t"); } db.Append("//"); db.Append(c.Comment); } db.Append(newline); db.Append(leveltabs); db.Append("{"); db.Append(newline); db.Append(OutputStructure(c, level + 1, newline, whitespace)); db.Append(leveltabs); db.Append("}"); db.Append(newline); if (whitespace) { db.Append(leveltabs); db.Append(newline); } } // Check if the value is of boolean type else if (de.Current.Value is bool) { // Check value if ((bool)de.Current.Value == true) { // Output the keyword "true" db.Append(leveltabs); db.Append(de.Current.Key); db.Append(spacing); db.Append("="); db.Append(spacing); db.Append("true;"); db.Append(newline); } else { // Output the keyword "false" db.Append(leveltabs); db.Append(de.Current.Key); db.Append(spacing); db.Append("="); db.Append(spacing); db.Append("false;"); db.Append(newline); } } // Check if value is of float type else if (de.Current.Value is float) { // Output the value as float (3 decimals) float f = (float)de.Current.Value; db.Append(leveltabs); db.Append(de.Current.Key); db.Append(spacing); db.Append("="); db.Append(spacing); db.Append(f.ToString("0.000", CultureInfo.InvariantCulture)); db.Append(";"); db.Append(newline); } // Check if value is of other numeric type else if (de.Current.Value.GetType().IsPrimitive) { // Output the value unquoted db.Append(leveltabs); db.Append(de.Current.Key); db.Append(spacing); db.Append("="); db.Append(spacing); db.Append(String.Format(CultureInfo.InvariantCulture, "{0}", de.Current.Value)); db.Append(";"); db.Append(newline); } else { // Output the value with quotes and escape characters db.Append(leveltabs); db.Append(de.Current.Key); db.Append(spacing); db.Append("="); db.Append(spacing); db.Append("\""); db.Append(EscapedString(de.Current.Value.ToString())); db.Append("\";"); db.Append(newline); } } } // Return the structure return(db.ToString()); }
// This parses a structure in the given data starting // from the given pos and line and updates pos and line. private UniversalCollection InputStructure(ref string data, ref int pos, ref int line) { char c = '\0'; // current data character int pm = PM_NOTHING; // current parse mode //string key = "", val = ""; // current key and value beign built bool escape = false; // escape sequence? bool endofstruct = false; // true as soon as this level struct ends UniversalCollection cs = new UniversalCollection(); StringBuilder keysb = new StringBuilder(32); StringBuilder valsb = new StringBuilder(32); // Go through all of the data until // the end or until the struct closes // or when an arror occurred while ((pos < data.Length) && (cpErrorResult == 0) && (endofstruct == false)) { // Get current character c = data[pos]; // ================ What parse mode are we at? if (pm == PM_NOTHING) { // Now check what character this is switch (c) { case '{': // Begin of new struct // Validate key { string key = keysb.ToString().Trim(); if (ValidateKey(key, line)) { // Next character pos++; // Parse this struct and add it cs.Add(new UniversalEntry(key, InputStructure(ref data, ref pos, ref line))); // Check the last character pos--; // Reset the key keysb.Length = 0; } } // Leave switch break; case '}': // End of this struct // Stop parsing in this struct endofstruct = true; // Leave the loop break; case '=': // Assignment // Validate key if (ValidateKey(keysb.ToString().Trim(), line)) { // Now parsing assignment pm = PM_ASSIGNMENT; } // Leave switch break; case ';': // Terminator // Validate key if (ValidateKey(keysb.ToString().Trim(), line)) { // Error: No value RaiseError(line, ERROR_KEYWITHOUTVALUE); } // Leave switch break; case '\n': // New line // Count the line line++; // Add this to the key as a space. // Spaces are not allowed, but it will be trimmed // when its the first or last character. keysb.Append(' '); // Leave switch break; case '\\': // Possible comment case '/': // Check for the line comment // if (data.Substring(pos, 2) == "//") { // Find the next line int np = data.IndexOf("\n", pos); // Next line found? if (np > -1) { // Count the line line++; // Skip everything on this line pos = np; } else { // No end of line // Skip everything else pos = data.Length; } } // Check for the block comment /* */ else if (data.Substring(pos, 2) == "/*") { // Find the next closing block comment int np = data.IndexOf("*/", pos); // Closing block comment found? if (np > -1) { // Count the lines in the block comment string blockdata = data.Substring(pos, np - pos + 2); line += (blockdata.Split("\n".ToCharArray()).Length - 1); // Skip everything in this block pos = np + 1; } else { // No end of line // Skip everything else pos = data.Length; } } // Leave switch break; default: // Everything else // Add character to key keysb.Append(char.ToLowerInvariant(c)); // Leave switch break; } } // ================ Parsing an assignment else if (pm == PM_ASSIGNMENT) { // Check for string opening if (c == '\"') { // Now parsing string pm = PM_STRING; } // Check for numeric character //else if("0123456789-.&".IndexOf(c.ToString(CultureInfo.InvariantCulture)) > -1) else if ((c >= '0' && c <= '9') || c == '&' || c == '-' || c == '.') { // Now parsing number pm = PM_NUMBER; // Go one byte back, because this // byte is part of the number! pos--; } // Check for new line else if (c == '\n') { // Count the new line line++; } // Check if assignment ends else if (c == ';') { // End of assignment pm = PM_NOTHING; // Remove this if it causes problems keysb.Length = 0; valsb.Length = 0; } // Otherwise (if not whitespace) it will be a keyword else if ((c != ' ') && (c != '\t')) { // Now parsing a keyword pm = PM_KEYWORD; // Go one byte back, because this // byte is part of the keyword! pos--; } } // ================ Parsing a number else if (pm == PM_NUMBER) { // Check if number ends here if (c == ';') { string val = valsb.ToString().Trim(); string key = keysb.ToString().Trim(); // Hexadecimal? if ((val.Length > 2) && val.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) { int ival = 0; long lval = 0; // Convert to int try { // Convert to value ival = System.Convert.ToInt32(val.Substring(2), 16); // Add it to struct cs.Add(new UniversalEntry(key, ival)); } catch (System.OverflowException) { // Too large for Int32, try Int64 try { // Convert to value lval = System.Convert.ToInt64(val.Substring(2), 16); // Add it to struct cs.Add(new UniversalEntry(key, lval)); } catch (System.OverflowException) { // Too large for Int64, return error RaiseError(line, ERROR_VALUETOOBIG); } catch (System.FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID); } } catch (System.FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID); } } // Floating point? else if (val.IndexOf(".") > -1) { float fval = 0; // Convert to float (remove the f first) try { fval = System.Convert.ToSingle(val, CultureInfo.InvariantCulture); } catch (System.FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID); } // Add it to struct cs.Add(new UniversalEntry(key, fval)); } else { int ival = 0; long lval = 0; // Convert to int try { // Convert to value ival = System.Convert.ToInt32(val, CultureInfo.InvariantCulture); // Add it to struct cs.Add(new UniversalEntry(key, ival)); } catch (System.OverflowException) { // Too large for Int32, try Int64 try { // Convert to value lval = System.Convert.ToInt64(val, CultureInfo.InvariantCulture); // Add it to struct cs.Add(new UniversalEntry(key, lval)); } catch (System.OverflowException) { // Too large for Int64, return error RaiseError(line, ERROR_VALUETOOBIG); } catch (System.FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID); } } catch (System.FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID); } } // Reset key and value keysb.Length = 0; valsb.Length = 0; // End of assignment pm = PM_NOTHING; } // Check for new line else if (c == '\n') { // Count the new line line++; } // Everything else is part of the value else { valsb.Append(char.ToLowerInvariant(c)); } } // ================ Parsing a string else if (pm == PM_STRING) { // Check if in an escape sequence if (escape) { // What character? switch (c) { case '\\': valsb.Append('\\'); break; case 'n': valsb.Append('\n'); break; case '\"': valsb.Append('\"'); break; case 'r': valsb.Append('\r'); break; case 't': valsb.Append('\t'); break; default: // Is it a number? //if("0123456789".IndexOf(c.ToString(CultureInfo.InvariantCulture)) > -1) if (c >= '0' && c <= '9') { int vv = 0; char vc = '0'; // Convert the next 3 characters to a number string v = data.Substring(pos, 3); try { vv = System.Convert.ToInt32(v.Trim(), CultureInfo.InvariantCulture); } catch (System.FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID); } // Convert the number to a char try { vc = System.Convert.ToChar(vv, CultureInfo.InvariantCulture); } catch (System.FormatException) { // ERROR: Invalid value in assignment RaiseError(line, ERROR_VALUEINVALID); } // Add the char valsb.Append(Char.ToLowerInvariant(vc)); } else { // Add the character as it is valsb.Append(c); } // Leave switch break; } // End of escape sequence escape = false; } else { // Check for sequence start if (c == '\\') { // Next character is of escape sequence escape = true; } // Check if string ends else if (c == '\"') { // Add string to struct cs.Add(new UniversalEntry(keysb.ToString().Trim(), valsb.ToString())); // End of assignment pm = PM_ASSIGNMENT; // Reset key and value keysb.Length = 0; valsb.Length = 0; } // Check for new line else if (c == '\n') { // Count the new line line++; } // Everything else is just part of string else { // Add to value valsb.Append(c); } } } // ================ Parsing a keyword else if (pm == PM_KEYWORD) { // Check if keyword ends if (c == ';') { // Add to the struct depending on the keyword switch (valsb.ToString().Trim().ToLowerInvariant()) { case "true": // Add boolean true cs.Add(new UniversalEntry(keysb.ToString().Trim(), true)); break; case "false": // Add boolean false cs.Add(new UniversalEntry(keysb.ToString().Trim(), false)); break; default: // Unknown keyword RaiseError(line, ERROR_KEYWORDUNKNOWN); break; } // End of assignment pm = PM_NOTHING; // Reset key and value keysb.Length = 0; valsb.Length = 0; } // Check for new line else if (c == '\n') { // Count the new line line++; } // Everything else is just part of keyword else { // Add to value valsb.Append(c); } } // Next character pos++; } // Return the parsed result return(cs); }
// This reads the linedefs and sidedefs private void ReadLinedefs(MapSet map, UniversalParser textmap, Dictionary <int, Vertex> vertexlink, Dictionary <int, Sector> sectorlink) { // Get list of entries List <UniversalCollection> linescolls = GetNamedCollections(textmap.Root, "linedef"); List <UniversalCollection> sidescolls = GetNamedCollections(textmap.Root, "sidedef"); // Go for all lines map.SetCapacity(0, map.Linedefs.Count + linescolls.Count, map.Sidedefs.Count + sidescolls.Count, 0, 0); char[] splitter = { ' ' }; //mxd for (int i = 0; i < linescolls.Count; i++) { // Read fields UniversalCollection lc = linescolls[i]; int[] args = new int[Linedef.NUM_ARGS]; string where = "linedef " + i; int v1 = GetCollectionEntry(lc, "v1", true, 0, where); int v2 = GetCollectionEntry(lc, "v2", true, 0, where); if (!vertexlink.ContainsKey(v1) || !vertexlink.ContainsKey(v2)) { //mxd General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " references one or more invalid vertices. Linedef has been removed."); continue; } int tag = GetCollectionEntry(lc, "id", false, 0, where); int special = GetCollectionEntry(lc, "special", false, 0, where); args[0] = GetCollectionEntry(lc, "arg0", false, 0, where); args[1] = GetCollectionEntry(lc, "arg1", false, 0, where); args[2] = GetCollectionEntry(lc, "arg2", false, 0, where); args[3] = GetCollectionEntry(lc, "arg3", false, 0, where); args[4] = GetCollectionEntry(lc, "arg4", false, 0, where); int s1 = GetCollectionEntry(lc, "sidefront", false, -1, where); int s2 = GetCollectionEntry(lc, "sideback", false, -1, where); //mxd. MoreIDs List <int> tags = new List <int> { tag }; string moreids = GetCollectionEntry(lc, "moreids", false, string.Empty, where); if (!string.IsNullOrEmpty(moreids)) { string[] moreidscol = moreids.Split(splitter, StringSplitOptions.RemoveEmptyEntries); foreach (string sid in moreidscol) { int id; if (int.TryParse(sid.Trim(), out id) && id != 0 && !tags.Contains(id)) { tags.Add(id); } } } if (tag == 0 && tags.Count > 1) { tags.RemoveAt(0); } // Flags Dictionary <string, bool> stringflags = new Dictionary <string, bool>(StringComparer.Ordinal); foreach (KeyValuePair <string, string> flag in General.Map.Config.LinedefFlags) { stringflags[flag.Key] = GetCollectionEntry(lc, flag.Key, false, false, where); } foreach (FlagTranslation ft in General.Map.Config.LinedefFlagsTranslation) { foreach (string field in ft.Fields) { stringflags[field] = GetCollectionEntry(lc, field, false, false, where); } } // Activations foreach (LinedefActivateInfo activate in General.Map.Config.LinedefActivates) { stringflags[activate.Key] = GetCollectionEntry(lc, activate.Key, false, false, where); } // Check if not zero-length if (Vector2D.ManhattanDistance(vertexlink[v1].Position, vertexlink[v2].Position) > 0.0001f) { // Create new linedef Linedef l = map.CreateLinedef(vertexlink[v1], vertexlink[v2]); if (l != null) { l.Update(stringflags, 0, tags, special, args); l.UpdateCache(); // Custom fields ReadCustomFields(lc, l, "linedef"); // Read sidedefs and connect them to the line if (s1 > -1) { if (s1 < sidescolls.Count) { ReadSidedef(map, sidescolls[s1], l, true, sectorlink, s1); } else { General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " references invalid front sidedef " + s1 + ". Sidedef has been removed."); } } if (s2 > -1) { if (s2 < sidescolls.Count) { ReadSidedef(map, sidescolls[s2], l, false, sectorlink, s2); } else { General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " references invalid back sidedef " + s1 + ". Sidedef has been removed."); } } } } else { General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " is zero-length. Linedef has been removed."); } } }
// This reads custom fields from a collection and adds them to a map element private void ReadCustomFields(UniversalCollection collection, MapElement element, string elementname) { element.Fields.BeforeFieldsChange(); // Go for all the elements in the collection foreach (UniversalEntry e in collection) { // mxd. Check if uifield if (uifields.ContainsKey(element.ElementType) && uifields[element.ElementType].ContainsKey(e.Key)) { int type = (int)uifields[element.ElementType][e.Key]; //mxd. Check type object value = e.Value; // Let's be kind and cast any int to a float if needed if (type == (int)UniversalType.Float && e.Value is int) { value = (float)(int)e.Value; } else if (!e.IsValidType(e.Value.GetType())) { General.ErrorLogger.Add(ErrorType.Warning, element + ": the value of entry \"" + e.Key + "\" is of incompatible type (expected " + e.GetType().Name + ", but got " + e.Value.GetType().Name + "). If you save the map, this value will be ignored."); continue; } // Make custom field element.Fields[e.Key] = new UniValue(type, value); } // Check if not a managed field else if (!config.SettingExists("managedfields." + elementname + "." + e.Key)) { int type = (int)UniversalType.Integer; //mxd. Try to find the type from configuration if (setknowncustomtypes) { type = General.Map.Options.GetUniversalFieldType(elementname, e.Key, -1); if (type != -1) { object value = e.Value; // Let's be kind and cast any int to a float if needed if (type == (int)UniversalType.Float && e.Value is int) { value = (float)(int)e.Value; } else if (!e.IsValidType(e.Value.GetType())) { General.ErrorLogger.Add(ErrorType.Warning, element + ": the value of entry \"" + e.Key + "\" is of incompatible type (expected " + e.GetType().Name + ", but got " + e.Value.GetType().Name + "). If you save the map, this value will be ignored."); continue; } // Make custom field element.Fields[e.Key] = new UniValue(type, value); continue; } } // Determine default type if (e.Value is int) { type = (int)UniversalType.Integer; } else if (e.Value is float) { type = (int)UniversalType.Float; } else if (e.Value is bool) { type = (int)UniversalType.Boolean; } else if (e.Value is string) { type = (int)UniversalType.String; } // Make custom field element.Fields[e.Key] = new UniValue(type, e.Value); } } }
// This reads the sectors private Dictionary <int, Sector> ReadSectors(MapSet map, UniversalParser textmap) { // Get list of entries List <UniversalCollection> collections = GetNamedCollections(textmap.Root, "sector"); // Create lookup table Dictionary <int, Sector> link = new Dictionary <int, Sector>(collections.Count); // Go for all collections map.SetCapacity(0, 0, 0, map.Sectors.Count + collections.Count, 0); char[] splitter = new[] { ' ' }; //mxd for (int i = 0; i < collections.Count; i++) { // Read fields UniversalCollection c = collections[i]; string where = "sector " + i; int hfloor = GetCollectionEntry(c, "heightfloor", false, 0, where); int hceil = GetCollectionEntry(c, "heightceiling", false, 0, where); string tfloor = GetCollectionEntry(c, "texturefloor", true, "-", where); string tceil = GetCollectionEntry(c, "textureceiling", true, "-", where); int bright = GetCollectionEntry(c, "lightlevel", false, 160, where); int special = GetCollectionEntry(c, "special", false, 0, where); int tag = GetCollectionEntry(c, "id", false, 0, where); //mxd. MoreIDs List <int> tags = new List <int> { tag }; string moreids = GetCollectionEntry(c, "moreids", false, string.Empty, where); if (!string.IsNullOrEmpty(moreids)) { string[] moreidscol = moreids.Split(splitter, StringSplitOptions.RemoveEmptyEntries); foreach (string sid in moreidscol) { int id; if (int.TryParse(sid.Trim(), out id) && id != 0 && !tags.Contains(id)) { tags.Add(id); } } } if (tag == 0 && tags.Count > 1) { tags.RemoveAt(0); } //mxd. Read slopes float fslopex = GetCollectionEntry(c, "floorplane_a", false, 0.0f, where); float fslopey = GetCollectionEntry(c, "floorplane_b", false, 0.0f, where); float fslopez = GetCollectionEntry(c, "floorplane_c", false, 0.0f, where); float foffset = GetCollectionEntry(c, "floorplane_d", false, float.NaN, where); float cslopex = GetCollectionEntry(c, "ceilingplane_a", false, 0.0f, where); float cslopey = GetCollectionEntry(c, "ceilingplane_b", false, 0.0f, where); float cslopez = GetCollectionEntry(c, "ceilingplane_c", false, 0.0f, where); float coffset = GetCollectionEntry(c, "ceilingplane_d", false, float.NaN, where); //mxd. Read flags Dictionary <string, bool> stringflags = new Dictionary <string, bool>(StringComparer.Ordinal); foreach (KeyValuePair <string, string> flag in General.Map.Config.SectorFlags) { stringflags[flag.Key] = GetCollectionEntry(c, flag.Key, false, false, where); } foreach (KeyValuePair <string, string> flag in General.Map.Config.CeilingPortalFlags) { stringflags[flag.Key] = GetCollectionEntry(c, flag.Key, false, false, where); } foreach (KeyValuePair <string, string> flag in General.Map.Config.FloorPortalFlags) { stringflags[flag.Key] = GetCollectionEntry(c, flag.Key, false, false, where); } // Create new item Sector s = map.CreateSector(); if (s != null) { s.Update(hfloor, hceil, tfloor, tceil, special, stringflags, tags, bright, foffset, new Vector3D(fslopex, fslopey, fslopez).GetNormal(), coffset, new Vector3D(cslopex, cslopey, cslopez).GetNormal()); // Custom fields ReadCustomFields(c, s, "sector"); // Add it to the lookup table link.Add(i, s); } } // Return lookup table return(link); }