UDMF reader/writer: fixed a bug where unknown top level fields and blocks were not preserved. Fixes #627

This commit is contained in:
biwa 2021-10-03 21:04:38 +02:00
parent d8bd7165a7
commit 80e56310a3
3 changed files with 80 additions and 2 deletions

View file

@ -163,6 +163,9 @@ namespace CodeImp.DoomBuilder.IO
Dictionary<int, Sector> sectorlink = ReadSectors(map, textmap);
ReadLinedefs(map, textmap, vertexlink, sectorlink);
ReadThings(map, textmap);
// Read all the stuff we don't know, but have to preserve
map.UnknownUDMFData = GetUnknownCollections(textmap.Root, new List<string>() { "namespace", "vertex", "sector", "linedef", "sidedef", "thing" });
}
// This reads the things
@ -629,6 +632,25 @@ namespace CodeImp.DoomBuilder.IO
return list;
}
/// <summary>
/// Get unknown fields and blocks from an universal collection.
/// </summary>
/// <param name="collection">Universal collection to get the fields and blocks from</param>
/// <param name="knowncollections">List of fields and block that are known and can be ignored</param>
/// <returns></returns>
private static List<UniversalEntry> GetUnknownCollections(UniversalCollection collection, List<string> knowncollections)
{
List<UniversalEntry> list = new List<UniversalEntry>();
// Make list
foreach (UniversalEntry e in collection)
{
if (!knowncollections.Contains(e.Key)) list.Add(e);
}
return list;
}
#endregion
}
}

View file

@ -114,7 +114,7 @@ namespace CodeImp.DoomBuilder.IO
// writenamespace may be null to omit writing the namespace to the stream
public void Write(MapSet map, Stream stream, string writenamespace)
{
Write(map.Vertices, map.Linedefs, map.Sidedefs, map.Sectors, map.Things, stream, writenamespace);
Write(map.Vertices, map.Linedefs, map.Sidedefs, map.Sectors, map.Things, map.UnknownUDMFData, stream, writenamespace);
}
// This writes the structures to a stream
@ -123,13 +123,16 @@ namespace CodeImp.DoomBuilder.IO
// 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)
ICollection<Thing> things, ICollection<UniversalEntry> unknowndata, Stream stream, string writenamespace)
{
UniversalParser textmap = new UniversalParser();
// Begin with fields that must be at the top
if(writenamespace != null) textmap.Root.Add("namespace", writenamespace);
// Dump unknown fields at the top
WriteUnknownData(unknowndata, textmap);
Dictionary<Vertex, int> vertexids = new Dictionary<Vertex, int>(vertices.Count); //mxd
Dictionary<Sidedef, int> sidedefids = new Dictionary<Sidedef, int>(sidedefs.Count); //mxd
Dictionary<Sector, int> sectorids = new Dictionary<Sector, int>(sectors.Count); //mxd
@ -362,6 +365,31 @@ namespace CodeImp.DoomBuilder.IO
}
}
/// <summary>
/// This writes UDMF data UDB doesn't know about to the map.
/// </summary>
/// <param name="data">Collection of universal entries.</param>
/// <param name="textmap">The map</param>
private void WriteUnknownData(ICollection<UniversalEntry> data, UniversalParser textmap)
{
foreach (UniversalEntry e in data)
{
if (e.Value is UniversalCollection)
{
UniversalCollection coll = new UniversalCollection();
foreach (UniversalEntry ie in (UniversalCollection)e.Value)
coll.Add(ie.Key, ie.Value);
textmap.Root.Add(e.Key, coll);
}
else
{
textmap.Root.Add(e);
}
}
}
// This adds custom fields from a map element to a collection
private void AddCustomFields(MapElement element, string elementname, UniversalCollection collection)
{

View file

@ -94,6 +94,9 @@ namespace CodeImp.DoomBuilder.Map
private LinkedList<Sector> sel_sectors;
private LinkedList<Thing> sel_things;
private SelectionType sel_type;
// Unknown UDMF data that needs to be preserved
private List<UniversalEntry> unknownudmfdata;
// Statics
private static long emptylongname;
@ -164,6 +167,8 @@ namespace CodeImp.DoomBuilder.Map
internal bool AutoRemove { get { return autoremove; } set { autoremove = value; } }
internal List<UniversalEntry> UnknownUDMFData { get { return unknownudmfdata; } set { unknownudmfdata = value; } }
#endregion
#region ================== Constructor / Disposer
@ -184,6 +189,7 @@ namespace CodeImp.DoomBuilder.Map
indexholes = new List<int>();
lastsectorindex = 0;
autoremove = true;
unknownudmfdata = new List<UniversalEntry>();
// We have no destructor
GC.SuppressFinalize(this);
@ -205,6 +211,7 @@ namespace CodeImp.DoomBuilder.Map
indexholes = new List<int>();
lastsectorindex = 0;
autoremove = true;
unknownudmfdata = new List<UniversalEntry>();
// Deserialize
Deserialize(stream);
@ -387,6 +394,27 @@ namespace CodeImp.DoomBuilder.Map
// Remove clone references
foreach(Vertex v in vertices) v.Clone = null;
foreach(Sector s in sectors) s.Clone = null;
// Copy unknown UDMF data
newset.UnknownUDMFData = new List<UniversalEntry>();
foreach(UniversalEntry e in unknownudmfdata)
{
if(e.Value is UniversalCollection)
{
// The UniversalEntry value is a collection, so we have to copy all sub-elements
UniversalCollection uc = new UniversalCollection();
foreach(UniversalEntry ie in (UniversalCollection)e.Value)
uc.Add(ie.Key, ie.Value);
newset.UnknownUDMFData.Add(new UniversalEntry(e.Key, uc));
}
else
{
// Just a normal UniversalEntry
newset.UnknownUDMFData.Add(new UniversalEntry(e.Key, e.Value));
}
}
// Return the new set
newset.EndAddRemove();