diff --git a/docs/docs/accessing-properties.md b/docs/docs/accessing-properties.md new file mode 100644 index 0000000..0269b88 --- /dev/null +++ b/docs/docs/accessing-properties.md @@ -0,0 +1 @@ +# Accessing properties \ No newline at end of file diff --git a/docs/docs/toc.yml b/docs/docs/toc.yml index 13cc1f7..d582202 100644 --- a/docs/docs/toc.yml +++ b/docs/docs/toc.yml @@ -3,4 +3,5 @@ - href: quickstart.md - name: Essentials -- href: loading-a-map.md \ No newline at end of file +- href: loading-a-map.md +- href: accessing-properties.md \ No newline at end of file diff --git a/src/DotTiled.Tests/Assert/AssertMap.cs b/src/DotTiled.Tests/Assert/AssertMap.cs index 6f25f45..6984b79 100644 --- a/src/DotTiled.Tests/Assert/AssertMap.cs +++ b/src/DotTiled.Tests/Assert/AssertMap.cs @@ -91,7 +91,7 @@ public static partial class DotTiledAssert AssertEqual(expected.NextObjectID, actual.NextObjectID, nameof(Map.NextObjectID)); AssertEqual(expected.Infinite, actual.Infinite, nameof(Map.Infinite)); - AssertPropertiesList(actual.Properties, expected.Properties); + AssertProperties(actual.Properties, expected.Properties); Assert.NotNull(actual.Tilesets); AssertEqual(expected.Tilesets.Count, actual.Tilesets.Count, "Tilesets.Count"); diff --git a/src/DotTiled.Tests/Assert/AssertProperties.cs b/src/DotTiled.Tests/Assert/AssertProperties.cs index ad4dc53..21fa639 100644 --- a/src/DotTiled.Tests/Assert/AssertProperties.cs +++ b/src/DotTiled.Tests/Assert/AssertProperties.cs @@ -4,24 +4,7 @@ namespace DotTiled.Tests; public static partial class DotTiledAssert { - internal static void AssertProperties(Dictionary? expected, Dictionary? actual) - { - if (expected is null) - { - Assert.Null(actual); - return; - } - - Assert.NotNull(actual); - AssertEqual(expected.Count, actual.Count, "Properties.Count"); - foreach (var kvp in expected) - { - Assert.Contains(kvp.Key, actual.Keys); - AssertProperty((dynamic)kvp.Value, (dynamic)actual[kvp.Key]); - } - } - - internal static void AssertPropertiesList(IList? expected, IList? actual) + internal static void AssertProperties(IList? expected, IList? actual) { if (expected is null) { @@ -36,17 +19,13 @@ public static partial class DotTiledAssert Assert.Contains(actual, p => p.Name == prop.Name); var actualProp = actual.First(p => p.Name == prop.Name); + AssertEqual(prop.Type, actualProp.Type, "Property.Type"); + AssertEqual(prop.Name, actualProp.Name, "Property.Name"); + AssertProperty((dynamic)prop, (dynamic)actualProp); } } - private static void AssertProperty(IProperty expected, IProperty actual) - { - AssertEqual(expected.Type, actual.Type, "Property.Type"); - AssertEqual(expected.Name, actual.Name, "Property.Name"); - AssertProperties((dynamic)actual, (dynamic)expected); - } - private static void AssertProperty(StringProperty expected, StringProperty actual) => AssertEqual(expected.Value, actual.Value, "StringProperty.Value"); private static void AssertProperty(IntProperty expected, IntProperty actual) => AssertEqual(expected.Value, actual.Value, "IntProperty.Value"); @@ -64,6 +43,6 @@ public static partial class DotTiledAssert private static void AssertProperty(ClassProperty expected, ClassProperty actual) { AssertEqual(expected.PropertyType, actual.PropertyType, "ClassProperty.PropertyType"); - AssertPropertiesList(expected.Value, actual.Value); + AssertProperties(expected.Value, actual.Value); } } diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-multi/map-external-tileset-multi.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-multi/map-external-tileset-multi.cs index 6dac137..a937685 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-multi/map-external-tileset-multi.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-multi/map-external-tileset-multi.cs @@ -49,16 +49,15 @@ public partial class TestData Width = 1, Height = 1 }, - Properties = new Dictionary - { - ["tilesetbool"] = new BoolProperty { Name = "tilesetbool", Value = true }, - ["tilesetcolor"] = new ColorProperty { Name = "tilesetcolor", Value = Color.Parse("#ffff0000", CultureInfo.InvariantCulture) }, - ["tilesetfile"] = new FileProperty { Name = "tilesetfile", Value = "" }, - ["tilesetfloat"] = new FloatProperty { Name = "tilesetfloat", Value = 5.2f }, - ["tilesetint"] = new IntProperty { Name = "tilesetint", Value = 9 }, - ["tilesetobject"] = new ObjectProperty { Name = "tilesetobject", Value = 0 }, - ["tilesetstring"] = new StringProperty { Name = "tilesetstring", Value = "hello world!" } - }, + Properties = [ + new BoolProperty { Name = "tilesetbool", Value = true }, + new ColorProperty { Name = "tilesetcolor", Value = Color.Parse("#ffff0000", CultureInfo.InvariantCulture) }, + new FileProperty { Name = "tilesetfile", Value = "" }, + new FloatProperty { Name = "tilesetfloat", Value = 5.2f }, + new IntProperty { Name = "tilesetint", Value = 9 }, + new ObjectProperty { Name = "tilesetobject", Value = 0 }, + new StringProperty { Name = "tilesetstring", Value = "hello world!" } + ], Tiles = [ new Tile { diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-many-layers/map-with-many-layers.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-many-layers/map-with-many-layers.cs index 6e4ae55..ba0013a 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-many-layers/map-with-many-layers.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-many-layers/map-with-many-layers.cs @@ -95,10 +95,9 @@ public partial class TestData new Vector2(35.6667f, 32.3333f) ], Template = fileExt == "tmx" ? "poly.tx" : "poly.tj", - Properties = new Dictionary - { - ["templateprop"] = new StringProperty { Name = "templateprop", Value = "helo there" } - } + Properties = [ + new StringProperty { Name = "templateprop", Value = "helo there" } + ] }, new TileObject { diff --git a/src/DotTiled/Model/Layers/BaseLayer.cs b/src/DotTiled/Model/Layers/BaseLayer.cs index aa78191..a16b41a 100644 --- a/src/DotTiled/Model/Layers/BaseLayer.cs +++ b/src/DotTiled/Model/Layers/BaseLayer.cs @@ -7,7 +7,7 @@ namespace DotTiled.Model; /// To check the type of a layer, use C# pattern matching, /// or some other mechanism to determine the type of the layer at runtime. /// -public abstract class BaseLayer +public abstract class BaseLayer : HasPropertiesBase { /// /// Unique ID of the layer. Each layer that is added to a map gets a unique ID. Even if a layer is deleted, no layer ever gets the same ID. @@ -62,5 +62,8 @@ public abstract class BaseLayer /// /// Layer properties. /// - public Dictionary? Properties { get; set; } + public List Properties { get; set; } = []; + + /// + public override IList GetProperties() => Properties; } diff --git a/src/DotTiled/Model/Layers/Objects/Object.cs b/src/DotTiled/Model/Layers/Objects/Object.cs index fad05db..f2990dc 100644 --- a/src/DotTiled/Model/Layers/Objects/Object.cs +++ b/src/DotTiled/Model/Layers/Objects/Object.cs @@ -5,7 +5,7 @@ namespace DotTiled.Model; /// /// Base class for objects in object layers. /// -public abstract class Object +public abstract class Object : HasPropertiesBase { /// /// Unique ID of the objects. Each object that is placed on a map gets a unique ID. Even if an object was deleted, no object gets the same ID. @@ -60,5 +60,8 @@ public abstract class Object /// /// Object properties. /// - public Dictionary? Properties { get; set; } + public List Properties { get; set; } = []; + + /// + public override IList GetProperties() => Properties; } diff --git a/src/DotTiled/Model/Tilesets/Tile.cs b/src/DotTiled/Model/Tilesets/Tile.cs index c6b964d..9919cfd 100644 --- a/src/DotTiled/Model/Tilesets/Tile.cs +++ b/src/DotTiled/Model/Tilesets/Tile.cs @@ -6,7 +6,7 @@ namespace DotTiled.Model; /// Represents a single tile in a tileset, when using a collection of images to represent the tileset. /// Tiled documentation for Tileset tiles /// -public class Tile +public class Tile : HasPropertiesBase { /// /// The local tile ID within its tileset. @@ -46,7 +46,10 @@ public class Tile /// /// Tile properties. /// - public Dictionary? Properties { get; set; } + public List Properties { get; set; } = []; + + /// + public override IList GetProperties() => Properties; /// /// The image representing this tile. Only used for tilesets that composed of a collection of images. diff --git a/src/DotTiled/Model/Tilesets/Tileset.cs b/src/DotTiled/Model/Tilesets/Tileset.cs index 147f3d2..47f2021 100644 --- a/src/DotTiled/Model/Tilesets/Tileset.cs +++ b/src/DotTiled/Model/Tilesets/Tileset.cs @@ -8,7 +8,7 @@ namespace DotTiled.Model; public enum ObjectAlignment { /// - /// The alignment is unspecified. Tile objects will use in orthogonal maps, and in isometric maps. + /// The alignment is unspecified. Tile objects will use in orthogonal maps, and in isometric maps. /// Unspecified, @@ -93,7 +93,7 @@ public enum FillMode /// /// A tileset is a collection of tiles that can be used in a tile layer, or by tile objects. /// -public class Tileset +public class Tileset : HasPropertiesBase { /// /// The TMX format version. Is incremented to match minor Tiled releases. @@ -161,7 +161,7 @@ public class Tileset public ObjectAlignment ObjectAlignment { get; set; } = ObjectAlignment.Unspecified; /// - /// The size to use when rendering tiles from thie tileset on a tile layer. When set to , the tile is drawn at the tile grid size of the map. + /// The size to use when rendering tiles from thie tileset on a tile layer. When set to , the tile is drawn at the tile grid size of the map. /// public TileRenderSize RenderSize { get; set; } = TileRenderSize.Tile; @@ -188,7 +188,10 @@ public class Tileset /// /// Tileset properties. /// - public Dictionary? Properties { get; set; } + public List Properties { get; set; } = []; + + /// + public override IList GetProperties() => Properties; // public List? TerrainTypes { get; set; } TODO: Implement Terrain -> Wangset conversion during deserialization diff --git a/src/DotTiled/Model/Tilesets/WangColor.cs b/src/DotTiled/Model/Tilesets/WangColor.cs index 20678cb..f5d1186 100644 --- a/src/DotTiled/Model/Tilesets/WangColor.cs +++ b/src/DotTiled/Model/Tilesets/WangColor.cs @@ -5,7 +5,7 @@ namespace DotTiled.Model; /// /// Represents a Wang color in a Wang set. /// -public class WangColor +public class WangColor : HasPropertiesBase { /// /// The name of this color. @@ -35,5 +35,8 @@ public class WangColor /// /// The Wang color properties. /// - public Dictionary? Properties { get; set; } + public List Properties { get; set; } = []; + + /// + public override IList GetProperties() => Properties; } diff --git a/src/DotTiled/Model/Tilesets/Wangset.cs b/src/DotTiled/Model/Tilesets/Wangset.cs index 1a6f7c3..66952e8 100644 --- a/src/DotTiled/Model/Tilesets/Wangset.cs +++ b/src/DotTiled/Model/Tilesets/Wangset.cs @@ -5,7 +5,7 @@ namespace DotTiled.Model; /// /// Defines a list of colors and any number of Wang tiles using these colors. /// -public class Wangset +public class Wangset : HasPropertiesBase { /// /// The name of the Wang set. @@ -25,7 +25,10 @@ public class Wangset /// /// The Wang set properties. /// - public Dictionary? Properties { get; set; } + public List Properties { get; set; } = []; + + /// + public override IList GetProperties() => Properties; // Up to 254 Wang colors /// diff --git a/src/DotTiled/Serialization/Helpers.cs b/src/DotTiled/Serialization/Helpers.cs index 0028650..073a19f 100644 --- a/src/DotTiled/Serialization/Helpers.cs +++ b/src/DotTiled/Serialization/Helpers.cs @@ -76,39 +76,7 @@ internal static partial class Helpers internal static List CreateInstanceOfCustomClass(CustomClassDefinition customClassDefinition) => customClassDefinition.Members.Select(x => x.Clone()).ToList(); - internal static Dictionary MergeProperties(Dictionary? baseProperties, Dictionary? overrideProperties) - { - if (baseProperties is null) - return overrideProperties ?? new Dictionary(); - - if (overrideProperties is null) - return baseProperties; - - var result = baseProperties.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Clone()); - foreach (var (key, value) in overrideProperties) - { - if (!result.TryGetValue(key, out var baseProp)) - { - result[key] = value; - continue; - } - else - { - if (value is ClassProperty classProp) - { - ((ClassProperty)baseProp).Value = MergePropertiesList(((ClassProperty)baseProp).Value, classProp.Value); - } - else - { - result[key] = value; - } - } - } - - return result; - } - - internal static IList MergePropertiesList(IList? baseProperties, IList? overrideProperties) + internal static IList MergeProperties(IList? baseProperties, IList? overrideProperties) { if (baseProperties is null) return overrideProperties ?? []; @@ -129,7 +97,7 @@ internal static partial class Helpers var existingProp = result.First(x => x.Name == overrideProp.Name); if (existingProp is ClassProperty classProp) { - classProp.Value = MergePropertiesList(classProp.Value, ((ClassProperty)overrideProp).Value); + classProp.Value = MergeProperties(classProp.Value, ((ClassProperty)overrideProp).Value); } else { diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Group.cs b/src/DotTiled/Serialization/Tmj/Tmj.Group.cs index ae44a75..a714038 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Group.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Group.cs @@ -23,7 +23,7 @@ internal partial class Tmj var offsetY = element.GetOptionalProperty("offsety", 0.0f); var parallaxX = element.GetOptionalProperty("parallaxx", 1.0f); var parallaxY = element.GetOptionalProperty("parallaxy", 1.0f); - var properties = element.GetOptionalPropertyCustom?>("properties", e => ReadProperties(e, customTypeDefinitions), null); + var properties = element.GetOptionalPropertyCustom("properties", e => ReadProperties(e, customTypeDefinitions), []); var layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(el => ReadLayer(el, externalTemplateResolver, customTypeDefinitions)), []); return new Group diff --git a/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs index bbbb151..74fb230 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs @@ -21,7 +21,7 @@ internal partial class Tmj var offsetY = element.GetOptionalProperty("offsety", 0.0f); var parallaxX = element.GetOptionalProperty("parallaxx", 1.0f); var parallaxY = element.GetOptionalProperty("parallaxy", 1.0f); - var properties = element.GetOptionalPropertyCustom?>("properties", e => ReadProperties(e, customTypeDefinitions), null); + var properties = element.GetOptionalPropertyCustom("properties", e => ReadProperties(e, customTypeDefinitions), []); var image = element.GetRequiredProperty("image"); var repeatX = element.GetOptionalProperty("repeatx", false); diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs b/src/DotTiled/Serialization/Tmj/Tmj.Map.cs index cdde458..eeb47b0 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Map.cs @@ -58,7 +58,7 @@ internal partial class Tmj var nextObjectID = element.GetRequiredProperty("nextobjectid"); var infinite = element.GetOptionalProperty("infinite", false); - var properties = element.GetOptionalPropertyCustom?>("properties", el => ReadPropertiesList(el, customTypeDefinitions), null); + var properties = element.GetOptionalPropertyCustom("properties", el => ReadProperties(el, customTypeDefinitions), []); List layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(el => ReadLayer(el, externalTemplateResolver, customTypeDefinitions)), []); List tilesets = element.GetOptionalPropertyCustom>("tilesets", e => e.GetValueAsList(el => ReadTileset(el, externalTilesetResolver, externalTemplateResolver, customTypeDefinitions)), []); @@ -84,7 +84,7 @@ internal partial class Tmj NextLayerID = nextLayerID, NextObjectID = nextObjectID, Infinite = infinite, - Properties = properties ?? [], + Properties = properties, Tilesets = tilesets, Layers = layers }; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs index 75d5ee0..589c151 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs @@ -24,7 +24,7 @@ internal partial class Tmj var offsetY = element.GetOptionalProperty("offsety", 0.0f); var parallaxX = element.GetOptionalProperty("parallaxx", 1.0f); var parallaxY = element.GetOptionalProperty("parallaxy", 1.0f); - var properties = element.GetOptionalPropertyCustom?>("properties", e => ReadProperties(e, customTypeDefinitions), null); + var properties = element.GetOptionalPropertyCustom("properties", e => ReadProperties(e, customTypeDefinitions), []); var x = element.GetOptionalProperty("x", 0); var y = element.GetOptionalProperty("y", 0); @@ -82,7 +82,7 @@ internal partial class Tmj bool pointDefault = false; List? polygonDefault = null; List? polylineDefault = null; - Dictionary? propertiesDefault = null; + List propertiesDefault = []; var template = element.GetOptionalProperty("template", null); if (template is not null) @@ -114,7 +114,7 @@ internal partial class Tmj var point = element.GetOptionalProperty("point", pointDefault); var polygon = element.GetOptionalPropertyCustom?>("polygon", ReadPoints, polygonDefault); var polyline = element.GetOptionalPropertyCustom?>("polyline", ReadPoints, polylineDefault); - var properties = element.GetOptionalPropertyCustom?>("properties", e => ReadProperties(e, customTypeDefinitions), propertiesDefault); + var properties = element.GetOptionalPropertyCustom("properties", e => ReadProperties(e, customTypeDefinitions), propertiesDefault); var rotation = element.GetOptionalProperty("rotation", rotationDefault); var text = element.GetOptionalPropertyCustom("text", ReadText, null); var type = element.GetOptionalProperty("type", typeDefault); diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs b/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs index caa5fbe..d9777e7 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs @@ -8,42 +8,7 @@ namespace DotTiled.Serialization.Tmj; internal partial class Tmj { - internal static Dictionary ReadProperties( - JsonElement element, - IReadOnlyCollection customTypeDefinitions) => - element.GetValueAsList(e => - { - var name = e.GetRequiredProperty("name"); - var type = e.GetOptionalPropertyParseable("type", s => s switch - { - "string" => PropertyType.String, - "int" => PropertyType.Int, - "float" => PropertyType.Float, - "bool" => PropertyType.Bool, - "color" => PropertyType.Color, - "file" => PropertyType.File, - "object" => PropertyType.Object, - "class" => PropertyType.Class, - _ => throw new JsonException("Invalid property type") - }, PropertyType.String); - - IProperty property = type switch - { - PropertyType.String => new StringProperty { Name = name, Value = e.GetRequiredProperty("value") }, - PropertyType.Int => new IntProperty { Name = name, Value = e.GetRequiredProperty("value") }, - PropertyType.Float => new FloatProperty { Name = name, Value = e.GetRequiredProperty("value") }, - PropertyType.Bool => new BoolProperty { Name = name, Value = e.GetRequiredProperty("value") }, - PropertyType.Color => new ColorProperty { Name = name, Value = e.GetRequiredPropertyParseable("value") }, - PropertyType.File => new FileProperty { Name = name, Value = e.GetRequiredProperty("value") }, - PropertyType.Object => new ObjectProperty { Name = name, Value = e.GetRequiredProperty("value") }, - PropertyType.Class => ReadClassProperty(e, customTypeDefinitions), - _ => throw new JsonException("Invalid property type") - }; - - return property!; - }).ToDictionary(p => p.Name); - - internal static List ReadPropertiesList( + internal static List ReadProperties( JsonElement element, IReadOnlyCollection customTypeDefinitions) => element.GetValueAsList(e => @@ -92,7 +57,7 @@ internal partial class Tmj var propsInType = Helpers.CreateInstanceOfCustomClass(ccd); var props = element.GetOptionalPropertyCustom>("value", el => ReadCustomClassProperties(el, ccd, customTypeDefinitions), []); - var mergedProps = Helpers.MergePropertiesList(propsInType, props); + var mergedProps = Helpers.MergeProperties(propsInType, props); return new ClassProperty { diff --git a/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs index cdda654..905e447 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs @@ -35,7 +35,7 @@ internal partial class Tmj var opacity = element.GetOptionalProperty("opacity", 1.0f); var parallaxx = element.GetOptionalProperty("parallaxx", 1.0f); var parallaxy = element.GetOptionalProperty("parallaxy", 1.0f); - var properties = element.GetOptionalPropertyCustom?>("properties", e => ReadProperties(e, customTypeDefinitions), null); + var properties = element.GetOptionalPropertyCustom("properties", e => ReadProperties(e, customTypeDefinitions), []); var repeatX = element.GetOptionalProperty("repeatx", false); var repeatY = element.GetOptionalProperty("repeaty", false); var startX = element.GetOptionalProperty("startx", 0); diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs b/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs index 7f3d6be..466b5d3 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs @@ -44,7 +44,7 @@ internal partial class Tmj "bottomright" => ObjectAlignment.BottomRight, _ => throw new JsonException($"Unknown object alignment '{s}'") }, ObjectAlignment.Unspecified); - var properties = element.GetOptionalPropertyCustom?>("properties", el => ReadProperties(el, customTypeDefinitions), null); + var properties = element.GetOptionalPropertyCustom("properties", el => ReadProperties(el, customTypeDefinitions), []); var source = element.GetOptionalProperty("source", null); var spacing = element.GetOptionalProperty("spacing", null); var tileCount = element.GetOptionalProperty("tilecount", null); @@ -176,7 +176,7 @@ internal partial class Tmj var height = e.GetOptionalProperty("height", imageHeight ?? 0); var objectGroup = e.GetOptionalPropertyCustom("objectgroup", e => ReadObjectLayer(e, externalTemplateResolver, customTypeDefinitions), null); var probability = e.GetOptionalProperty("probability", 0.0f); - var properties = e.GetOptionalPropertyCustom?>("properties", el => ReadProperties(el, customTypeDefinitions), null); + var properties = e.GetOptionalPropertyCustom("properties", el => ReadProperties(el, customTypeDefinitions), []); // var terrain, replaced by wangsets var type = e.GetOptionalProperty("type", ""); @@ -223,7 +223,7 @@ internal partial class Tmj var @clalss = element.GetOptionalProperty("class", ""); var colors = element.GetOptionalPropertyCustom>("colors", e => e.GetValueAsList(el => ReadWangColor(el, customTypeDefinitions)), []); var name = element.GetRequiredProperty("name"); - var properties = element.GetOptionalPropertyCustom?>("properties", e => ReadProperties(e, customTypeDefinitions), null); + var properties = element.GetOptionalPropertyCustom("properties", e => ReadProperties(e, customTypeDefinitions), []); var tile = element.GetOptionalProperty("tile", 0); var type = element.GetOptionalProperty("type", ""); var wangTiles = element.GetOptionalPropertyCustom>("wangtiles", e => e.GetValueAsList(ReadWangTile), []); @@ -247,7 +247,7 @@ internal partial class Tmj var color = element.GetRequiredPropertyParseable("color", s => Color.Parse(s, CultureInfo.InvariantCulture)); var name = element.GetRequiredProperty("name"); var probability = element.GetOptionalProperty("probability", 1.0f); - var properties = element.GetOptionalPropertyCustom?>("properties", e => ReadProperties(e, customTypeDefinitions), null); + var properties = element.GetOptionalPropertyCustom("properties", e => ReadProperties(e, customTypeDefinitions), []); var tile = element.GetOptionalProperty("tile", 0); return new WangColor diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs b/src/DotTiled/Serialization/Tmx/Tmx.Map.cs index cabfdcc..4ce03a4 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Map.cs @@ -69,7 +69,7 @@ internal partial class Tmx reader.ProcessChildren("map", (r, elementName) => elementName switch { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadPropertiesList(r, customTypeDefinitions), "Properties"), + "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(r, customTypeDefinitions), "Properties"), "tileset" => () => tilesets.Add(ReadTileset(r, externalTilesetResolver, externalTemplateResolver, customTypeDefinitions)), "layer" => () => layers.Add(ReadTileLayer(r, infinite, customTypeDefinitions)), "objectgroup" => () => layers.Add(ReadObjectLayer(r, externalTemplateResolver, customTypeDefinitions)), diff --git a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs b/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs index 4929ede..2ce3ca3 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs @@ -39,7 +39,7 @@ internal partial class Tmx }) ?? DrawOrder.TopDown; // Elements - Dictionary? properties = null; + List? properties = null; List objects = []; reader.ProcessChildren("objectgroup", (r, elementName) => elementName switch @@ -66,7 +66,7 @@ internal partial class Tmx ParallaxX = parallaxX, ParallaxY = parallaxY, Color = color, - Properties = properties, + Properties = properties ?? [], DrawOrder = drawOrder, Objects = objects }; @@ -93,7 +93,7 @@ internal partial class Tmx float rotationDefault = obj?.Rotation ?? 0f; uint? gidDefault = obj is TileObject tileObj ? tileObj.GID : null; bool visibleDefault = obj?.Visible ?? true; - Dictionary? propertiesDefault = obj?.Properties ?? null; + List? propertiesDefault = obj?.Properties ?? null; var id = reader.GetOptionalAttributeParseable("id") ?? idDefault; var name = reader.GetOptionalAttribute("name") ?? nameDefault; @@ -109,11 +109,11 @@ internal partial class Tmx // Elements Model.Object? foundObject = null; int propertiesCounter = 0; - Dictionary? properties = propertiesDefault; + List? properties = propertiesDefault; reader.ProcessChildren("object", (r, elementName) => elementName switch { - "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties(r, customTypeDefinitions)), "Properties", ref propertiesCounter), + "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties(r, customTypeDefinitions)).ToList(), "Properties", ref propertiesCounter), "ellipse" => () => Helpers.SetAtMostOnce(ref foundObject, ReadEllipseObject(r), "Object marker"), "point" => () => Helpers.SetAtMostOnce(ref foundObject, ReadPointObject(r), "Object marker"), "polygon" => () => Helpers.SetAtMostOnce(ref foundObject, ReadPolygonObject(r), "Object marker"), @@ -139,7 +139,7 @@ internal partial class Tmx foundObject.Height = height; foundObject.Rotation = rotation; foundObject.Visible = visible; - foundObject.Properties = properties; + foundObject.Properties = properties ?? []; foundObject.Template = template; return OverrideObject(obj, foundObject); @@ -161,7 +161,7 @@ internal partial class Tmx obj.Height = foundObject.Height; obj.Rotation = foundObject.Rotation; obj.Visible = foundObject.Visible; - obj.Properties = Helpers.MergeProperties(obj.Properties, foundObject.Properties); + obj.Properties = Helpers.MergeProperties(obj.Properties, foundObject.Properties).ToList(); obj.Template = foundObject.Template; return obj; } diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs b/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs index f641c4f..2e288a5 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs @@ -7,43 +7,7 @@ namespace DotTiled.Serialization.Tmx; internal partial class Tmx { - internal static Dictionary ReadProperties( - XmlReader reader, - IReadOnlyCollection customTypeDefinitions) - { - return reader.ReadList("properties", "property", (r) => - { - var name = r.GetRequiredAttribute("name"); - var type = r.GetOptionalAttributeEnum("type", (s) => s switch - { - "string" => PropertyType.String, - "int" => PropertyType.Int, - "float" => PropertyType.Float, - "bool" => PropertyType.Bool, - "color" => PropertyType.Color, - "file" => PropertyType.File, - "object" => PropertyType.Object, - "class" => PropertyType.Class, - _ => throw new XmlException("Invalid property type") - }) ?? PropertyType.String; - - IProperty property = type switch - { - PropertyType.String => new StringProperty { Name = name, Value = r.GetRequiredAttribute("value") }, - PropertyType.Int => new IntProperty { Name = name, Value = r.GetRequiredAttributeParseable("value") }, - PropertyType.Float => new FloatProperty { Name = name, Value = r.GetRequiredAttributeParseable("value") }, - PropertyType.Bool => new BoolProperty { Name = name, Value = r.GetRequiredAttributeParseable("value") }, - PropertyType.Color => new ColorProperty { Name = name, Value = r.GetRequiredAttributeParseable("value") }, - PropertyType.File => new FileProperty { Name = name, Value = r.GetRequiredAttribute("value") }, - PropertyType.Object => new ObjectProperty { Name = name, Value = r.GetRequiredAttributeParseable("value") }, - PropertyType.Class => ReadClassProperty(r, customTypeDefinitions), - _ => throw new XmlException("Invalid property type") - }; - return (name, property); - }).ToDictionary(x => x.name, x => x.property); - } - - internal static List ReadPropertiesList( + internal static List ReadProperties( XmlReader reader, IReadOnlyCollection customTypeDefinitions) { @@ -91,8 +55,8 @@ internal partial class Tmx { reader.ReadStartElement("property"); var propsInType = Helpers.CreateInstanceOfCustomClass(ccd); - var props = ReadPropertiesList(reader, customTypeDefinitions); - var mergedProps = Helpers.MergePropertiesList(propsInType, props); + var props = ReadProperties(reader, customTypeDefinitions); + var mergedProps = Helpers.MergeProperties(propsInType, props); reader.ReadEndElement(); return new ClassProperty { Name = name, PropertyType = propertyType, Value = mergedProps }; diff --git a/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs b/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs index 320019d..8605ade 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs @@ -28,7 +28,7 @@ internal partial class Tmx var parallaxX = reader.GetOptionalAttributeParseable("parallaxx") ?? 1.0f; var parallaxY = reader.GetOptionalAttributeParseable("parallaxy") ?? 1.0f; - Dictionary? properties = null; + List? properties = null; Data? data = null; reader.ProcessChildren("layer", (r, elementName) => elementName switch @@ -55,7 +55,7 @@ internal partial class Tmx ParallaxX = parallaxX, ParallaxY = parallaxY, Data = data, - Properties = properties + Properties = properties ?? [] }; } @@ -78,7 +78,7 @@ internal partial class Tmx var repeatX = (reader.GetOptionalAttributeParseable("repeatx") ?? 0) == 1; var repeatY = (reader.GetOptionalAttributeParseable("repeaty") ?? 0) == 1; - Dictionary? properties = null; + List? properties = null; Image? image = null; reader.ProcessChildren("imagelayer", (r, elementName) => elementName switch @@ -102,7 +102,7 @@ internal partial class Tmx OffsetY = offsetY, ParallaxX = parallaxX, ParallaxY = parallaxY, - Properties = properties, + Properties = properties ?? [], Image = image, RepeatX = repeatX, RepeatY = repeatY @@ -125,7 +125,7 @@ internal partial class Tmx var parallaxX = reader.GetOptionalAttributeParseable("parallaxx") ?? 1.0f; var parallaxY = reader.GetOptionalAttributeParseable("parallaxy") ?? 1.0f; - Dictionary? properties = null; + List? properties = null; List layers = []; reader.ProcessChildren("group", (r, elementName) => elementName switch @@ -150,7 +150,7 @@ internal partial class Tmx OffsetY = offsetY, ParallaxX = parallaxX, ParallaxY = parallaxY, - Properties = properties, + Properties = properties ?? [], Layers = layers }; } diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs b/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs index 6fb1ff5..84ccd24 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs @@ -60,7 +60,7 @@ internal partial class Tmx Image? image = null; TileOffset? tileOffset = null; Grid? grid = null; - Dictionary? properties = null; + List? properties = null; List? wangsets = null; Transformations? transformations = null; List tiles = []; @@ -109,7 +109,7 @@ internal partial class Tmx Image = image, TileOffset = tileOffset, Grid = grid, - Properties = properties, + Properties = properties ?? [], Wangsets = wangsets, Transformations = transformations, Tiles = tiles @@ -219,7 +219,7 @@ internal partial class Tmx var height = reader.GetOptionalAttributeParseable("height"); // Elements - Dictionary? properties = null; + List? properties = null; Image? image = null; ObjectLayer? objectLayer = null; List? animation = null; @@ -247,7 +247,7 @@ internal partial class Tmx Y = y, Width = width ?? image?.Width ?? 0, Height = height ?? image?.Height ?? 0, - Properties = properties, + Properties = properties ?? [], Image = image, ObjectLayer = objectLayer, Animation = animation @@ -269,7 +269,7 @@ internal partial class Tmx var tile = reader.GetRequiredAttributeParseable("tile"); // Elements - Dictionary? properties = null; + List? properties = null; List wangColors = []; List wangTiles = []; @@ -289,7 +289,7 @@ internal partial class Tmx Name = name, Class = @class, Tile = tile, - Properties = properties, + Properties = properties ?? [], WangColors = wangColors, WangTiles = wangTiles }; @@ -307,7 +307,7 @@ internal partial class Tmx var probability = reader.GetOptionalAttributeParseable("probability") ?? 0f; // Elements - Dictionary? properties = null; + List? properties = null; reader.ProcessChildren("wangcolor", (r, elementName) => elementName switch { @@ -322,7 +322,7 @@ internal partial class Tmx Color = color, Tile = tile, Probability = probability, - Properties = properties + Properties = properties ?? [] }; }