From 0ad1347bc183e5e765b9e4b375a170915e42aef4 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Wed, 4 Sep 2024 22:11:45 +0200 Subject: [PATCH 1/3] Map now resolves props from class --- src/DotTiled.Tests/Serialization/TestData.cs | 1 + .../map-with-class-and-props.tmx | 15 ++++ .../Map/map-with-class/map-with-class.cs | 83 +++++++++++++++++++ .../Map/map-with-class/map-with-class.tmj | 33 ++++++++ .../Map/map-with-class/map-with-class.tmx | 12 +++ src/DotTiled/Serialization/Helpers.cs | 12 +++ .../Serialization/Tmj/TmjReaderBase.Map.cs | 4 +- .../Serialization/Tmx/TmxReaderBase.Map.cs | 2 +- 8 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.tmx create mode 100644 src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.cs create mode 100644 src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.tmj create mode 100644 src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.tmx diff --git a/src/DotTiled.Tests/Serialization/TestData.cs b/src/DotTiled.Tests/Serialization/TestData.cs index 7f68c9e..3e58e6d 100644 --- a/src/DotTiled.Tests/Serialization/TestData.cs +++ b/src/DotTiled.Tests/Serialization/TestData.cs @@ -41,5 +41,6 @@ public static partial class TestData ["Serialization/TestData/Map/map_external_tileset_wangset/map-external-tileset-wangset", (string f) => MapExternalTilesetWangset(f), Array.Empty()], ["Serialization/TestData/Map/map_with_many_layers/map-with-many-layers", (string f) => MapWithManyLayers(f), Array.Empty()], ["Serialization/TestData/Map/map_with_deep_props/map-with-deep-props", (string f) => MapWithDeepProps(), MapWithDeepPropsCustomTypeDefinitions()], + ["Serialization/TestData/Map/map_with_class/map-with-class", (string f) => MapWithClass(), MapWithClassCustomTypeDefinitions()], ]; } diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.tmx b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.tmx new file mode 100644 index 0000000..4da805d --- /dev/null +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.tmx @@ -0,0 +1,15 @@ + + + + + + + +0,0,0,0,0, +0,0,0,0,0, +0,0,0,0,0, +0,0,0,0,0, +0,0,0,0,0 + + + diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.cs new file mode 100644 index 0000000..80d50a5 --- /dev/null +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.cs @@ -0,0 +1,83 @@ +namespace DotTiled.Tests; + +public partial class TestData +{ + public static Map MapWithClass() => new Map + { + Class = "TestClass", + Orientation = MapOrientation.Orthogonal, + Width = 5, + Height = 5, + TileWidth = 32, + TileHeight = 32, + Infinite = false, + ParallaxOriginX = 0, + ParallaxOriginY = 0, + RenderOrder = RenderOrder.RightDown, + CompressionLevel = -1, + BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 }, + Version = "1.10", + TiledVersion = "1.11.0", + NextLayerID = 2, + NextObjectID = 1, + Layers = [ + new TileLayer + { + ID = 1, + Name = "Tile Layer 1", + Width = 5, + Height = 5, + Data = new Data + { + Encoding = DataEncoding.Csv, + GlobalTileIDs = new Optional([ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ]), + FlippingFlags = new Optional([ + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None + ]) + } + } + ], + Properties = [ + new BoolProperty + { + Name = "classbool", + Value = true + }, + new StringProperty + { + Name = "stringbool", + Value = "Hello there default value" + } + ] + }; + + public static IReadOnlyCollection MapWithClassCustomTypeDefinitions() => [ + new CustomClassDefinition + { + Name = "TestClass", + UseAs = CustomClassUseAs.Map, + Members = [ + new BoolProperty + { + Name = "classbool", + Value = true + }, + new StringProperty + { + Name = "stringbool", + Value = "Hello there default value" + } + ] + }, + ]; +} diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.tmj b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.tmj new file mode 100644 index 0000000..480e3bb --- /dev/null +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.tmj @@ -0,0 +1,33 @@ +{ "class":"TestClass", + "compressionlevel":-1, + "height":5, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0], + "height":5, + "id":1, + "name":"Tile Layer 1", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":5, + "x":0, + "y":0 + }], + "nextlayerid":2, + "nextobjectid":1, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.11.0", + "tileheight":32, + "tilesets":[], + "tilewidth":32, + "type":"map", + "version":"1.10", + "width":5 +} \ No newline at end of file diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.tmx b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.tmx new file mode 100644 index 0000000..b3382eb --- /dev/null +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.tmx @@ -0,0 +1,12 @@ + + + + +0,0,0,0,0, +0,0,0,0,0, +0,0,0,0,0, +0,0,0,0,0, +0,0,0,0,0 + + + diff --git a/src/DotTiled/Serialization/Helpers.cs b/src/DotTiled/Serialization/Helpers.cs index b259d15..e784b80 100644 --- a/src/DotTiled/Serialization/Helpers.cs +++ b/src/DotTiled/Serialization/Helpers.cs @@ -86,6 +86,18 @@ internal static partial class Helpers }; } + internal static List ResolveClassProperties(string className, Func customTypeResolver) + { + if (string.IsNullOrWhiteSpace(className)) + return null; + + var customType = customTypeResolver(className) ?? throw new InvalidOperationException($"Could not resolve custom type '{className}'."); + if (customType is not CustomClassDefinition ccd) + throw new InvalidOperationException($"Custom type '{className}' is not a class."); + + return CreateInstanceOfCustomClass(ccd, customTypeResolver); + } + internal static List CreateInstanceOfCustomClass( CustomClassDefinition customClassDefinition, Func customTypeResolver) diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs index eaa0a9e..8779dde 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Text.Json; namespace DotTiled.Serialization.Tmj; @@ -52,7 +53,8 @@ public abstract partial class TmjReaderBase var nextObjectID = element.GetRequiredProperty("nextobjectid"); var infinite = element.GetOptionalProperty("infinite").GetValueOr(false); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var classProps = Helpers.ResolveClassProperties(@class, _customTypeResolver); + var properties = Helpers.MergeProperties(element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]), classProps).ToList(); List layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(el => ReadLayer(el))).GetValueOr([]); List tilesets = element.GetOptionalPropertyCustom>("tilesets", e => e.GetValueAsList(el => ReadTileset(el, version, tiledVersion))).GetValueOr([]); diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs index 3ba3eed..a16b715 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs @@ -56,7 +56,7 @@ public abstract partial class TmxReaderBase var infinite = _reader.GetOptionalAttributeParseable("infinite").GetValueOr(0) == 1; // At most one of - List properties = null; + List properties = Helpers.ResolveClassProperties(@class, _customTypeResolver); // Any number of List layers = []; From ffc529ecb647ef993525376f79d6ddea14cecc65 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Wed, 4 Sep 2024 22:24:40 +0200 Subject: [PATCH 2/3] Now able to override properties from class in Map --- src/DotTiled.Tests/Serialization/TestData.cs | 1 + .../map-with-class-and-props.cs | 83 +++++++++++++++++++ .../map-with-class-and-props.tmj | 39 +++++++++ .../Map/map-with-class/map-with-class.cs | 4 +- .../Serialization/Tmj/TmjReaderBase.Map.cs | 4 +- .../Serialization/Tmj/TmjReaderBase.cs | 8 ++ .../Serialization/Tmx/TmxReaderBase.Map.cs | 4 +- 7 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.cs create mode 100644 src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.tmj diff --git a/src/DotTiled.Tests/Serialization/TestData.cs b/src/DotTiled.Tests/Serialization/TestData.cs index 3e58e6d..582bd70 100644 --- a/src/DotTiled.Tests/Serialization/TestData.cs +++ b/src/DotTiled.Tests/Serialization/TestData.cs @@ -42,5 +42,6 @@ public static partial class TestData ["Serialization/TestData/Map/map_with_many_layers/map-with-many-layers", (string f) => MapWithManyLayers(f), Array.Empty()], ["Serialization/TestData/Map/map_with_deep_props/map-with-deep-props", (string f) => MapWithDeepProps(), MapWithDeepPropsCustomTypeDefinitions()], ["Serialization/TestData/Map/map_with_class/map-with-class", (string f) => MapWithClass(), MapWithClassCustomTypeDefinitions()], + ["Serialization/TestData/Map/map_with_class_and_props/map-with-class-and-props", (string f) => MapWithClassAndProps(), MapWithClassAndPropsCustomTypeDefinitions()], ]; } diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.cs new file mode 100644 index 0000000..8cbd6bd --- /dev/null +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.cs @@ -0,0 +1,83 @@ +namespace DotTiled.Tests; + +public partial class TestData +{ + public static Map MapWithClassAndProps() => new Map + { + Class = "TestClass", + Orientation = MapOrientation.Orthogonal, + Width = 5, + Height = 5, + TileWidth = 32, + TileHeight = 32, + Infinite = false, + ParallaxOriginX = 0, + ParallaxOriginY = 0, + RenderOrder = RenderOrder.RightDown, + CompressionLevel = -1, + BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 }, + Version = "1.10", + TiledVersion = "1.11.0", + NextLayerID = 2, + NextObjectID = 1, + Layers = [ + new TileLayer + { + ID = 1, + Name = "Tile Layer 1", + Width = 5, + Height = 5, + Data = new Data + { + Encoding = DataEncoding.Csv, + GlobalTileIDs = new Optional([ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ]), + FlippingFlags = new Optional([ + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None + ]) + } + } + ], + Properties = [ + new BoolProperty + { + Name = "classbool", + Value = true + }, + new StringProperty + { + Name = "classstring", + Value = "I am not default value" + } + ] + }; + + public static IReadOnlyCollection MapWithClassAndPropsCustomTypeDefinitions() => [ + new CustomClassDefinition + { + Name = "TestClass", + UseAs = CustomClassUseAs.Map, + Members = [ + new BoolProperty + { + Name = "classbool", + Value = true + }, + new StringProperty + { + Name = "classstring", + Value = "Hello there default value" + } + ] + }, + ]; +} diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.tmj b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.tmj new file mode 100644 index 0000000..d60afe3 --- /dev/null +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class-and-props/map-with-class-and-props.tmj @@ -0,0 +1,39 @@ +{ "class":"TestClass", + "compressionlevel":-1, + "height":5, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0], + "height":5, + "id":1, + "name":"Tile Layer 1", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":5, + "x":0, + "y":0 + }], + "nextlayerid":2, + "nextobjectid":1, + "orientation":"orthogonal", + "properties":[ + { + "name":"classstring", + "type":"string", + "value":"I am not default value" + }], + "renderorder":"right-down", + "tiledversion":"1.11.0", + "tileheight":32, + "tilesets":[], + "tilewidth":32, + "type":"map", + "version":"1.10", + "width":5 +} \ No newline at end of file diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.cs index 80d50a5..ef98d02 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-class/map-with-class.cs @@ -55,7 +55,7 @@ public partial class TestData }, new StringProperty { - Name = "stringbool", + Name = "classstring", Value = "Hello there default value" } ] @@ -74,7 +74,7 @@ public partial class TestData }, new StringProperty { - Name = "stringbool", + Name = "classstring", Value = "Hello there default value" } ] diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs index 8779dde..caecb7e 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Text.Json; namespace DotTiled.Serialization.Tmj; @@ -53,8 +52,7 @@ public abstract partial class TmjReaderBase var nextObjectID = element.GetRequiredProperty("nextobjectid"); var infinite = element.GetOptionalProperty("infinite").GetValueOr(false); - var classProps = Helpers.ResolveClassProperties(@class, _customTypeResolver); - var properties = Helpers.MergeProperties(element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]), classProps).ToList(); + var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([])); List layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(el => ReadLayer(el))).GetValueOr([]); List tilesets = element.GetOptionalPropertyCustom>("tilesets", e => e.GetValueAsList(el => ReadTileset(el, version, tiledVersion))).GetValueOr([]); diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.cs index f36ca88..f32100a 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Text.Json; namespace DotTiled.Serialization.Tmj; @@ -40,6 +42,12 @@ public abstract partial class TmjReaderBase : IDisposable _customTypeResolver = customTypeResolver ?? throw new ArgumentNullException(nameof(customTypeResolver)); } + private List ResolveAndMergeProperties(string className, List readProperties) + { + var classProps = Helpers.ResolveClassProperties(className, _customTypeResolver); + return Helpers.MergeProperties(classProps, readProperties).ToList(); + } + /// protected virtual void Dispose(bool disposing) { diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs index a16b715..ed3a492 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; namespace DotTiled.Serialization.Tmx; @@ -56,6 +57,7 @@ public abstract partial class TmxReaderBase var infinite = _reader.GetOptionalAttributeParseable("infinite").GetValueOr(0) == 1; // At most one of + var propertiesCounter = 0; List properties = Helpers.ResolveClassProperties(@class, _customTypeResolver); // Any number of @@ -64,7 +66,7 @@ public abstract partial class TmxReaderBase _reader.ProcessChildren("map", (r, elementName) => elementName switch { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties()).ToList(), "Properties", ref propertiesCounter), "tileset" => () => tilesets.Add(ReadTileset(version, tiledVersion)), "layer" => () => layers.Add(ReadTileLayer(infinite)), "objectgroup" => () => layers.Add(ReadObjectLayer()), From 99fb910336c71bcc51468c1480767578f5c238c1 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Thu, 5 Sep 2024 20:43:12 +0200 Subject: [PATCH 3/3] Affected parts of model should now inherit properties from their specified class --- .../Serialization/Tmj/TmjReaderBase.Group.cs | 2 +- .../Tmj/TmjReaderBase.ImageLayer.cs | 2 +- .../Tmj/TmjReaderBase.ObjectLayer.cs | 2 +- .../Tmj/TmjReaderBase.TileLayer.cs | 2 +- .../Tmj/TmjReaderBase.Tileset.cs | 12 +++++------ .../Tmx/TmxReaderBase.ObjectLayer.cs | 7 ++++--- .../Tmx/TmxReaderBase.TileLayer.cs | 16 +++++++++------ .../Tmx/TmxReaderBase.Tileset.cs | 20 +++++++++++-------- 8 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs index 9548f1c..0df3c10 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs @@ -17,7 +17,7 @@ public abstract partial class TmjReaderBase var offsetY = element.GetOptionalProperty("offsety").GetValueOr(0.0f); var parallaxX = element.GetOptionalProperty("parallaxx").GetValueOr(1.0f); var parallaxY = element.GetOptionalProperty("parallaxy").GetValueOr(1.0f); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([])); var layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(ReadLayer)).GetValueOr([]); return new Group diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs index 7034663..3d59779 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs @@ -16,7 +16,7 @@ public abstract partial class TmjReaderBase var offsetY = element.GetOptionalProperty("offsety").GetValueOr(0.0f); var parallaxX = element.GetOptionalProperty("parallaxx").GetValueOr(1.0f); var parallaxY = element.GetOptionalProperty("parallaxy").GetValueOr(1.0f); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([])); var image = element.GetRequiredProperty("image"); var repeatX = element.GetOptionalProperty("repeatx").GetValueOr(false); diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs index 0456157..f90d986 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs @@ -19,7 +19,7 @@ public abstract partial class TmjReaderBase var offsetY = element.GetOptionalProperty("offsety").GetValueOr(0.0f); var parallaxX = element.GetOptionalProperty("parallaxx").GetValueOr(1.0f); var parallaxY = element.GetOptionalProperty("parallaxy").GetValueOr(1.0f); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([])); var x = element.GetOptionalProperty("x").GetValueOr(0); var y = element.GetOptionalProperty("y").GetValueOr(0); diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs index 7c8791a..f33840d 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs @@ -30,7 +30,7 @@ public abstract partial class TmjReaderBase var opacity = element.GetOptionalProperty("opacity").GetValueOr(1.0f); var parallaxx = element.GetOptionalProperty("parallaxx").GetValueOr(1.0f); var parallaxy = element.GetOptionalProperty("parallaxy").GetValueOr(1.0f); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([])); var repeatX = element.GetOptionalProperty("repeatx").GetValueOr(false); var repeatY = element.GetOptionalProperty("repeaty").GetValueOr(false); var startX = element.GetOptionalProperty("startx").GetValueOr(0); diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs index ea91acf..9263fa9 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs @@ -40,7 +40,7 @@ public abstract partial class TmjReaderBase "bottomright" => ObjectAlignment.BottomRight, _ => throw new JsonException($"Unknown object alignment '{s}'") }).GetValueOr(ObjectAlignment.Unspecified); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([])); var source = element.GetOptionalProperty("source"); var spacing = element.GetOptionalProperty("spacing"); var tileCount = element.GetOptionalProperty("tilecount"); @@ -166,8 +166,8 @@ public abstract partial class TmjReaderBase var height = e.GetOptionalProperty("height").GetValueOr(imageHeight.GetValueOr(0)); var objectGroup = e.GetOptionalPropertyCustom("objectgroup", e => ReadObjectLayer(e)); var probability = e.GetOptionalProperty("probability").GetValueOr(0.0f); - var properties = e.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); var type = e.GetOptionalProperty("type").GetValueOr(""); + var properties = ResolveAndMergeProperties(type, e.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([])); Optional imageModel = image.HasValue ? new Image { @@ -207,17 +207,17 @@ public abstract partial class TmjReaderBase internal Wangset ReadWangset(JsonElement element) { - var @clalss = element.GetOptionalProperty("class").GetValueOr(""); + var @class = element.GetOptionalProperty("class").GetValueOr(""); var colors = element.GetOptionalPropertyCustom>("colors", e => e.GetValueAsList(el => ReadWangColor(el))).GetValueOr([]); var name = element.GetRequiredProperty("name"); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([])); var tile = element.GetOptionalProperty("tile").GetValueOr(0); var type = element.GetOptionalProperty("type").GetValueOr(""); var wangTiles = element.GetOptionalPropertyCustom>("wangtiles", e => e.GetValueAsList(ReadWangTile)).GetValueOr([]); return new Wangset { - Class = @clalss, + Class = @class, WangColors = colors, Name = name, Properties = properties, @@ -232,7 +232,7 @@ public abstract partial class TmjReaderBase var color = element.GetRequiredPropertyParseable("color"); var name = element.GetRequiredProperty("name"); var probability = element.GetOptionalProperty("probability").GetValueOr(1.0f); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([])); var tile = element.GetOptionalProperty("tile").GetValueOr(0); return new WangColor diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs index 67cd69a..85c669c 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs @@ -34,12 +34,13 @@ public abstract partial class TmxReaderBase }).GetValueOr(DrawOrder.TopDown); // Elements - List properties = null; + var propertiesCounter = 0; + List properties = Helpers.ResolveClassProperties(@class, _customTypeResolver); List objects = []; _reader.ProcessChildren("objectgroup", (r, elementName) => elementName switch { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties()).ToList(), "Properties", ref propertiesCounter), "object" => () => objects.Add(ReadObject()), _ => r.Skip }); @@ -101,7 +102,7 @@ public abstract partial class TmxReaderBase // Elements DotTiled.Object foundObject = null; int propertiesCounter = 0; - List properties = propertiesDefault; + List properties = Helpers.ResolveClassProperties(type, _customTypeResolver) ?? propertiesDefault; _reader.ProcessChildren("object", (r, elementName) => elementName switch { diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs index d3a7106..974215b 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; namespace DotTiled.Serialization.Tmx; @@ -21,13 +22,14 @@ public abstract partial class TmxReaderBase var parallaxX = _reader.GetOptionalAttributeParseable("parallaxx").GetValueOr(1.0f); var parallaxY = _reader.GetOptionalAttributeParseable("parallaxy").GetValueOr(1.0f); - List properties = null; + var propertiesCounter = 0; + List properties = Helpers.ResolveClassProperties(@class, _customTypeResolver); Data data = null; _reader.ProcessChildren("layer", (r, elementName) => elementName switch { "data" => () => Helpers.SetAtMostOnce(ref data, ReadData(dataUsesChunks), "Data"), - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties()).ToList(), "Properties", ref propertiesCounter), _ => r.Skip }); @@ -69,13 +71,14 @@ public abstract partial class TmxReaderBase var repeatX = _reader.GetOptionalAttributeParseable("repeatx").GetValueOr(0) == 1; var repeatY = _reader.GetOptionalAttributeParseable("repeaty").GetValueOr(0) == 1; - List properties = null; + var propertiesCounter = 0; + List properties = Helpers.ResolveClassProperties(@class, _customTypeResolver); Image image = null; _reader.ProcessChildren("imagelayer", (r, elementName) => elementName switch { "image" => () => Helpers.SetAtMostOnce(ref image, ReadImage(), "Image"), - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties()).ToList(), "Properties", ref propertiesCounter), _ => r.Skip }); @@ -113,12 +116,13 @@ public abstract partial class TmxReaderBase var parallaxX = _reader.GetOptionalAttributeParseable("parallaxx").GetValueOr(1f); var parallaxY = _reader.GetOptionalAttributeParseable("parallaxy").GetValueOr(1f); - List properties = null; + var propertiesCounter = 0; + List properties = Helpers.ResolveClassProperties(@class, _customTypeResolver); List layers = []; _reader.ProcessChildren("group", (r, elementName) => elementName switch { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties()).ToList(), "Properties", ref propertiesCounter), "layer" => () => layers.Add(ReadTileLayer(false)), "objectgroup" => () => layers.Add(ReadObjectLayer()), "imagelayer" => () => layers.Add(ReadImageLayer()), diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs index 971e6fd..2fc2540 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs @@ -68,7 +68,8 @@ public abstract partial class TmxReaderBase Image image = null; TileOffset tileOffset = null; Grid grid = null; - List properties = null; + var propertiesCounter = 0; + List properties = Helpers.ResolveClassProperties(@class, _customTypeResolver); List wangsets = null; Transformations transformations = null; List tiles = []; @@ -78,7 +79,7 @@ public abstract partial class TmxReaderBase "image" => () => Helpers.SetAtMostOnce(ref image, ReadImage(), "Image"), "tileoffset" => () => Helpers.SetAtMostOnce(ref tileOffset, ReadTileOffset(), "TileOffset"), "grid" => () => Helpers.SetAtMostOnce(ref grid, ReadGrid(), "Grid"), - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties()).ToList(), "Properties", ref propertiesCounter), "wangsets" => () => Helpers.SetAtMostOnce(ref wangsets, ReadWangsets(), "Wangsets"), "transformations" => () => Helpers.SetAtMostOnce(ref transformations, ReadTransformations(), "Transformations"), "tile" => () => tiles.Add(ReadTile()), @@ -197,14 +198,15 @@ public abstract partial class TmxReaderBase var height = _reader.GetOptionalAttributeParseable("height"); // Elements - List properties = null; + var propertiesCounter = 0; + List properties = Helpers.ResolveClassProperties(type, _customTypeResolver); Image image = null; ObjectLayer objectLayer = null; List animation = null; _reader.ProcessChildren("tile", (r, elementName) => elementName switch { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties()).ToList(), "Properties", ref propertiesCounter), "image" => () => Helpers.SetAtMostOnce(ref image, ReadImage(), "Image"), "objectgroup" => () => Helpers.SetAtMostOnce(ref objectLayer, ReadObjectLayer(), "ObjectLayer"), "animation" => () => Helpers.SetAtMostOnce(ref animation, r.ReadList("animation", "frame", (ar) => @@ -243,13 +245,14 @@ public abstract partial class TmxReaderBase var tile = _reader.GetRequiredAttributeParseable("tile"); // Elements - List properties = null; + var propertiesCounter = 0; + List properties = Helpers.ResolveClassProperties(@class, _customTypeResolver); List wangColors = []; List wangTiles = []; _reader.ProcessChildren("wangset", (r, elementName) => elementName switch { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties()).ToList(), "Properties", ref propertiesCounter), "wangcolor" => () => wangColors.Add(ReadWangColor()), "wangtile" => () => wangTiles.Add(ReadWangTile()), _ => r.Skip @@ -279,11 +282,12 @@ public abstract partial class TmxReaderBase var probability = _reader.GetOptionalAttributeParseable("probability").GetValueOr(0f); // Elements - List properties = null; + var propertiesCounter = 0; + List properties = Helpers.ResolveClassProperties(@class, _customTypeResolver); _reader.ProcessChildren("wangcolor", (r, elementName) => elementName switch { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties()).ToList(), "Properties", ref propertiesCounter), _ => r.Skip });