From 608e77927abcc3f5965c9aa6cbc721eadd56c1e2 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Sun, 18 Aug 2024 21:29:38 +0200 Subject: [PATCH 01/23] Use only Model namespace --- docs/docfx.json | 3 +- src/DotTiled.Benchmark/Program.cs | 4 +- src/DotTiled.Tests/Assert/AssertData.cs | 2 +- src/DotTiled.Tests/Assert/AssertImage.cs | 2 +- src/DotTiled.Tests/Assert/AssertLayer.cs | 2 +- src/DotTiled.Tests/Assert/AssertObject.cs | 2 +- src/DotTiled.Tests/Assert/AssertProperties.cs | 2 +- src/DotTiled.Tests/Assert/AssertTileset.cs | 4 +- src/DotTiled.Tests/Serialization/TestData.cs | 4 +- .../TestData/Map/default-map/default-map.cs | 2 +- .../map-external-tileset-multi.cs | 6 +- .../map-external-tileset-wangset.cs | 4 +- .../map-with-common-props.cs | 4 +- .../map-with-custom-type-props.cs | 6 +- .../map-with-embedded-tileset.cs | 4 +- .../map-with-external-tileset.cs | 4 +- .../map-with-flippingflags.cs | 4 +- .../map-with-many-layers.cs | 8 +- .../Serialization/Tmj/TmjMapReaderTests.cs | 4 +- .../Serialization/Tmx/TmxMapReaderTests.cs | 4 +- src/DotTiled/DotTiled.csproj | 1 + src/DotTiled/Model/Color.cs | 39 +++++ src/DotTiled/Model/Layers/BaseLayer.cs | 3 +- src/DotTiled/Model/Layers/Data.cs | 2 +- src/DotTiled/Model/Layers/Group.cs | 2 +- src/DotTiled/Model/Layers/ImageLayer.cs | 4 +- src/DotTiled/Model/Layers/ObjectLayer.cs | 3 +- .../Model/Layers/Objects/EllipseObject.cs | 2 +- src/DotTiled/Model/Layers/Objects/Object.cs | 3 +- .../Model/Layers/Objects/PointObject.cs | 2 +- .../Model/Layers/Objects/PolygonObject.cs | 2 +- .../Model/Layers/Objects/PolylineObject.cs | 2 +- .../Model/Layers/Objects/RectangleObject.cs | 2 +- .../Model/Layers/Objects/TextObject.cs | 3 +- .../Model/Layers/Objects/TileObject.cs | 2 +- src/DotTiled/Model/Layers/TileLayer.cs | 2 +- src/DotTiled/Model/Map.cs | 151 +++++++++++++++++- src/DotTiled/Model/Properties/BoolProperty.cs | 2 +- .../Model/Properties/ClassProperty.cs | 2 +- .../Model/Properties/ColorProperty.cs | 2 +- .../CustomTypes/CustomClassDefinition.cs | 2 +- .../CustomTypes/CustomEnumDefinition.cs | 2 +- .../CustomTypes/CustomTypeDefinition.cs | 2 +- src/DotTiled/Model/Properties/FileProperty.cs | 2 +- .../Model/Properties/FloatProperty.cs | 2 +- src/DotTiled/Model/Properties/IProperty.cs | 2 +- src/DotTiled/Model/Properties/IntProperty.cs | 2 +- .../Model/Properties/ObjectProperty.cs | 2 +- src/DotTiled/Model/Properties/PropertyType.cs | 2 +- .../Model/Properties/StringProperty.cs | 2 +- src/DotTiled/Model/Template.cs | 14 +- src/DotTiled/Model/Tilesets/Frame.cs | 2 +- src/DotTiled/Model/Tilesets/Grid.cs | 2 +- src/DotTiled/Model/Tilesets/Image.cs | 2 +- src/DotTiled/Model/Tilesets/Tile.cs | 4 +- src/DotTiled/Model/Tilesets/TileOffset.cs | 2 +- src/DotTiled/Model/Tilesets/Tileset.cs | 3 +- .../Model/Tilesets/Transformations.cs | 2 +- src/DotTiled/Model/Tilesets/WangColor.cs | 3 +- src/DotTiled/Model/Tilesets/WangTile.cs | 2 +- src/DotTiled/Model/Tilesets/Wangset.cs | 3 +- src/DotTiled/Serialization/Helpers.cs | 6 +- src/DotTiled/Serialization/ITilesetReader.cs | 2 +- .../Serialization/Tmj/TjTemplateReader.cs | 2 - src/DotTiled/Serialization/Tmj/Tmj.Data.cs | 2 +- src/DotTiled/Serialization/Tmj/Tmj.Group.cs | 3 - .../Serialization/Tmj/Tmj.ImageLayer.cs | 5 +- src/DotTiled/Serialization/Tmj/Tmj.Layer.cs | 2 - src/DotTiled/Serialization/Tmj/Tmj.Map.cs | 4 - .../Serialization/Tmj/Tmj.ObjectLayer.cs | 4 - .../Serialization/Tmj/Tmj.Properties.cs | 2 - .../Serialization/Tmj/Tmj.Template.cs | 2 - .../Serialization/Tmj/Tmj.TileLayer.cs | 3 - src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs | 4 - .../Serialization/Tmj/TmjMapReader.cs | 2 - .../Serialization/Tmj/TsjTilesetReader.cs | 2 - src/DotTiled/Serialization/Tmx/Tmx.Chunk.cs | 2 +- src/DotTiled/Serialization/Tmx/Tmx.Data.cs | 2 +- src/DotTiled/Serialization/Tmx/Tmx.Map.cs | 4 - .../Serialization/Tmx/Tmx.ObjectLayer.cs | 5 - .../Serialization/Tmx/Tmx.Properties.cs | 2 - .../Serialization/Tmx/Tmx.TileLayer.cs | 4 - src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs | 4 - .../Serialization/Tmx/TmxMapReader.cs | 2 - .../Serialization/Tmx/TsxTilesetReader.cs | 2 - .../Serialization/Tmx/TxTemplateReader.cs | 2 - 86 files changed, 278 insertions(+), 161 deletions(-) diff --git a/docs/docfx.json b/docs/docfx.json index fa6feed..4c955cb 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -9,7 +9,8 @@ ] } ], - "dest": "api" + "dest": "api", + "enumSortOrder": "declaringOrder" } ], "build": { diff --git a/src/DotTiled.Benchmark/Program.cs b/src/DotTiled.Benchmark/Program.cs index e04c6b1..55c04cf 100644 --- a/src/DotTiled.Benchmark/Program.cs +++ b/src/DotTiled.Benchmark/Program.cs @@ -39,7 +39,7 @@ public MapLoading() [BenchmarkCategory("MapFromInMemoryTmxString")] [Benchmark(Baseline = true, Description = "DotTiled")] - public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmxString() + public DotTiled.Model LoadWithDotTiledFromInMemoryTmxString() { using var stringReader = new StringReader(_tmxContents); using var xmlReader = XmlReader.Create(stringReader); @@ -49,7 +49,7 @@ public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmxString() [BenchmarkCategory("MapFromInMemoryTmjString")] [Benchmark(Baseline = true, Description = "DotTiled")] - public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmjString() + public DotTiled.Model LoadWithDotTiledFromInMemoryTmjString() { using var mapReader = new DotTiled.Serialization.Tmj.TmjMapReader(_tmjContents, _ => throw new Exception(), _ => throw new Exception(), []); return mapReader.ReadMap(); diff --git a/src/DotTiled.Tests/Assert/AssertData.cs b/src/DotTiled.Tests/Assert/AssertData.cs index 3c18ef9..3ddcf4a 100644 --- a/src/DotTiled.Tests/Assert/AssertData.cs +++ b/src/DotTiled.Tests/Assert/AssertData.cs @@ -1,4 +1,4 @@ -using DotTiled.Model.Layers; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Assert/AssertImage.cs b/src/DotTiled.Tests/Assert/AssertImage.cs index 613318b..51a9b82 100644 --- a/src/DotTiled.Tests/Assert/AssertImage.cs +++ b/src/DotTiled.Tests/Assert/AssertImage.cs @@ -1,4 +1,4 @@ -using DotTiled.Model.Tilesets; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Assert/AssertLayer.cs b/src/DotTiled.Tests/Assert/AssertLayer.cs index 1cb9e36..89886cc 100644 --- a/src/DotTiled.Tests/Assert/AssertLayer.cs +++ b/src/DotTiled.Tests/Assert/AssertLayer.cs @@ -1,4 +1,4 @@ -using DotTiled.Model.Layers; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Assert/AssertObject.cs b/src/DotTiled.Tests/Assert/AssertObject.cs index f234ed2..93a5c45 100644 --- a/src/DotTiled.Tests/Assert/AssertObject.cs +++ b/src/DotTiled.Tests/Assert/AssertObject.cs @@ -1,4 +1,4 @@ -using DotTiled.Model.Layers.Objects; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Assert/AssertProperties.cs b/src/DotTiled.Tests/Assert/AssertProperties.cs index ddd0e69..16d9cdb 100644 --- a/src/DotTiled.Tests/Assert/AssertProperties.cs +++ b/src/DotTiled.Tests/Assert/AssertProperties.cs @@ -1,4 +1,4 @@ -using DotTiled.Model.Properties; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Assert/AssertTileset.cs b/src/DotTiled.Tests/Assert/AssertTileset.cs index c0e5e8e..3e4ab28 100644 --- a/src/DotTiled.Tests/Assert/AssertTileset.cs +++ b/src/DotTiled.Tests/Assert/AssertTileset.cs @@ -1,5 +1,5 @@ -using DotTiled.Model.Layers; -using DotTiled.Model.Tilesets; +using DotTiled.Model; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData.cs b/src/DotTiled.Tests/Serialization/TestData.cs index 467e1df..30c4b9f 100644 --- a/src/DotTiled.Tests/Serialization/TestData.cs +++ b/src/DotTiled.Tests/Serialization/TestData.cs @@ -1,6 +1,6 @@ using System.Xml; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; +using DotTiled.Model; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs b/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs index c445069..4eef6de 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs @@ -1,5 +1,5 @@ using DotTiled.Model; -using DotTiled.Model.Layers; +using DotTiled.Model; namespace DotTiled.Tests; 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 e1aecda..04c425a 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 @@ -1,8 +1,8 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Tilesets; +using DotTiled.Model; +using DotTiled.Model; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs index 7e21c54..a894a53 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs @@ -1,7 +1,7 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Tilesets; +using DotTiled.Model; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs index 7b4de68..14f95ac 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs @@ -1,7 +1,7 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; +using DotTiled.Model; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs index 47a6b6b..e7d135c 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs @@ -1,8 +1,8 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; +using DotTiled.Model; +using DotTiled.Model; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs index 0673cf6..e9c4e73 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs @@ -1,7 +1,7 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Tilesets; +using DotTiled.Model; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs index efea5c0..055a0c9 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs @@ -1,7 +1,7 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Tilesets; +using DotTiled.Model; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs index d2f1813..96995d7 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs @@ -1,7 +1,7 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Tilesets; +using DotTiled.Model; +using DotTiled.Model; namespace DotTiled.Tests; 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 2b09178..320fa48 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 @@ -1,9 +1,9 @@ using System.Numerics; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Layers.Objects; -using DotTiled.Model.Properties; -using DotTiled.Model.Tilesets; +using DotTiled.Model; +using DotTiled.Model; +using DotTiled.Model; +using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs b/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs index c862203..a856f68 100644 --- a/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs @@ -1,6 +1,6 @@ using DotTiled.Model; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; +using DotTiled.Model; +using DotTiled.Model; using DotTiled.Serialization.Tmj; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs b/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs index ab48769..6a26b62 100644 --- a/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs @@ -1,7 +1,7 @@ using System.Xml; using DotTiled.Model; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; +using DotTiled.Model; +using DotTiled.Model; using DotTiled.Serialization.Tmx; namespace DotTiled.Tests; diff --git a/src/DotTiled/DotTiled.csproj b/src/DotTiled/DotTiled.csproj index 0102e6e..0a2dfe8 100644 --- a/src/DotTiled/DotTiled.csproj +++ b/src/DotTiled/DotTiled.csproj @@ -3,6 +3,7 @@ net8.0 enable + true diff --git a/src/DotTiled/Model/Color.cs b/src/DotTiled/Model/Color.cs index 4700e0c..24cf8e5 100644 --- a/src/DotTiled/Model/Color.cs +++ b/src/DotTiled/Model/Color.cs @@ -1,22 +1,57 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Threading; namespace DotTiled.Model; +/// +/// Represents a Tiled color. +/// public class Color : IParsable, IEquatable { + /// + /// The red component of the color. + /// public required byte R { get; set; } + + /// + /// The green component of the color. + /// public required byte G { get; set; } + + /// + /// The blue component of the color. + /// public required byte B { get; set; } + + /// + /// The alpha component of the color. + /// public byte A { get; set; } = 255; + /// + /// Attempts to parse the specified string into a . Expects strings in the format #RRGGBB or #AARRGGBB. + /// The leading # is optional. + /// + /// A string value to parse into a + /// An object that supplies culture-specific information about the format of s. + /// The parsed + /// Thrown in case the provided string is not in a valid format. public static Color Parse(string s, IFormatProvider? provider) { TryParse(s, provider, out var result); return result ?? throw new FormatException($"Invalid format for TiledColor: {s}"); } + /// + /// Attempts to parse the specified string into a . Expects strings in the format #RRGGBB or #AARRGGBB. + /// The leading # is optional. + /// + /// A string value to parse into a + /// An object that supplies culture-specific information about the format of s. + /// When this method returns, contains the parsed or null on failure. + /// true if was successfully parsed; otherwise, false. public static bool TryParse( [NotNullWhen(true)] string? s, IFormatProvider? provider, @@ -55,6 +90,7 @@ public static bool TryParse( return true; } + /// public bool Equals(Color? other) { if (other is null) @@ -63,9 +99,12 @@ public bool Equals(Color? other) return R == other.R && G == other.G && B == other.B && A == other.A; } + /// public override bool Equals(object? obj) => obj is Color other && Equals(other); + /// public override int GetHashCode() => HashCode.Combine(R, G, B, A); + /// public override string ToString() => $"#{A:x2}{R:x2}{G:x2}{B:x2}"; } diff --git a/src/DotTiled/Model/Layers/BaseLayer.cs b/src/DotTiled/Model/Layers/BaseLayer.cs index adeee69..f73c760 100644 --- a/src/DotTiled/Model/Layers/BaseLayer.cs +++ b/src/DotTiled/Model/Layers/BaseLayer.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; -using DotTiled.Model.Properties; -namespace DotTiled.Model.Layers; +namespace DotTiled.Model; public abstract class BaseLayer { diff --git a/src/DotTiled/Model/Layers/Data.cs b/src/DotTiled/Model/Layers/Data.cs index 2d54020..7388828 100644 --- a/src/DotTiled/Model/Layers/Data.cs +++ b/src/DotTiled/Model/Layers/Data.cs @@ -1,6 +1,6 @@ using System; -namespace DotTiled.Model.Layers; +namespace DotTiled.Model; public enum DataEncoding { diff --git a/src/DotTiled/Model/Layers/Group.cs b/src/DotTiled/Model/Layers/Group.cs index fd89f61..9fa68da 100644 --- a/src/DotTiled/Model/Layers/Group.cs +++ b/src/DotTiled/Model/Layers/Group.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotTiled.Model.Layers; +namespace DotTiled.Model; public class Group : BaseLayer { diff --git a/src/DotTiled/Model/Layers/ImageLayer.cs b/src/DotTiled/Model/Layers/ImageLayer.cs index cd35a41..fbdf54e 100644 --- a/src/DotTiled/Model/Layers/ImageLayer.cs +++ b/src/DotTiled/Model/Layers/ImageLayer.cs @@ -1,6 +1,4 @@ -using DotTiled.Model.Tilesets; - -namespace DotTiled.Model.Layers; +namespace DotTiled.Model; public class ImageLayer : BaseLayer { diff --git a/src/DotTiled/Model/Layers/ObjectLayer.cs b/src/DotTiled/Model/Layers/ObjectLayer.cs index 817e95e..04f97dd 100644 --- a/src/DotTiled/Model/Layers/ObjectLayer.cs +++ b/src/DotTiled/Model/Layers/ObjectLayer.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; -using DotTiled.Model.Layers.Objects; -namespace DotTiled.Model.Layers; +namespace DotTiled.Model; public enum DrawOrder { diff --git a/src/DotTiled/Model/Layers/Objects/EllipseObject.cs b/src/DotTiled/Model/Layers/Objects/EllipseObject.cs index fe57573..8e75338 100644 --- a/src/DotTiled/Model/Layers/Objects/EllipseObject.cs +++ b/src/DotTiled/Model/Layers/Objects/EllipseObject.cs @@ -1,3 +1,3 @@ -namespace DotTiled.Model.Layers.Objects; +namespace DotTiled.Model; public class EllipseObject : Object { } diff --git a/src/DotTiled/Model/Layers/Objects/Object.cs b/src/DotTiled/Model/Layers/Objects/Object.cs index 82254e5..98935b1 100644 --- a/src/DotTiled/Model/Layers/Objects/Object.cs +++ b/src/DotTiled/Model/Layers/Objects/Object.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; -using DotTiled.Model.Properties; -namespace DotTiled.Model.Layers.Objects; +namespace DotTiled.Model; public abstract class Object { diff --git a/src/DotTiled/Model/Layers/Objects/PointObject.cs b/src/DotTiled/Model/Layers/Objects/PointObject.cs index f2949a2..e606c37 100644 --- a/src/DotTiled/Model/Layers/Objects/PointObject.cs +++ b/src/DotTiled/Model/Layers/Objects/PointObject.cs @@ -1,3 +1,3 @@ -namespace DotTiled.Model.Layers.Objects; +namespace DotTiled.Model; public class PointObject : Object { } diff --git a/src/DotTiled/Model/Layers/Objects/PolygonObject.cs b/src/DotTiled/Model/Layers/Objects/PolygonObject.cs index 57e3f06..6a58592 100644 --- a/src/DotTiled/Model/Layers/Objects/PolygonObject.cs +++ b/src/DotTiled/Model/Layers/Objects/PolygonObject.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Numerics; -namespace DotTiled.Model.Layers.Objects; +namespace DotTiled.Model; public class PolygonObject : Object { diff --git a/src/DotTiled/Model/Layers/Objects/PolylineObject.cs b/src/DotTiled/Model/Layers/Objects/PolylineObject.cs index 03cd6b4..e97d017 100644 --- a/src/DotTiled/Model/Layers/Objects/PolylineObject.cs +++ b/src/DotTiled/Model/Layers/Objects/PolylineObject.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Numerics; -namespace DotTiled.Model.Layers.Objects; +namespace DotTiled.Model; public class PolylineObject : Object { diff --git a/src/DotTiled/Model/Layers/Objects/RectangleObject.cs b/src/DotTiled/Model/Layers/Objects/RectangleObject.cs index ff64a76..4fad428 100644 --- a/src/DotTiled/Model/Layers/Objects/RectangleObject.cs +++ b/src/DotTiled/Model/Layers/Objects/RectangleObject.cs @@ -1,3 +1,3 @@ -namespace DotTiled.Model.Layers.Objects; +namespace DotTiled.Model; public class RectangleObject : Object { } diff --git a/src/DotTiled/Model/Layers/Objects/TextObject.cs b/src/DotTiled/Model/Layers/Objects/TextObject.cs index f39f84a..2072c7f 100644 --- a/src/DotTiled/Model/Layers/Objects/TextObject.cs +++ b/src/DotTiled/Model/Layers/Objects/TextObject.cs @@ -1,7 +1,6 @@ using System.Globalization; -namespace DotTiled.Model.Layers.Objects; - +namespace DotTiled.Model; public enum TextHorizontalAlignment { diff --git a/src/DotTiled/Model/Layers/Objects/TileObject.cs b/src/DotTiled/Model/Layers/Objects/TileObject.cs index 992ac3c..dc52100 100644 --- a/src/DotTiled/Model/Layers/Objects/TileObject.cs +++ b/src/DotTiled/Model/Layers/Objects/TileObject.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Layers.Objects; +namespace DotTiled.Model; public class TileObject : Object { diff --git a/src/DotTiled/Model/Layers/TileLayer.cs b/src/DotTiled/Model/Layers/TileLayer.cs index 9002397..f314c1c 100644 --- a/src/DotTiled/Model/Layers/TileLayer.cs +++ b/src/DotTiled/Model/Layers/TileLayer.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Layers; +namespace DotTiled.Model; public class TileLayer : BaseLayer { diff --git a/src/DotTiled/Model/Map.cs b/src/DotTiled/Model/Map.cs index 3102567..c9c72dc 100644 --- a/src/DotTiled/Model/Map.cs +++ b/src/DotTiled/Model/Map.cs @@ -1,66 +1,205 @@ using System.Collections.Generic; using System.Globalization; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Tilesets; namespace DotTiled.Model; +/// +/// Map orientation enumeration. The map orientation determines the alignment of the tiles in the map. +/// public enum MapOrientation { + /// + /// Orthogonal orientation. This is the typical top-down grid-based layout. + /// Orthogonal, + + /// + /// Isometric orientation. This is a type of axonometric projection where the tiles are shown as rhombuses, as seen from a side-on view. + /// Isometric, + + /// + /// Staggered orientation. This is an isometric projection with a side-on view where the tiles are arranged in a staggered grid. + /// Staggered, + + /// + /// Hexagonal orientation. This is a type of axial projection where the tiles are shown as hexagons, as seen from a top-down view. + /// Hexagonal } +/// +/// Render order enumeration. The order in which tiles on tile layers are rendered. +/// public enum RenderOrder { + /// + /// Right-down render order. Starts at top-left and proceeds right then down. + /// RightDown, + + /// + /// Right-up render order. Starts at bottom-left and proceeds right then up. + /// RightUp, + + /// + /// Left-down render order. Starts at top-right and proceeds left then down. + /// LeftDown, + + /// + /// Left-up render order. Starts at bottom-right and proceeds left then up. + /// LeftUp } +/// +/// Stagger axis enumeration. For staggered and hexagonal maps, determines which axis (X or Y) is staggered. +/// public enum StaggerAxis { + /// + /// X stagger axis. + /// X, + + /// + /// Y stagger axis. + /// Y } +/// +/// Stagger index enumeration. For staggered and hexagonal maps, determines whether the "even" or "odd" indexes along the staggered axis are shifted. +/// public enum StaggerIndex { + /// + /// Even stagger index. + /// Odd, + + /// + /// Odd stagger index. + /// Even } +/// +/// Represents a Tiled map. +/// public class Map { - // Attributes + /// + /// The TMX format version. Is incremented to match minor Tiled releases. + /// public required string Version { get; set; } + + /// + /// The Tiled version used to save the file. + /// public required string TiledVersion { get; set; } + + /// + /// The class of this map. + /// public string Class { get; set; } = ""; + + /// + /// Map orientation. + /// public required MapOrientation Orientation { get; set; } + + /// + /// The order in which tiles on tile layers are rendered. + /// public RenderOrder RenderOrder { get; set; } = RenderOrder.RightDown; + + /// + /// The compression level to use for tile layer data (defaults to -1, which means to use the algorithm default). + /// Typically only useful for parsing, but may be interesting for certain use cases. + /// public int CompressionLevel { get; set; } = -1; + + /// + /// The width of the map in tiles. + /// public required uint Width { get; set; } + + /// + /// The height of the map in tiles. + /// public required uint Height { get; set; } + + /// + /// The width of a tile. + /// public required uint TileWidth { get; set; } + + /// + /// The height of a tile. + /// public required uint TileHeight { get; set; } + + /// + /// Only for hexagonal maps. Determines the width or height (depending on the staggered axis) of the tile's edge, in pixels. + /// public uint? HexSideLength { get; set; } + + /// + /// For staggered and hexagonal maps, determines which axis (X or Y) is staggered. + /// public StaggerAxis? StaggerAxis { get; set; } + + /// + /// For staggered and hexagonal maps, determines whether the "even" or "odd" indexes along the staggered axis are shifted. + /// public StaggerIndex? StaggerIndex { get; set; } + + /// + /// X coordinate of the parallax origin in pixels. + /// public float ParallaxOriginX { get; set; } = 0.0f; + + /// + /// Y coordinate of the parallax origin in pixels. + /// public float ParallaxOriginY { get; set; } = 0.0f; + + /// + /// The background color of the map. + /// public Color BackgroundColor { get; set; } = Color.Parse("#00000000", CultureInfo.InvariantCulture); + + /// + /// Stores the next available ID for new layers. This number is used to prevent reuse of the same ID after layers have been removed. + /// public required uint NextLayerID { get; set; } + + /// + /// Stores the next available ID for new objects. This number is used to prevent reuse of the same ID after objects have been removed. + /// public required uint NextObjectID { get; set; } + + /// + /// Whether this map is infinite. An infinite map has no fixed size and can grow in all directions. Its layer data is stored in chunks. + /// public bool Infinite { get; set; } = false; - // At most one of + /// + /// Map properties. + /// public Dictionary? Properties { get; set; } - // Any number of + /// + /// List of tilesets used by the map. + /// public List Tilesets { get; set; } = []; + + /// + /// Hierarchical list of layers. is a layer type which can contain sub-layers to create a hierarchy. + /// public List Layers { get; set; } = []; } diff --git a/src/DotTiled/Model/Properties/BoolProperty.cs b/src/DotTiled/Model/Properties/BoolProperty.cs index 6360a3a..af57a91 100644 --- a/src/DotTiled/Model/Properties/BoolProperty.cs +++ b/src/DotTiled/Model/Properties/BoolProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Properties; +namespace DotTiled.Model; public class BoolProperty : IProperty { diff --git a/src/DotTiled/Model/Properties/ClassProperty.cs b/src/DotTiled/Model/Properties/ClassProperty.cs index e46389f..8117e7f 100644 --- a/src/DotTiled/Model/Properties/ClassProperty.cs +++ b/src/DotTiled/Model/Properties/ClassProperty.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace DotTiled.Model.Properties; +namespace DotTiled.Model; public class ClassProperty : IProperty { diff --git a/src/DotTiled/Model/Properties/ColorProperty.cs b/src/DotTiled/Model/Properties/ColorProperty.cs index 06d8fc1..83e5852 100644 --- a/src/DotTiled/Model/Properties/ColorProperty.cs +++ b/src/DotTiled/Model/Properties/ColorProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Properties; +namespace DotTiled.Model; public class ColorProperty : IProperty { diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs b/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs index c080e2a..888d268 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs +++ b/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace DotTiled.Model.Properties.CustomTypes; +namespace DotTiled.Model; [Flags] public enum CustomClassUseAs diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs b/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs index 9d15b7d..602eef0 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs +++ b/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotTiled.Model.Properties.CustomTypes; +namespace DotTiled.Model; public enum CustomEnumStorageType { diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs b/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs index f535215..5670ebe 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs +++ b/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Properties.CustomTypes; +namespace DotTiled.Model; public abstract class CustomTypeDefinition { diff --git a/src/DotTiled/Model/Properties/FileProperty.cs b/src/DotTiled/Model/Properties/FileProperty.cs index 42b9d15..f6b1314 100644 --- a/src/DotTiled/Model/Properties/FileProperty.cs +++ b/src/DotTiled/Model/Properties/FileProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Properties; +namespace DotTiled.Model; public class FileProperty : IProperty { diff --git a/src/DotTiled/Model/Properties/FloatProperty.cs b/src/DotTiled/Model/Properties/FloatProperty.cs index ccb18ae..fbbc797 100644 --- a/src/DotTiled/Model/Properties/FloatProperty.cs +++ b/src/DotTiled/Model/Properties/FloatProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Properties; +namespace DotTiled.Model; public class FloatProperty : IProperty { diff --git a/src/DotTiled/Model/Properties/IProperty.cs b/src/DotTiled/Model/Properties/IProperty.cs index 0414c3c..925eff0 100644 --- a/src/DotTiled/Model/Properties/IProperty.cs +++ b/src/DotTiled/Model/Properties/IProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Properties; +namespace DotTiled.Model; public interface IProperty { diff --git a/src/DotTiled/Model/Properties/IntProperty.cs b/src/DotTiled/Model/Properties/IntProperty.cs index cfaf7d0..cb4fe43 100644 --- a/src/DotTiled/Model/Properties/IntProperty.cs +++ b/src/DotTiled/Model/Properties/IntProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Properties; +namespace DotTiled.Model; public class IntProperty : IProperty { diff --git a/src/DotTiled/Model/Properties/ObjectProperty.cs b/src/DotTiled/Model/Properties/ObjectProperty.cs index 5f37607..ee2b02d 100644 --- a/src/DotTiled/Model/Properties/ObjectProperty.cs +++ b/src/DotTiled/Model/Properties/ObjectProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Properties; +namespace DotTiled.Model; public class ObjectProperty : IProperty { diff --git a/src/DotTiled/Model/Properties/PropertyType.cs b/src/DotTiled/Model/Properties/PropertyType.cs index bb01960..88a1cda 100644 --- a/src/DotTiled/Model/Properties/PropertyType.cs +++ b/src/DotTiled/Model/Properties/PropertyType.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Properties; +namespace DotTiled.Model; public enum PropertyType { diff --git a/src/DotTiled/Model/Properties/StringProperty.cs b/src/DotTiled/Model/Properties/StringProperty.cs index 9842ca4..965d08b 100644 --- a/src/DotTiled/Model/Properties/StringProperty.cs +++ b/src/DotTiled/Model/Properties/StringProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Properties; +namespace DotTiled.Model; public class StringProperty : IProperty { diff --git a/src/DotTiled/Model/Template.cs b/src/DotTiled/Model/Template.cs index 834f8d8..d8cee95 100644 --- a/src/DotTiled/Model/Template.cs +++ b/src/DotTiled/Model/Template.cs @@ -1,11 +1,17 @@ -using DotTiled.Model.Layers.Objects; -using DotTiled.Model.Tilesets; - namespace DotTiled.Model; +/// +/// Represents a Tiled template. A template is a reusable object that can be placed in an inside the Tiled editor. +/// public class Template { - // At most one of (if the template is a tile object) + /// + /// If the template represents a tile object, this property will contain the tileset that the tile belongs to. + /// public Tileset? Tileset { get; set; } + + /// + /// The object that this template represents. + /// public required Object Object { get; set; } } diff --git a/src/DotTiled/Model/Tilesets/Frame.cs b/src/DotTiled/Model/Tilesets/Frame.cs index 8762423..f57f579 100644 --- a/src/DotTiled/Model/Tilesets/Frame.cs +++ b/src/DotTiled/Model/Tilesets/Frame.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Tilesets; +namespace DotTiled.Model; public class Frame { diff --git a/src/DotTiled/Model/Tilesets/Grid.cs b/src/DotTiled/Model/Tilesets/Grid.cs index 81d5e06..d98ad6f 100644 --- a/src/DotTiled/Model/Tilesets/Grid.cs +++ b/src/DotTiled/Model/Tilesets/Grid.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Tilesets; +namespace DotTiled.Model; public enum GridOrientation { diff --git a/src/DotTiled/Model/Tilesets/Image.cs b/src/DotTiled/Model/Tilesets/Image.cs index e5ea154..d776bb8 100644 --- a/src/DotTiled/Model/Tilesets/Image.cs +++ b/src/DotTiled/Model/Tilesets/Image.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Tilesets; +namespace DotTiled.Model; public enum ImageFormat { diff --git a/src/DotTiled/Model/Tilesets/Tile.cs b/src/DotTiled/Model/Tilesets/Tile.cs index 55669ee..26c6057 100644 --- a/src/DotTiled/Model/Tilesets/Tile.cs +++ b/src/DotTiled/Model/Tilesets/Tile.cs @@ -1,8 +1,6 @@ using System.Collections.Generic; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -namespace DotTiled.Model.Tilesets; +namespace DotTiled.Model; public class Tile { diff --git a/src/DotTiled/Model/Tilesets/TileOffset.cs b/src/DotTiled/Model/Tilesets/TileOffset.cs index cbe9111..2b2e620 100644 --- a/src/DotTiled/Model/Tilesets/TileOffset.cs +++ b/src/DotTiled/Model/Tilesets/TileOffset.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Tilesets; +namespace DotTiled.Model; public class TileOffset { diff --git a/src/DotTiled/Model/Tilesets/Tileset.cs b/src/DotTiled/Model/Tilesets/Tileset.cs index 15bd56b..639fe62 100644 --- a/src/DotTiled/Model/Tilesets/Tileset.cs +++ b/src/DotTiled/Model/Tilesets/Tileset.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; -using DotTiled.Model.Properties; -namespace DotTiled.Model.Tilesets; +namespace DotTiled.Model; public enum ObjectAlignment { diff --git a/src/DotTiled/Model/Tilesets/Transformations.cs b/src/DotTiled/Model/Tilesets/Transformations.cs index 83187a7..1a84549 100644 --- a/src/DotTiled/Model/Tilesets/Transformations.cs +++ b/src/DotTiled/Model/Tilesets/Transformations.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Tilesets; +namespace DotTiled.Model; public class Transformations { diff --git a/src/DotTiled/Model/Tilesets/WangColor.cs b/src/DotTiled/Model/Tilesets/WangColor.cs index c13b0da..d3a0328 100644 --- a/src/DotTiled/Model/Tilesets/WangColor.cs +++ b/src/DotTiled/Model/Tilesets/WangColor.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; -using DotTiled.Model.Properties; -namespace DotTiled.Model.Tilesets; +namespace DotTiled.Model; public class WangColor { diff --git a/src/DotTiled/Model/Tilesets/WangTile.cs b/src/DotTiled/Model/Tilesets/WangTile.cs index 488a12a..d526d71 100644 --- a/src/DotTiled/Model/Tilesets/WangTile.cs +++ b/src/DotTiled/Model/Tilesets/WangTile.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model.Tilesets; +namespace DotTiled.Model; public class WangTile { diff --git a/src/DotTiled/Model/Tilesets/Wangset.cs b/src/DotTiled/Model/Tilesets/Wangset.cs index 6101347..653f43f 100644 --- a/src/DotTiled/Model/Tilesets/Wangset.cs +++ b/src/DotTiled/Model/Tilesets/Wangset.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; -using DotTiled.Model.Properties; -namespace DotTiled.Model.Tilesets; +namespace DotTiled.Model; public class Wangset { diff --git a/src/DotTiled/Serialization/Helpers.cs b/src/DotTiled/Serialization/Helpers.cs index abfba09..fe401ba 100644 --- a/src/DotTiled/Serialization/Helpers.cs +++ b/src/DotTiled/Serialization/Helpers.cs @@ -3,9 +3,9 @@ using System.IO; using System.IO.Compression; using System.Linq; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Tilesets; +using DotTiled.Model; +using DotTiled.Model; +using DotTiled.Model; namespace DotTiled.Serialization; diff --git a/src/DotTiled/Serialization/ITilesetReader.cs b/src/DotTiled/Serialization/ITilesetReader.cs index fa4a94c..803ea8e 100644 --- a/src/DotTiled/Serialization/ITilesetReader.cs +++ b/src/DotTiled/Serialization/ITilesetReader.cs @@ -1,5 +1,5 @@ using System; -using DotTiled.Model.Tilesets; +using DotTiled.Model; namespace DotTiled.Serialization; diff --git a/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs b/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs index 69747bb..a10a1f3 100644 --- a/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs +++ b/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using DotTiled.Model; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Data.cs b/src/DotTiled/Serialization/Tmj/Tmj.Data.cs index ac3d30b..2edb93f 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Data.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Data.cs @@ -5,7 +5,7 @@ using System.IO.Compression; using System.Linq; using System.Text.Json; -using DotTiled.Model.Layers; +using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Group.cs b/src/DotTiled/Serialization/Tmj/Tmj.Group.cs index 159d892..796458b 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Group.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Group.cs @@ -4,9 +4,6 @@ using System.Numerics; using System.Text.Json; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs index e3d6112..70d9ce4 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs @@ -4,10 +4,7 @@ using System.Numerics; using System.Text.Json; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; +using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs b/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs index d81ce17..fb02fe5 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs @@ -4,8 +4,6 @@ using System.Numerics; using System.Text.Json; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties.CustomTypes; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs b/src/DotTiled/Serialization/Tmj/Tmj.Map.cs index e27dfed..642d8f4 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Map.cs @@ -5,10 +5,6 @@ using System.Linq; using System.Text.Json; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs index 0662fc9..af0449b 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs @@ -4,10 +4,6 @@ using System.Numerics; using System.Text.Json; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Layers.Objects; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs b/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs index 1ef4944..28aad66 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs @@ -4,8 +4,6 @@ using System.Linq; using System.Text.Json; using DotTiled.Model; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Template.cs b/src/DotTiled/Serialization/Tmj/Tmj.Template.cs index 65d6f87..a9a8766 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Template.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Template.cs @@ -4,8 +4,6 @@ using System.Numerics; using System.Text.Json; using DotTiled.Model; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs index d2fd53d..3711eb2 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs @@ -4,9 +4,6 @@ using System.Numerics; using System.Text.Json; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs b/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs index 8b206c9..0d6dfc7 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs @@ -6,10 +6,6 @@ using System.Linq; using System.Text.Json; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs index 3eb1df0..23d9754 100644 --- a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs +++ b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs @@ -4,8 +4,6 @@ using System.Text; using System.Text.Json; using DotTiled.Model; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs index a41adfe..7ddae3e 100644 --- a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using DotTiled.Model; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Chunk.cs b/src/DotTiled/Serialization/Tmx/Tmx.Chunk.cs index d0db01f..b42ebb0 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Chunk.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Chunk.cs @@ -1,5 +1,5 @@ using System.Xml; -using DotTiled.Model.Layers; +using DotTiled.Model; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Data.cs b/src/DotTiled/Serialization/Tmx/Tmx.Data.cs index 5d55ba4..77f7d6a 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Data.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Data.cs @@ -4,7 +4,7 @@ using System.IO.Compression; using System.Linq; using System.Xml; -using DotTiled.Model.Layers; +using DotTiled.Model; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs b/src/DotTiled/Serialization/Tmx/Tmx.Map.cs index 2152852..e7a5e35 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Map.cs @@ -4,10 +4,6 @@ using System.Linq; using System.Xml; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs b/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs index 5f5bda0..523b224 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs @@ -5,11 +5,6 @@ using System.Numerics; using System.Xml; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Layers.Objects; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs b/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs index 7f62358..3d5b6c4 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs @@ -2,8 +2,6 @@ using System.Linq; using System.Xml; using DotTiled.Model; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs b/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs index 41e720b..8b972a3 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs @@ -3,10 +3,6 @@ using System.Linq; using System.Xml; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs b/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs index 5d8aac6..6e43455 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs @@ -4,10 +4,6 @@ using System.Linq; using System.Xml; using DotTiled.Model; -using DotTiled.Model.Layers; -using DotTiled.Model.Properties; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs index f9228b4..091f161 100644 --- a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs +++ b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Xml; using DotTiled.Model; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs index f7a1565..0cc4e2f 100644 --- a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Xml; using DotTiled.Model; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs index 3fa6c69..e640dd8 100644 --- a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs +++ b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Xml; using DotTiled.Model; -using DotTiled.Model.Properties.CustomTypes; -using DotTiled.Model.Tilesets; namespace DotTiled.Serialization.Tmx; From 0d19127fb74c5b7ac6c2172d272894d89a3ec315 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Tue, 20 Aug 2024 23:23:40 +0200 Subject: [PATCH 02/23] Add XML docs for entire model --- Makefile | 32 ++-- src/DotTiled.Tests/Assert/AssertObject.cs | 22 +-- src/DotTiled/Model/Layers/BaseLayer.cs | 49 +++++- src/DotTiled/Model/Layers/Data.cs | 101 +++++++++++- src/DotTiled/Model/Layers/Group.cs | 9 +- src/DotTiled/Model/Layers/ImageLayer.cs | 23 ++- src/DotTiled/Model/Layers/ObjectLayer.cs | 41 ++++- .../Model/Layers/Objects/EllipseObject.cs | 4 + src/DotTiled/Model/Layers/Objects/Object.cs | 47 +++++- .../Model/Layers/Objects/PointObject.cs | 4 + .../Model/Layers/Objects/PolygonObject.cs | 9 +- .../Model/Layers/Objects/PolylineObject.cs | 8 +- .../Model/Layers/Objects/RectangleObject.cs | 4 + .../Model/Layers/Objects/TextObject.cs | 83 +++++++++- .../Model/Layers/Objects/TileObject.cs | 6 + src/DotTiled/Model/Layers/TileLayer.cs | 23 ++- src/DotTiled/Model/Properties/BoolProperty.cs | 11 ++ .../Model/Properties/ClassProperty.cs | 18 +- .../Model/Properties/ColorProperty.cs | 11 ++ .../CustomTypes/CustomClassDefinition.cs | 62 +++++++ .../CustomTypes/CustomEnumDefinition.cs | 25 +++ .../CustomTypes/CustomTypeDefinition.cs | 10 ++ src/DotTiled/Model/Properties/FileProperty.cs | 11 ++ .../Model/Properties/FloatProperty.cs | 11 ++ src/DotTiled/Model/Properties/IProperty.cs | 15 ++ src/DotTiled/Model/Properties/IntProperty.cs | 11 ++ .../Model/Properties/ObjectProperty.cs | 11 ++ src/DotTiled/Model/Properties/PropertyType.cs | 34 ++++ .../Model/Properties/StringProperty.cs | 11 ++ src/DotTiled/Model/Tilesets/Frame.cs | 11 +- src/DotTiled/Model/Tilesets/Grid.cs | 25 ++- src/DotTiled/Model/Tilesets/Image.cs | 41 ++++- src/DotTiled/Model/Tilesets/Tile.cs | 48 +++++- src/DotTiled/Model/Tilesets/TileOffset.cs | 11 +- src/DotTiled/Model/Tilesets/Tileset.cs | 154 +++++++++++++++++- .../Model/Tilesets/Transformations.cs | 19 ++- src/DotTiled/Model/Tilesets/WangColor.cs | 27 ++- src/DotTiled/Model/Tilesets/WangTile.cs | 11 +- src/DotTiled/Model/Tilesets/Wangset.cs | 27 ++- .../Serialization/Tmj/Tmj.ObjectLayer.cs | 4 +- .../Serialization/Tmj/Tmj.Template.cs | 2 +- .../Serialization/Tmx/Tmx.ObjectLayer.cs | 12 +- 42 files changed, 1023 insertions(+), 75 deletions(-) diff --git a/Makefile b/Makefile index 66cf561..a65d55f 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,17 @@ -test: - dotnet test src/DotTiled.sln - -docs-serve: docs-build - docfx docs/docfx.json --serve - -docs-build: - cp README.md docs/index.md - docfx docs/docfx.json - -BENCHMARK_SOURCES = DotTiled.Benchmark/Program.cs DotTiled.Benchmark/DotTiled.Benchmark.csproj -BENCHMARK_OUTPUTDIR = DotTiled.Benchmark/BenchmarkDotNet.Artifacts -.PHONY: benchmark -benchmark: $(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md - -$(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md: $(BENCHMARK_SOURCES) +test: + dotnet test src/DotTiled.sln + +docs-serve: + docfx docs/docfx.json --serve + +docs-build: + cp README.md docs/index.md + docfx docs/docfx.json + +BENCHMARK_SOURCES = DotTiled.Benchmark/Program.cs DotTiled.Benchmark/DotTiled.Benchmark.csproj +BENCHMARK_OUTPUTDIR = DotTiled.Benchmark/BenchmarkDotNet.Artifacts +.PHONY: benchmark +benchmark: $(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md + +$(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md: $(BENCHMARK_SOURCES) dotnet run --project DotTiled.Benchmark/DotTiled.Benchmark.csproj -c Release -- $(BENCHMARK_OUTPUTDIR) \ No newline at end of file diff --git a/src/DotTiled.Tests/Assert/AssertObject.cs b/src/DotTiled.Tests/Assert/AssertObject.cs index 93a5c45..d982ebd 100644 --- a/src/DotTiled.Tests/Assert/AssertObject.cs +++ b/src/DotTiled.Tests/Assert/AssertObject.cs @@ -4,19 +4,19 @@ namespace DotTiled.Tests; public static partial class DotTiledAssert { - internal static void AssertObject(Model.Layers.Objects.Object expected, Model.Layers.Objects.Object actual) + internal static void AssertObject(Model.Object expected, Model.Object actual) { // Attributes - AssertEqual(expected.ID, actual.ID, nameof(Model.Layers.Objects.Object.ID)); - AssertEqual(expected.Name, actual.Name, nameof(Model.Layers.Objects.Object.Name)); - AssertEqual(expected.Type, actual.Type, nameof(Model.Layers.Objects.Object.Type)); - AssertEqual(expected.X, actual.X, nameof(Model.Layers.Objects.Object.X)); - AssertEqual(expected.Y, actual.Y, nameof(Model.Layers.Objects.Object.Y)); - AssertEqual(expected.Width, actual.Width, nameof(Model.Layers.Objects.Object.Width)); - AssertEqual(expected.Height, actual.Height, nameof(Model.Layers.Objects.Object.Height)); - AssertEqual(expected.Rotation, actual.Rotation, nameof(Model.Layers.Objects.Object.Rotation)); - AssertEqual(expected.Visible, actual.Visible, nameof(Model.Layers.Objects.Object.Visible)); - AssertEqual(expected.Template, actual.Template, nameof(Model.Layers.Objects.Object.Template)); + AssertEqual(expected.ID, actual.ID, nameof(Model.Object.ID)); + AssertEqual(expected.Name, actual.Name, nameof(Model.Object.Name)); + AssertEqual(expected.Type, actual.Type, nameof(Model.Object.Type)); + AssertEqual(expected.X, actual.X, nameof(Model.Object.X)); + AssertEqual(expected.Y, actual.Y, nameof(Model.Object.Y)); + AssertEqual(expected.Width, actual.Width, nameof(Model.Object.Width)); + AssertEqual(expected.Height, actual.Height, nameof(Model.Object.Height)); + AssertEqual(expected.Rotation, actual.Rotation, nameof(Model.Object.Rotation)); + AssertEqual(expected.Visible, actual.Visible, nameof(Model.Object.Visible)); + AssertEqual(expected.Template, actual.Template, nameof(Model.Object.Template)); AssertProperties(expected.Properties, actual.Properties); diff --git a/src/DotTiled/Model/Layers/BaseLayer.cs b/src/DotTiled/Model/Layers/BaseLayer.cs index f73c760..aa78191 100644 --- a/src/DotTiled/Model/Layers/BaseLayer.cs +++ b/src/DotTiled/Model/Layers/BaseLayer.cs @@ -2,20 +2,65 @@ namespace DotTiled.Model; +/// +/// Base class for all layer types in a map. +/// 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 { - // Attributes + /// + /// 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. + /// public required uint ID { get; set; } + + /// + /// The name of the layer. + /// public string Name { get; set; } = ""; + + /// + /// The class of the layer. + /// public string Class { get; set; } = ""; + + /// + /// The opacity of the layer as a value from 0 (fully transparent) to 1 (fully opaque). + /// public float Opacity { get; set; } = 1.0f; + + /// + /// Whether the layer is shown (true) or hidden (false). + /// public bool Visible { get; set; } = true; + + /// + /// A tint color that is multiplied with any tiles drawn by this layer. + /// public Color? TintColor { get; set; } + + /// + /// Horizontal offset for this layer in pixels. + /// public float OffsetX { get; set; } = 0.0f; + + /// + /// Vertical offset for this layer in pixels. + /// public float OffsetY { get; set; } = 0.0f; + + /// + /// Horizontal parallax factor for this layer. + /// public float ParallaxX { get; set; } = 1.0f; + + /// + /// Vertical parallax factor for this layer. + /// public float ParallaxY { get; set; } = 1.0f; - // At most one of + /// + /// Layer properties. + /// public Dictionary? Properties { get; set; } } diff --git a/src/DotTiled/Model/Layers/Data.cs b/src/DotTiled/Model/Layers/Data.cs index 7388828..d2a9686 100644 --- a/src/DotTiled/Model/Layers/Data.cs +++ b/src/DotTiled/Model/Layers/Data.cs @@ -2,50 +2,143 @@ namespace DotTiled.Model; +/// +/// Specifies the encoding used to encode the tile layer data. +/// public enum DataEncoding { + /// + /// The data is stored as comma-separated values. + /// Csv, + + /// + /// The data is stored as base64-encoded binary data. + /// Base64 } +/// +/// Specifies the compression algorithm used to compress the tile layer data. +/// public enum DataCompression { + /// + /// GZip compression. + /// GZip, + + /// + /// ZLib compression. + /// ZLib, + + /// + /// ZStandard compression. Currently not supported by DotTiled and will throw an exception if encountered. + /// ZStd } +/// +/// The flipping flags for a tile. These can be used to check how a tile is flipped or rotated. Uses the +/// FlagsAttribute, for which there is plenty of documentation. +/// [Flags] public enum FlippingFlags : uint { + /// + /// No flipping. + /// None = 0, + + /// + /// The tile is flipped horizontally. + /// FlippedHorizontally = 0x80000000u, + + /// + /// The tile is flipped vertically. + /// FlippedVertically = 0x40000000u, + + /// + /// The tile is flipped diagonally. + /// FlippedDiagonally = 0x20000000u, + + /// + /// In hexagonal maps, the tile is rotated 120 degrees clockwise. + /// RotatedHexagonal120 = 0x10000000u } +/// +/// Represents part of a tile layer of a map that is infinite. +/// public class Chunk { - // Attributes + /// + /// The X coordinate of the chunk in tiles. + /// public required int X { get; set; } + + /// + /// The Y coordinate of the chunk in tiles. + /// public required int Y { get; set; } + + /// + /// The width of the chunk in tiles. + /// public required uint Width { get; set; } + + /// + /// The height of the chunk in tiles. + /// public required uint Height { get; set; } - // Data + /// + /// The parsed chunk data, as a list of tile GIDs. + /// To get an actual tile ID, you map it to a local tile ID using the correct tileset. Please refer to + /// the documentation on how to do this. + /// public required uint[] GlobalTileIDs { get; set; } + + /// + /// The parsed flipping flags for each tile in the chunk. Appear in the same order as the tiles in the layer in . + /// public required FlippingFlags[] FlippingFlags { get; set; } } +/// +/// Represents the data of a tile layer. +/// public class Data { - // Attributes + /// + /// The encoding used to encode the tile layer data. + /// public DataEncoding? Encoding { get; set; } + + /// + /// The compression method used to compress the tile layer data. + /// public DataCompression? Compression { get; set; } - // Data + /// + /// The parsed tile layer data, as a list of tile GIDs. + /// To get an actual tile ID, you map it to a local tile ID using the correct tileset. Please refer to + /// the documentation on how to do this. + /// public uint[]? GlobalTileIDs { get; set; } + + /// + /// The parsed flipping flags for each tile in the layer. Appear in the same order as the tiles in the layer in . + /// public FlippingFlags[]? FlippingFlags { get; set; } + + /// + /// If the map is infinite, it will instead contain a list of chunks. + /// public Chunk[]? Chunks { get; set; } } diff --git a/src/DotTiled/Model/Layers/Group.cs b/src/DotTiled/Model/Layers/Group.cs index 9fa68da..f770c63 100644 --- a/src/DotTiled/Model/Layers/Group.cs +++ b/src/DotTiled/Model/Layers/Group.cs @@ -2,10 +2,13 @@ namespace DotTiled.Model; +/// +/// Represents a group of layers, to form a hierarchy. +/// public class Group : BaseLayer { - // Uses same attributes as BaseLayer - - // Any number of + /// + /// The contained sub-layers in the group. + /// public List Layers { get; set; } = []; } diff --git a/src/DotTiled/Model/Layers/ImageLayer.cs b/src/DotTiled/Model/Layers/ImageLayer.cs index fbdf54e..e0bb110 100644 --- a/src/DotTiled/Model/Layers/ImageLayer.cs +++ b/src/DotTiled/Model/Layers/ImageLayer.cs @@ -1,13 +1,32 @@ namespace DotTiled.Model; +/// +/// Represents an image layer in a map. +/// public class ImageLayer : BaseLayer { - // Attributes + /// + /// The X position of the image layer in pixels. + /// public uint X { get; set; } = 0; + + /// + /// The Y position of the image layer in pixels. + /// public uint Y { get; set; } = 0; + + /// + /// Whether the image drawn by this layer is repeated along the X axis. + /// public bool RepeatX { get; set; } = false; + + /// + /// Whether the image drawn by this layer is repeated along the Y axis. + /// public bool RepeatY { get; set; } = false; - // At most one of + /// + /// The image to be drawn by this image layer. + /// public Image? Image { get; set; } } diff --git a/src/DotTiled/Model/Layers/ObjectLayer.cs b/src/DotTiled/Model/Layers/ObjectLayer.cs index 04f97dd..60acc13 100644 --- a/src/DotTiled/Model/Layers/ObjectLayer.cs +++ b/src/DotTiled/Model/Layers/ObjectLayer.cs @@ -2,22 +2,59 @@ namespace DotTiled.Model; +/// +/// Represents the order in which objects can be drawn. +/// public enum DrawOrder { + /// + /// Objects are drawn sorted by their Y coordinate. + /// TopDown, + + /// + /// Objects are drawn in the order of appearance in the object layer. + /// Index } +/// +/// Represents an object layer in a map. In Tiled documentation, it is often called an "object group". +/// public class ObjectLayer : BaseLayer { - // Attributes + /// + /// The X coordinate of the object layer in tiles. + /// public uint X { get; set; } = 0; + + /// + /// The Y coordinate of the object layer in tiles. + /// public uint Y { get; set; } = 0; + + /// + /// The width of the object layer in tiles. Meaningless. + /// public uint? Width { get; set; } + + /// + /// The height of the object layer in tiles. Meaningless. + /// public uint? Height { get; set; } + + /// + /// A color that is multiplied with any tile objects drawn by this layer. + /// public Color? Color { get; set; } + + /// + /// Whether the objects are drawn according to the order of appearance () or sorted by their Y coordinate (). + /// public DrawOrder DrawOrder { get; set; } = DrawOrder.TopDown; - // Elements + /// + /// The objects in the object layer. + /// public required List Objects { get; set; } } diff --git a/src/DotTiled/Model/Layers/Objects/EllipseObject.cs b/src/DotTiled/Model/Layers/Objects/EllipseObject.cs index 8e75338..7e777de 100644 --- a/src/DotTiled/Model/Layers/Objects/EllipseObject.cs +++ b/src/DotTiled/Model/Layers/Objects/EllipseObject.cs @@ -1,3 +1,7 @@ namespace DotTiled.Model; +/// +/// An ellipse object in a map. The existing , , , +/// and properties are used to determine the size of the ellipse. +/// public class EllipseObject : Object { } diff --git a/src/DotTiled/Model/Layers/Objects/Object.cs b/src/DotTiled/Model/Layers/Objects/Object.cs index 98935b1..fad05db 100644 --- a/src/DotTiled/Model/Layers/Objects/Object.cs +++ b/src/DotTiled/Model/Layers/Objects/Object.cs @@ -2,20 +2,63 @@ namespace DotTiled.Model; +/// +/// Base class for objects in object layers. +/// public abstract class Object { - // Attributes + /// + /// 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. + /// public uint? ID { get; set; } + + /// + /// The name of the object. An arbitrary string. + /// public string Name { get; set; } = ""; + + /// + /// The class of the object. An arbitrary string. + /// public string Type { get; set; } = ""; + + /// + /// The X coordinate of the object in pixels. + /// public float X { get; set; } = 0f; + + /// + /// The Y coordinate of the object in pixels. + /// public float Y { get; set; } = 0f; + + /// + /// The width of the object in pixels. + /// public float Width { get; set; } = 0f; + + /// + /// The height of the object in pixels. + /// public float Height { get; set; } = 0f; + + /// + /// The rotation of the object in degrees clockwise around (X, Y). + /// public float Rotation { get; set; } = 0f; + + /// + /// Whether the object is shown (true) or hidden (false). + /// public bool Visible { get; set; } = true; + + /// + /// A reference to a template file. + /// public string? Template { get; set; } - // Elements + /// + /// Object properties. + /// public Dictionary? Properties { get; set; } } diff --git a/src/DotTiled/Model/Layers/Objects/PointObject.cs b/src/DotTiled/Model/Layers/Objects/PointObject.cs index e606c37..44eada8 100644 --- a/src/DotTiled/Model/Layers/Objects/PointObject.cs +++ b/src/DotTiled/Model/Layers/Objects/PointObject.cs @@ -1,3 +1,7 @@ namespace DotTiled.Model; +/// +/// A point object in a map. The existing and properties are used to +/// determine the position of the point. +/// public class PointObject : Object { } diff --git a/src/DotTiled/Model/Layers/Objects/PolygonObject.cs b/src/DotTiled/Model/Layers/Objects/PolygonObject.cs index 6a58592..09805d8 100644 --- a/src/DotTiled/Model/Layers/Objects/PolygonObject.cs +++ b/src/DotTiled/Model/Layers/Objects/PolygonObject.cs @@ -3,8 +3,15 @@ namespace DotTiled.Model; +/// +/// A polygon object in a map. The existing and properties are used as +/// the origin of the polygon. +/// public class PolygonObject : Object { - // Attributes + /// + /// The points that make up the polygon. + /// and are used as the origin of the polygon. + /// public required List Points { get; set; } } diff --git a/src/DotTiled/Model/Layers/Objects/PolylineObject.cs b/src/DotTiled/Model/Layers/Objects/PolylineObject.cs index e97d017..d267c07 100644 --- a/src/DotTiled/Model/Layers/Objects/PolylineObject.cs +++ b/src/DotTiled/Model/Layers/Objects/PolylineObject.cs @@ -3,8 +3,14 @@ namespace DotTiled.Model; +/// +/// A polyline object in a map. The existing and properties are used as +/// the origin of the polyline. +/// public class PolylineObject : Object { - // Attributes + /// + /// The points that make up the polyline. and are used as the origin of the polyline. + /// public required List Points { get; set; } } diff --git a/src/DotTiled/Model/Layers/Objects/RectangleObject.cs b/src/DotTiled/Model/Layers/Objects/RectangleObject.cs index 4fad428..99c6cff 100644 --- a/src/DotTiled/Model/Layers/Objects/RectangleObject.cs +++ b/src/DotTiled/Model/Layers/Objects/RectangleObject.cs @@ -1,3 +1,7 @@ namespace DotTiled.Model; +/// +/// A rectangle object in a map. The existing , , , +/// and properties are used to determine the size of the rectangle. +/// public class RectangleObject : Object { } diff --git a/src/DotTiled/Model/Layers/Objects/TextObject.cs b/src/DotTiled/Model/Layers/Objects/TextObject.cs index 2072c7f..9c5ed2d 100644 --- a/src/DotTiled/Model/Layers/Objects/TextObject.cs +++ b/src/DotTiled/Model/Layers/Objects/TextObject.cs @@ -2,36 +2,115 @@ namespace DotTiled.Model; +/// +/// The horizontal alignment of text. +/// public enum TextHorizontalAlignment { + /// + /// The text is aligned to the left. + /// Left, + + /// + /// The text is aligned to the center. + /// Center, + + /// + /// The text is aligned to the right. + /// Right, + + /// + /// The text is justified. + /// Justify } +/// +/// The vertical alignment of text. +/// public enum TextVerticalAlignment { + /// + /// The text is aligned to the top. + /// Top, + + /// + /// The text is aligned to the center. + /// Center, + + /// + /// The text is aligned to the bottom. + /// Bottom } +/// +/// A text object in a map. +/// public class TextObject : Object { - // Attributes + /// + /// The font family used for the text. + /// public string FontFamily { get; set; } = "sans-serif"; + + /// + /// The size of the font in pixels. + /// public int PixelSize { get; set; } = 16; + + /// + /// Whether word wrapping is enabled. + /// public bool Wrap { get; set; } = false; + + /// + /// The color of the text. + /// public Color Color { get; set; } = Color.Parse("#000000", CultureInfo.InvariantCulture); + + /// + /// Whether the text is bold. + /// public bool Bold { get; set; } = false; + + /// + /// Whether the text is italic. + /// public bool Italic { get; set; } = false; + + /// + /// Whether a line should be drawn below the text. + /// public bool Underline { get; set; } = false; + + /// + /// Whether a line should be drawn through the text. + /// public bool Strikeout { get; set; } = false; + + /// + /// Whether kerning should be used while rendering the text. + /// public bool Kerning { get; set; } = true; + + /// + /// The horizontal alignment of the text. + /// public TextHorizontalAlignment HorizontalAlignment { get; set; } = TextHorizontalAlignment.Left; + + /// + /// The vertical alignment of the text. + /// public TextVerticalAlignment VerticalAlignment { get; set; } = TextVerticalAlignment.Top; - // Elements + /// + /// The text to be displayed. + /// public string Text { get; set; } = ""; } diff --git a/src/DotTiled/Model/Layers/Objects/TileObject.cs b/src/DotTiled/Model/Layers/Objects/TileObject.cs index dc52100..fe44c50 100644 --- a/src/DotTiled/Model/Layers/Objects/TileObject.cs +++ b/src/DotTiled/Model/Layers/Objects/TileObject.cs @@ -1,6 +1,12 @@ namespace DotTiled.Model; +/// +/// A tile object in a map. +/// public class TileObject : Object { + /// + /// A reference to a tile. + /// public uint GID { get; set; } } diff --git a/src/DotTiled/Model/Layers/TileLayer.cs b/src/DotTiled/Model/Layers/TileLayer.cs index f314c1c..600f7c0 100644 --- a/src/DotTiled/Model/Layers/TileLayer.cs +++ b/src/DotTiled/Model/Layers/TileLayer.cs @@ -1,13 +1,32 @@ namespace DotTiled.Model; +/// +/// Represents a tile layer in a map. +/// public class TileLayer : BaseLayer { - // Attributes + /// + /// The X coordinate of the layer in tiles. + /// public uint X { get; set; } = 0; + + /// + /// The Y coordinate of the layer in tiles. + /// public uint Y { get; set; } = 0; + + /// + /// The width of the layer in tiles. Always the same as the map width for fixed-size maps. + /// public required uint Width { get; set; } + + /// + /// The height of the layer in tiles. Always the same as the map height for fixed-size maps. + /// public required uint Height { get; set; } - // At most one of + /// + /// The tile layer data. + /// public Data? Data { get; set; } } diff --git a/src/DotTiled/Model/Properties/BoolProperty.cs b/src/DotTiled/Model/Properties/BoolProperty.cs index af57a91..bc60a87 100644 --- a/src/DotTiled/Model/Properties/BoolProperty.cs +++ b/src/DotTiled/Model/Properties/BoolProperty.cs @@ -1,11 +1,22 @@ namespace DotTiled.Model; +/// +/// Represents a boolean property. +/// public class BoolProperty : IProperty { + /// public required string Name { get; set; } + + /// public PropertyType Type => PropertyType.Bool; + + /// + /// The boolean value of the property. + /// public required bool Value { get; set; } + /// public IProperty Clone() => new BoolProperty { Name = Name, diff --git a/src/DotTiled/Model/Properties/ClassProperty.cs b/src/DotTiled/Model/Properties/ClassProperty.cs index 8117e7f..50d65ba 100644 --- a/src/DotTiled/Model/Properties/ClassProperty.cs +++ b/src/DotTiled/Model/Properties/ClassProperty.cs @@ -3,13 +3,29 @@ namespace DotTiled.Model; +/// +/// Represents a class property. +/// public class ClassProperty : IProperty { + /// public required string Name { get; set; } - public PropertyType Type => Model.Properties.PropertyType.Class; + + /// + public PropertyType Type => Model.PropertyType.Class; + + /// + /// The type of the class property. This will be the name of a custom defined + /// type in Tiled. + /// public required string PropertyType { get; set; } + + /// + /// The properties of the class property. + /// public required Dictionary Properties { get; set; } + /// public IProperty Clone() => new ClassProperty { Name = Name, diff --git a/src/DotTiled/Model/Properties/ColorProperty.cs b/src/DotTiled/Model/Properties/ColorProperty.cs index 83e5852..aec43f6 100644 --- a/src/DotTiled/Model/Properties/ColorProperty.cs +++ b/src/DotTiled/Model/Properties/ColorProperty.cs @@ -1,11 +1,22 @@ namespace DotTiled.Model; +/// +/// Represents a color property. +/// public class ColorProperty : IProperty { + /// public required string Name { get; set; } + + /// public PropertyType Type => PropertyType.Color; + + /// + /// The color value of the property. + /// public required Color Value { get; set; } + /// public IProperty Clone() => new ColorProperty { Name = Name, diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs b/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs index 888d268..b5aa0ec 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs +++ b/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs @@ -3,25 +3,87 @@ namespace DotTiled.Model; +/// +/// Represents the types of objects that can use a custom class. +/// Uses the FlagsAttribute, for which there is plenty of documentation. +/// [Flags] public enum CustomClassUseAs { + /// + /// Any property on any kind of object. + /// Property, + + /// + /// A map. + /// Map, + + /// + /// A layer. + /// Layer, + + /// + /// An object. + /// Object, + + /// + /// A tile. + /// Tile, + + /// + /// A tileset. + /// Tileset, + + /// + /// A Wang color. + /// WangColor, + + /// + /// A Wangset. + /// Wangset, + + /// + /// A project. + /// Project, + + /// + /// All types. + /// All = Property | Map | Layer | Object | Tile | Tileset | WangColor | Wangset | Project } +/// +/// Represents a custom class definition in Tiled. Refer to the +/// documentation of custom types to understand how they work. +/// public class CustomClassDefinition : CustomTypeDefinition { + /// + /// The color of the custom class inside the Tiled editor. + /// public Color? Color { get; set; } + + /// + /// Whether the custom class should be drawn with a fill color. + /// public bool DrawFill { get; set; } + + /// + /// What the custom class can be used as, or rather, what types of objects can use it. + /// public CustomClassUseAs UseAs { get; set; } + + /// + /// The members of the custom class, with their names, types and default values. + /// public List Members { get; set; } = []; } diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs b/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs index 602eef0..ee40be0 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs +++ b/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs @@ -2,15 +2,40 @@ namespace DotTiled.Model; +/// +/// Represents the storage type of a custom enum. +/// public enum CustomEnumStorageType { + /// + /// The backing value is an integer. + /// Int, + + /// + /// The backing value is a string. + /// String } +/// +/// Represents a custom enum definition in Tiled. Refer to the +/// documentation of custom types to understand how they work. +/// public class CustomEnumDefinition : CustomTypeDefinition { + /// + /// The storage type of the custom enum. + /// public CustomEnumStorageType StorageType { get; set; } + + /// + /// The values of the custom enum. + /// public List Values { get; set; } = []; + + /// + /// Whether the value should be treated as flags. + /// public bool ValueAsFlags { get; set; } } diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs b/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs index 5670ebe..3a91b0a 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs +++ b/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs @@ -1,7 +1,17 @@ namespace DotTiled.Model; +/// +/// Base class for custom type definitions. +/// public abstract class CustomTypeDefinition { + /// + /// The ID of the custom type. + /// public uint ID { get; set; } + + /// + /// The name of the custom type. + /// public string Name { get; set; } = ""; } diff --git a/src/DotTiled/Model/Properties/FileProperty.cs b/src/DotTiled/Model/Properties/FileProperty.cs index f6b1314..4ed8642 100644 --- a/src/DotTiled/Model/Properties/FileProperty.cs +++ b/src/DotTiled/Model/Properties/FileProperty.cs @@ -1,11 +1,22 @@ namespace DotTiled.Model; +/// +/// Represents a file property. +/// public class FileProperty : IProperty { + /// public required string Name { get; set; } + + /// public PropertyType Type => PropertyType.File; + + /// + /// The value of the property. + /// public required string Value { get; set; } + /// public IProperty Clone() => new FileProperty { Name = Name, diff --git a/src/DotTiled/Model/Properties/FloatProperty.cs b/src/DotTiled/Model/Properties/FloatProperty.cs index fbbc797..4c6b51f 100644 --- a/src/DotTiled/Model/Properties/FloatProperty.cs +++ b/src/DotTiled/Model/Properties/FloatProperty.cs @@ -1,11 +1,22 @@ namespace DotTiled.Model; +/// +/// Represents a float property. +/// public class FloatProperty : IProperty { + /// public required string Name { get; set; } + + /// public PropertyType Type => PropertyType.Float; + + /// + /// The float value of the property. + /// public required float Value { get; set; } + /// public IProperty Clone() => new FloatProperty { Name = Name, diff --git a/src/DotTiled/Model/Properties/IProperty.cs b/src/DotTiled/Model/Properties/IProperty.cs index 925eff0..262ee09 100644 --- a/src/DotTiled/Model/Properties/IProperty.cs +++ b/src/DotTiled/Model/Properties/IProperty.cs @@ -1,9 +1,24 @@ namespace DotTiled.Model; +/// +/// Interface for properties that can be attached to objects, tiles, tilesets, maps etc. +/// public interface IProperty { + /// + /// The name of the property. + /// public string Name { get; set; } + + /// + /// The type of the property. + /// public PropertyType Type { get; } + /// + /// Clones the property, only used for copying properties when performing overriding + /// with templates. + /// + /// An identical, but non-reference-equal, instance of the same property. IProperty Clone(); } diff --git a/src/DotTiled/Model/Properties/IntProperty.cs b/src/DotTiled/Model/Properties/IntProperty.cs index cb4fe43..29f7a1d 100644 --- a/src/DotTiled/Model/Properties/IntProperty.cs +++ b/src/DotTiled/Model/Properties/IntProperty.cs @@ -1,11 +1,22 @@ namespace DotTiled.Model; +/// +/// Represents an integer property. +/// public class IntProperty : IProperty { + /// public required string Name { get; set; } + + /// public PropertyType Type => PropertyType.Int; + + /// + /// The integer value of the property. + /// public required int Value { get; set; } + /// public IProperty Clone() => new IntProperty { Name = Name, diff --git a/src/DotTiled/Model/Properties/ObjectProperty.cs b/src/DotTiled/Model/Properties/ObjectProperty.cs index ee2b02d..04b15ba 100644 --- a/src/DotTiled/Model/Properties/ObjectProperty.cs +++ b/src/DotTiled/Model/Properties/ObjectProperty.cs @@ -1,11 +1,22 @@ namespace DotTiled.Model; +/// +/// Represents an object property. +/// public class ObjectProperty : IProperty { + /// public required string Name { get; set; } + + /// public PropertyType Type => PropertyType.Object; + + /// + /// The object identifier referenced by the property. + /// public required uint Value { get; set; } + /// public IProperty Clone() => new ObjectProperty { Name = Name, diff --git a/src/DotTiled/Model/Properties/PropertyType.cs b/src/DotTiled/Model/Properties/PropertyType.cs index 88a1cda..d6057cc 100644 --- a/src/DotTiled/Model/Properties/PropertyType.cs +++ b/src/DotTiled/Model/Properties/PropertyType.cs @@ -1,13 +1,47 @@ namespace DotTiled.Model; +/// +/// Represents the type of a property. +/// public enum PropertyType { + /// + /// A string property. + /// String, + + /// + /// An integer property. + /// Int, + + /// + /// A float property. + /// Float, + + /// + /// A boolean property. + /// Bool, + + /// + /// A color property. + /// Color, + + /// + /// A file property. + /// File, + + /// + /// An object property. + /// Object, + + /// + /// A class property. + /// Class } diff --git a/src/DotTiled/Model/Properties/StringProperty.cs b/src/DotTiled/Model/Properties/StringProperty.cs index 965d08b..49d7aec 100644 --- a/src/DotTiled/Model/Properties/StringProperty.cs +++ b/src/DotTiled/Model/Properties/StringProperty.cs @@ -1,11 +1,22 @@ namespace DotTiled.Model; +/// +/// Represents a string property. +/// public class StringProperty : IProperty { + /// public required string Name { get; set; } + + /// public PropertyType Type => PropertyType.String; + + /// + /// The string value of the property. + /// public required string Value { get; set; } + /// public IProperty Clone() => new StringProperty { Name = Name, diff --git a/src/DotTiled/Model/Tilesets/Frame.cs b/src/DotTiled/Model/Tilesets/Frame.cs index f57f579..7e48aa0 100644 --- a/src/DotTiled/Model/Tilesets/Frame.cs +++ b/src/DotTiled/Model/Tilesets/Frame.cs @@ -1,8 +1,17 @@ namespace DotTiled.Model; +/// +/// A single frame of an animated tile. +/// public class Frame { - // Attributes + /// + /// The local tile ID within the parent tileset. + /// public required uint TileID { get; set; } + + /// + /// How long (in milliseconds) this frame should be displayed before advancing to the next frame. + /// public required uint Duration { get; set; } } diff --git a/src/DotTiled/Model/Tilesets/Grid.cs b/src/DotTiled/Model/Tilesets/Grid.cs index d98ad6f..e8acfac 100644 --- a/src/DotTiled/Model/Tilesets/Grid.cs +++ b/src/DotTiled/Model/Tilesets/Grid.cs @@ -1,15 +1,38 @@ namespace DotTiled.Model; +/// +/// Orientation of the grid for the tiles in this tileset. +/// public enum GridOrientation { + /// + /// The grid is orthogonal. + /// Orthogonal, + + /// + /// The grid is isometric. + /// Isometric } +/// +/// Used to specify how tile overlays for terrain and collision information are rendered in isometric maps. +/// public class Grid { - // Attributes + /// + /// Orientation of the grid for the tiles in this tileset. + /// public GridOrientation Orientation { get; set; } = GridOrientation.Orthogonal; + + /// + /// Width of a grid cell. + /// public required uint Width { get; set; } + + /// + /// Height of a grid cell. + /// public required uint Height { get; set; } } diff --git a/src/DotTiled/Model/Tilesets/Image.cs b/src/DotTiled/Model/Tilesets/Image.cs index d776bb8..418d5f4 100644 --- a/src/DotTiled/Model/Tilesets/Image.cs +++ b/src/DotTiled/Model/Tilesets/Image.cs @@ -1,19 +1,58 @@ namespace DotTiled.Model; +/// +/// The format of an image. +/// public enum ImageFormat { + /// + /// Portable Network Graphics. + /// Png, + + /// + /// Graphics Interchange Format. + /// Gif, + + /// + /// Joint Photographic Experts Group. + /// Jpg, + + /// + /// Windows Bitmap. + /// Bmp } +/// +/// Represents an image that is used by a tileset. +/// public class Image { - // Attributes + /// + /// The format of the image. + /// public ImageFormat? Format { get; set; } + + /// + /// The reference to the image file. + /// public string? Source { get; set; } + + /// + /// Defines a specific color that is treated as transparent. + /// public Color? TransparentColor { get; set; } + + /// + /// The image width in pixels, used for tile index correction when the image changes. + /// public uint? Width { get; set; } + + /// + /// The image height in pixels, used for tile index correction when the image changes. + /// public uint? Height { get; set; } } diff --git a/src/DotTiled/Model/Tilesets/Tile.cs b/src/DotTiled/Model/Tilesets/Tile.cs index 26c6057..c6b964d 100644 --- a/src/DotTiled/Model/Tilesets/Tile.cs +++ b/src/DotTiled/Model/Tilesets/Tile.cs @@ -2,20 +2,64 @@ 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 { - // Attributes + /// + /// The local tile ID within its tileset. + /// public required uint ID { get; set; } + + /// + /// The class of the tile. Is inherited by tile objects + /// public string Type { get; set; } = ""; + + /// + /// A percentage indicating the probability that this tile is chosen when it competes with others while editing with the terrain tool. + /// public float Probability { get; set; } = 0f; + + /// + /// The X position of the sub-rectangle representing this tile within the tileset image. + /// public uint X { get; set; } = 0; + + /// + /// The Y position of the sub-rectangle representing this tile within the tileset image. + /// public uint Y { get; set; } = 0; + + /// + /// The width of the sub-rectangle representing this tile within the tileset image. + /// public required uint Width { get; set; } + + /// + /// The height of the sub-rectangle representing this tile within the tileset image. + /// public required uint Height { get; set; } - // Elements + /// + /// Tile properties. + /// public Dictionary? Properties { get; set; } + + /// + /// The image representing this tile. Only used for tilesets that composed of a collection of images. + /// public Image? Image { get; set; } + + /// + /// Unclear what this is for. + /// public ObjectLayer? ObjectLayer { get; set; } + + /// + /// The animation frames for this tile. + /// public List? Animation { get; set; } } diff --git a/src/DotTiled/Model/Tilesets/TileOffset.cs b/src/DotTiled/Model/Tilesets/TileOffset.cs index 2b2e620..6030f39 100644 --- a/src/DotTiled/Model/Tilesets/TileOffset.cs +++ b/src/DotTiled/Model/Tilesets/TileOffset.cs @@ -1,8 +1,17 @@ namespace DotTiled.Model; +/// +/// Is used to specify an offset in pixels in tilesets, to be applied when drawing a tile from the related tileset. +/// public class TileOffset { - // Attributes + /// + /// The horizontal offset in pixels. + /// public float X { get; set; } = 0f; + + /// + /// The vertical offset in pixels. + /// public float Y { get; set; } = 0f; } diff --git a/src/DotTiled/Model/Tilesets/Tileset.cs b/src/DotTiled/Model/Tilesets/Tileset.cs index 639fe62..147f3d2 100644 --- a/src/DotTiled/Model/Tilesets/Tileset.cs +++ b/src/DotTiled/Model/Tilesets/Tileset.cs @@ -2,60 +2,208 @@ namespace DotTiled.Model; +/// +/// The alignment of tile objects. +/// public enum ObjectAlignment { + /// + /// The alignment is unspecified. Tile objects will use in orthogonal maps, and in isometric maps. + /// Unspecified, + + /// + /// The tile object is aligned to the top left of the tile. + /// TopLeft, + + /// + /// The tile object is aligned to the top of the tile. + /// Top, + + /// + /// The tile object is aligned to the top right of the tile. + /// TopRight, + + /// + /// The tile object is aligned to the left of the tile. + /// Left, + + /// + /// The tile object is aligned to the center of the tile. + /// Center, + + /// + /// The tile object is aligned to the right of the tile. + /// Right, + + /// + /// The tile object is aligned to the bottom left of the tile. + /// BottomLeft, + + /// + /// The tile object is aligned to the bottom of the tile. + /// Bottom, + + /// + /// The tile object is aligned to the bottom right of the tile. + /// BottomRight } +/// +/// The size to use when rendering tiles from a tileset on a tile layer. +/// public enum TileRenderSize { + /// + /// The tile is drawn at the size of the tile in the tileset. + /// Tile, + + /// + /// The tile is drawn at the tile grid size of the map. + /// Grid } +/// +/// Determines how a tile is rendered in a tile set. +/// public enum FillMode { + /// + /// The tile is stretched to fill the tile size, possibly distorting the tile. + /// Stretch, + + /// + /// The tile's aspect ratio is preserved, and it is scaled to fit within the tile size. + /// PreserveAspectFit } +/// +/// A tileset is a collection of tiles that can be used in a tile layer, or by tile objects. +/// public class Tileset { - // Attributes + /// + /// The TMX format version. Is incremented to match minor Tiled releases. + /// public string? Version { get; set; } + + /// + /// The Tiled version used to save the file in case it was loaded from an external tileset file. + /// public string? TiledVersion { get; set; } + + /// + /// The first global tile ID of this tileset (this global ID maps to the first tile in this tileset). + /// public uint? FirstGID { get; set; } + + /// + /// If this tileset is stored in an external TSX (Tile Set XML) file, this attribute refers to that file. + /// public string? Source { get; set; } + + /// + /// The name of this tileset. + /// public string? Name { get; set; } + + /// + /// The class of this tileset. + /// public string Class { get; set; } = ""; + + /// + /// The width of the tiles in this tileset, which should be at least 1 (non-zero) except in the case of image collection tilesets (in which case it stores the maximum tile width). + /// public uint? TileWidth { get; set; } + + /// + /// The height of the tiles in this tileset, which should be at least 1 (non-zero) except in the case of image collection tilesets (in which case it stores the maximum tile height). + /// public uint? TileHeight { get; set; } + + /// + /// The spacing in pixels between the tiles in this tileset (applies to the tileset image). Irrelevant for image collection tilesets. + /// public float? Spacing { get; set; } = 0f; + + /// + /// The margin around the tiles in this tileset (applies to the tileset image). Irrelevant for image collection tilesets. + /// public float? Margin { get; set; } = 0f; + + /// + /// The number of tiles in this tileset. + /// public uint? TileCount { get; set; } + + /// + /// The number of tile columns in the tileset. + /// public uint? Columns { get; set; } + + /// + /// Controls the aligntment for tile objects. + /// 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. + /// public TileRenderSize RenderSize { get; set; } = TileRenderSize.Tile; + + /// + /// The fill mode to use when rendering tiles from this tileset. + /// public FillMode FillMode { get; set; } = FillMode.Stretch; - // At most one of + /// + /// If the tileset is based on a single image, which is cut into tiles based on the given attributes of the tileset, then this is that image. + /// public Image? Image { get; set; } + + /// + /// This is used to specify an offset in pixels, to be applied when drawing a tile from the related tileset. When not present, no offset is applied. + /// public TileOffset? TileOffset { get; set; } + + /// + /// Ths is only used in case of isometric orientation, and determines how tile overlays for terrain and collision information are rendered. + /// public Grid? Grid { get; set; } + + /// + /// Tileset properties. + /// public Dictionary? Properties { get; set; } + // public List? TerrainTypes { get; set; } TODO: Implement Terrain -> Wangset conversion during deserialization + + /// + /// Contains the list of Wang sets defined for this tileset. + /// public List? Wangsets { get; set; } + + /// + /// Used to describe which transformations can be applied to the tiles (e.g. to extend a Wang set by transforming existing tiles). + /// public Transformations? Transformations { get; set; } - // Any number of + /// + /// If this tileset is based on a collection of images, then this list of tiles will contain the individual images that make up the tileset. + /// public List Tiles { get; set; } = []; } diff --git a/src/DotTiled/Model/Tilesets/Transformations.cs b/src/DotTiled/Model/Tilesets/Transformations.cs index 1a84549..b6cf6bf 100644 --- a/src/DotTiled/Model/Tilesets/Transformations.cs +++ b/src/DotTiled/Model/Tilesets/Transformations.cs @@ -1,10 +1,27 @@ namespace DotTiled.Model; +/// +/// Represents which transformations can be applied to a tile in a tileset. +/// public class Transformations { - // Attributes + /// + /// Whether the file in this can set be flipped horizontally. + /// public bool HFlip { get; set; } = false; + + /// + /// Whether the file in this can set be flipped vertically. + /// public bool VFlip { get; set; } = false; + + /// + /// Whether the file in this set can be rotated in 90 degree increments. + /// public bool Rotate { get; set; } = false; + + /// + /// Whether untransformed tiles remain preferred, otherwise transformed tiles are used to produce more vartiations. + /// public bool PreferUntransformed { get; set; } = false; } diff --git a/src/DotTiled/Model/Tilesets/WangColor.cs b/src/DotTiled/Model/Tilesets/WangColor.cs index d3a0328..20678cb 100644 --- a/src/DotTiled/Model/Tilesets/WangColor.cs +++ b/src/DotTiled/Model/Tilesets/WangColor.cs @@ -2,15 +2,38 @@ namespace DotTiled.Model; +/// +/// Represents a Wang color in a Wang set. +/// public class WangColor { - // Attributes + /// + /// The name of this color. + /// public required string Name { get; set; } + + /// + /// The class of the Wang color. + /// public string Class { get; set; } = ""; + + /// + /// The color of the Wang color. + /// public required Color Color { get; set; } + + /// + /// The tile ID of the tile representing this color. + /// public required int Tile { get; set; } + + /// + /// The relative probability that this color is chosen over others in case of multiple options. + /// public float Probability { get; set; } = 0f; - // Elements + /// + /// The Wang color properties. + /// public Dictionary? Properties { get; set; } } diff --git a/src/DotTiled/Model/Tilesets/WangTile.cs b/src/DotTiled/Model/Tilesets/WangTile.cs index d526d71..2347b91 100644 --- a/src/DotTiled/Model/Tilesets/WangTile.cs +++ b/src/DotTiled/Model/Tilesets/WangTile.cs @@ -1,8 +1,17 @@ namespace DotTiled.Model; +/// +/// Represents a Wang tile in a Wang set. +/// public class WangTile { - // Attributes + /// + /// The tile ID associated with this Wang tile. + /// public required uint TileID { get; set; } + + /// + /// The Wang ID of this Wang tile. + /// public required byte[] WangID { get; set; } } diff --git a/src/DotTiled/Model/Tilesets/Wangset.cs b/src/DotTiled/Model/Tilesets/Wangset.cs index 653f43f..1a6f7c3 100644 --- a/src/DotTiled/Model/Tilesets/Wangset.cs +++ b/src/DotTiled/Model/Tilesets/Wangset.cs @@ -2,20 +2,39 @@ namespace DotTiled.Model; +/// +/// Defines a list of colors and any number of Wang tiles using these colors. +/// public class Wangset { - // Attributes + /// + /// The name of the Wang set. + /// public required string Name { get; set; } + + /// + /// The class of the Wang set. + /// public string Class { get; set; } = ""; + + /// + /// The tile ID of the tile representing the Wang set. + /// public required int Tile { get; set; } - // Elements - // At most one of + /// + /// The Wang set properties. + /// public Dictionary? Properties { get; set; } // Up to 254 Wang colors + /// + /// The Wang colors in the Wang set. + /// public List? WangColors { get; set; } = []; - // Any number of + /// + /// The Wang tiles in the Wang set. + /// public List WangTiles { get; set; } = []; } diff --git a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs index af0449b..ba01791 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs @@ -38,7 +38,7 @@ internal static ObjectLayer ReadObjectLayer( _ => throw new JsonException($"Unknown draw order '{s}'.") }, DrawOrder.TopDown); - var objects = element.GetOptionalPropertyCustom>("objects", e => e.GetValueAsList(el => ReadObject(el, externalTemplateResolver, customTypeDefinitions)), []); + var objects = element.GetOptionalPropertyCustom>("objects", e => e.GetValueAsList(el => ReadObject(el, externalTemplateResolver, customTypeDefinitions)), []); return new ObjectLayer { @@ -63,7 +63,7 @@ internal static ObjectLayer ReadObjectLayer( }; } - internal static Model.Layers.Objects.Object ReadObject( + internal static Model.Object ReadObject( JsonElement element, Func externalTemplateResolver, IReadOnlyCollection customTypeDefinitions) diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Template.cs b/src/DotTiled/Serialization/Tmj/Tmj.Template.cs index a9a8766..100aaa2 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Template.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Template.cs @@ -17,7 +17,7 @@ internal static Template ReadTemplate( { var type = element.GetRequiredProperty("type"); var tileset = element.GetOptionalPropertyCustom("tileset", el => ReadTileset(el, externalTilesetResolver, externalTemplateResolver, customTypeDefinitions), null); - var @object = element.GetRequiredPropertyCustom("object", el => ReadObject(el, externalTemplateResolver, customTypeDefinitions)); + var @object = element.GetRequiredPropertyCustom("object", el => ReadObject(el, externalTemplateResolver, customTypeDefinitions)); return new Template { diff --git a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs b/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs index 523b224..7c04edf 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs @@ -40,7 +40,7 @@ internal static ObjectLayer ReadObjectLayer( // Elements Dictionary? properties = null; - List objects = []; + List objects = []; reader.ProcessChildren("objectgroup", (r, elementName) => elementName switch { @@ -72,14 +72,14 @@ internal static ObjectLayer ReadObjectLayer( }; } - internal static Model.Layers.Objects.Object ReadObject( + internal static Model.Object ReadObject( XmlReader reader, Func externalTemplateResolver, IReadOnlyCollection customTypeDefinitions) { // Attributes var template = reader.GetOptionalAttribute("template"); - Model.Layers.Objects.Object? obj = null; + Model.Object? obj = null; if (template is not null) obj = externalTemplateResolver(template).Object; @@ -107,7 +107,7 @@ internal static Model.Layers.Objects.Object ReadObject( var visible = reader.GetOptionalAttributeParseable("visible") ?? visibleDefault; // Elements - Model.Layers.Objects.Object? foundObject = null; + Model.Object? foundObject = null; int propertiesCounter = 0; Dictionary? properties = propertiesDefault; @@ -145,7 +145,7 @@ internal static Model.Layers.Objects.Object ReadObject( return OverrideObject(obj, foundObject); } - internal static Model.Layers.Objects.Object OverrideObject(Model.Layers.Objects.Object? obj, Model.Layers.Objects.Object foundObject) + internal static Model.Object OverrideObject(Model.Object? obj, Model.Object foundObject) { if (obj is null) return foundObject; @@ -316,7 +316,7 @@ internal static Template ReadTemplate( Tileset? tileset = null; // Should contain exactly one of - Model.Layers.Objects.Object? obj = null; + Model.Object? obj = null; reader.ProcessChildren("template", (r, elementName) => elementName switch { From 7fbf0160d6e0504836f2ffff2b23f83d079b18cc Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Tue, 20 Aug 2024 23:47:05 +0200 Subject: [PATCH 03/23] Add XML docs for public serialization --- src/DotTiled/Serialization/IMapReader.cs | 7 +++++++ src/DotTiled/Serialization/ITemplateReader.cs | 7 +++++++ src/DotTiled/Serialization/ITilesetReader.cs | 7 +++++++ src/DotTiled/Serialization/Tmj/TjTemplateReader.cs | 14 ++++++++++++++ src/DotTiled/Serialization/Tmj/TmjMapReader.cs | 14 ++++++++++++++ src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs | 13 +++++++++++++ src/DotTiled/Serialization/Tmx/TmxMapReader.cs | 14 ++++++++++++++ src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs | 13 +++++++++++++ src/DotTiled/Serialization/Tmx/TxTemplateReader.cs | 14 ++++++++++++++ 9 files changed, 103 insertions(+) diff --git a/src/DotTiled/Serialization/IMapReader.cs b/src/DotTiled/Serialization/IMapReader.cs index a1e8b05..d96def5 100644 --- a/src/DotTiled/Serialization/IMapReader.cs +++ b/src/DotTiled/Serialization/IMapReader.cs @@ -3,7 +3,14 @@ namespace DotTiled.Serialization; +/// +/// Interface for reading a map from some source. Used by the different file format parsers to read a map. +/// public interface IMapReader : IDisposable { + /// + /// Reads a map from the source. + /// + /// The parsed map. Map ReadMap(); } diff --git a/src/DotTiled/Serialization/ITemplateReader.cs b/src/DotTiled/Serialization/ITemplateReader.cs index 45832fa..9497e26 100644 --- a/src/DotTiled/Serialization/ITemplateReader.cs +++ b/src/DotTiled/Serialization/ITemplateReader.cs @@ -3,7 +3,14 @@ namespace DotTiled.Serialization; +/// +/// Interface for reading a template from some source. Used by the different file format parsers to read a template. +/// public interface ITemplateReader : IDisposable { + /// + /// Reads a template from the source. + /// + /// The parsed template. Template ReadTemplate(); } diff --git a/src/DotTiled/Serialization/ITilesetReader.cs b/src/DotTiled/Serialization/ITilesetReader.cs index 803ea8e..e798bcf 100644 --- a/src/DotTiled/Serialization/ITilesetReader.cs +++ b/src/DotTiled/Serialization/ITilesetReader.cs @@ -3,7 +3,14 @@ namespace DotTiled.Serialization; +/// +/// Interface for reading a tileset from some source. Used by the different file format parsers to read a tileset. +/// public interface ITilesetReader : IDisposable { + /// + /// Reads a tileset from the source. + /// + /// The parsed tileset. Tileset ReadTileset(); } diff --git a/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs b/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs index a10a1f3..3a66f1b 100644 --- a/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs +++ b/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs @@ -4,6 +4,9 @@ namespace DotTiled.Serialization.Tmj; +/// +/// A template reader for reading Tiled JSON templates. +/// public class TjTemplateReader : ITemplateReader { // External resolvers @@ -15,6 +18,14 @@ public class TjTemplateReader : ITemplateReader private readonly IReadOnlyCollection _customTypeDefinitions; + /// + /// Constructs a new . + /// + /// A string containing a Tiled template in the Tiled JSON format. + /// A function that resolves external tilesets given their source. + /// A function that resolves external templates given their source. + /// A collection of custom type definitions that can be used to resolve custom types when encountering . + /// Thrown when any of the arguments are null. public TjTemplateReader( string jsonString, Func externalTilesetResolver, @@ -27,6 +38,7 @@ public TjTemplateReader( _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); } + /// public Template ReadTemplate() { var jsonDoc = System.Text.Json.JsonDocument.Parse(_jsonString); @@ -34,6 +46,7 @@ public Template ReadTemplate() return Tmj.ReadTemplate(rootElement, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions); } + /// protected virtual void Dispose(bool disposing) { if (!disposedValue) @@ -56,6 +69,7 @@ protected virtual void Dispose(bool disposing) // Dispose(disposing: false); // } + /// public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method diff --git a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs index 23d9754..8e5ddd4 100644 --- a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs +++ b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs @@ -7,6 +7,9 @@ namespace DotTiled.Serialization.Tmj; +/// +/// A map reader for reading Tiled JSON maps. +/// public class TmjMapReader : IMapReader { // External resolvers @@ -18,6 +21,14 @@ public class TmjMapReader : IMapReader private readonly IReadOnlyCollection _customTypeDefinitions; + /// + /// Constructs a new . + /// + /// A string containing a Tiled map in the Tiled JSON format. + /// A function that resolves external tilesets given their source. + /// A function that resolves external templates given their source. + /// A collection of custom type definitions that can be used to resolve custom types when encountering . + /// Thrown when any of the arguments are null. public TmjMapReader( string jsonString, Func externalTilesetResolver, @@ -30,6 +41,7 @@ public TmjMapReader( _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); } + /// public Map ReadMap() { var jsonDoc = JsonDocument.Parse(_jsonString); @@ -37,6 +49,7 @@ public Map ReadMap() return Tmj.ReadMap(rootElement, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions); } + /// protected virtual void Dispose(bool disposing) { if (!disposedValue) @@ -59,6 +72,7 @@ protected virtual void Dispose(bool disposing) // Dispose(disposing: false); // } + /// public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method diff --git a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs index 7ddae3e..84ec60e 100644 --- a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs @@ -4,6 +4,9 @@ namespace DotTiled.Serialization.Tmj; +/// +/// A tileset reader for the Tiled JSON format. +/// public class TsjTilesetReader : ITilesetReader { // External resolvers @@ -14,6 +17,13 @@ public class TsjTilesetReader : ITilesetReader private readonly IReadOnlyCollection _customTypeDefinitions; + /// + /// Constructs a new . + /// + /// A string containing a Tiled tileset in the Tiled JSON format. + /// A function that resolves external templates given their source. + /// A collection of custom type definitions that can be used to resolve custom types when encountering . + /// Thrown when any of the arguments are null. public TsjTilesetReader( string jsonString, Func externalTemplateResolver, @@ -24,6 +34,7 @@ public TsjTilesetReader( _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); } + /// public Tileset ReadTileset() { var jsonDoc = System.Text.Json.JsonDocument.Parse(_jsonString); @@ -35,6 +46,7 @@ public Tileset ReadTileset() _customTypeDefinitions); } + /// protected virtual void Dispose(bool disposing) { if (!disposedValue) @@ -57,6 +69,7 @@ protected virtual void Dispose(bool disposing) // Dispose(disposing: false); // } + /// public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method diff --git a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs index 091f161..be21580 100644 --- a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs +++ b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs @@ -5,6 +5,9 @@ namespace DotTiled.Serialization.Tmx; +/// +/// A map reader for the Tiled XML format. +/// public class TmxMapReader : IMapReader { // External resolvers @@ -16,6 +19,14 @@ public class TmxMapReader : IMapReader private readonly IReadOnlyCollection _customTypeDefinitions; + /// + /// Constructs a new . + /// + /// An XML reader for reading a Tiled map in the Tiled XML format. + /// A function that resolves external tilesets given their source. + /// A function that resolves external templates given their source. + /// A collection of custom type definitions that can be used to resolve custom types when encountering . + /// Thrown when any of the arguments are null. public TmxMapReader( XmlReader reader, Func externalTilesetResolver, @@ -31,11 +42,13 @@ public TmxMapReader( _reader.MoveToContent(); } + /// public Map ReadMap() { return Tmx.ReadMap(_reader, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions); } + /// protected virtual void Dispose(bool disposing) { if (!disposedValue) @@ -59,6 +72,7 @@ protected virtual void Dispose(bool disposing) // Dispose(disposing: false); // } + /// public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method diff --git a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs index 0cc4e2f..374a0d1 100644 --- a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs @@ -5,6 +5,9 @@ namespace DotTiled.Serialization.Tmx; +/// +/// A tileset reader for the Tiled XML format. +/// public class TsxTilesetReader : ITilesetReader { // External resolvers @@ -15,6 +18,13 @@ public class TsxTilesetReader : ITilesetReader private readonly IReadOnlyCollection _customTypeDefinitions; + /// + /// Constructs a new . + /// + /// An XML reader for reading a Tiled tileset in the Tiled XML format. + /// A function that resolves external templates given their source. + /// A collection of custom type definitions that can be used to resolve custom types when encountering . + /// Thrown when any of the arguments are null. public TsxTilesetReader( XmlReader reader, Func externalTemplateResolver, @@ -28,8 +38,10 @@ public TsxTilesetReader( _reader.MoveToContent(); } + /// public Tileset ReadTileset() => Tmx.ReadTileset(_reader, null, _externalTemplateResolver, _customTypeDefinitions); + /// protected virtual void Dispose(bool disposing) { if (!disposedValue) @@ -52,6 +64,7 @@ protected virtual void Dispose(bool disposing) // Dispose(disposing: false); // } + /// public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method diff --git a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs index e640dd8..fe93244 100644 --- a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs +++ b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs @@ -5,6 +5,9 @@ namespace DotTiled.Serialization.Tmx; +/// +/// A template reader for the Tiled XML format. +/// public class TxTemplateReader : ITemplateReader { // Resolvers @@ -16,6 +19,14 @@ public class TxTemplateReader : ITemplateReader private readonly IReadOnlyCollection _customTypeDefinitions; + /// + /// Constructs a new . + /// + /// An XML reader for reading a Tiled template in the Tiled XML format. + /// A function that resolves external tilesets given their source. + /// A function that resolves external templates given their source. + /// A collection of custom type definitions that can be used to resolve custom types when encountering . + /// Thrown when any of the arguments are null. public TxTemplateReader( XmlReader reader, Func externalTilesetResolver, @@ -31,8 +42,10 @@ public TxTemplateReader( _reader.MoveToContent(); } + /// public Template ReadTemplate() => Tmx.ReadTemplate(_reader, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions); + /// protected virtual void Dispose(bool disposing) { if (!disposedValue) @@ -55,6 +68,7 @@ protected virtual void Dispose(bool disposing) // Dispose(disposing: false); // } + /// public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method From 9960cccd5b2330c14a4d6652b6801f2a5fa7bd03 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Wed, 21 Aug 2024 23:15:38 +0200 Subject: [PATCH 04/23] Add build step to make test --- Makefile | 1 + src/DotTiled.Benchmark/Program.cs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a65d55f..5e6402f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ test: + dotnet build src/DotTiled.sln dotnet test src/DotTiled.sln docs-serve: diff --git a/src/DotTiled.Benchmark/Program.cs b/src/DotTiled.Benchmark/Program.cs index 55c04cf..e04c6b1 100644 --- a/src/DotTiled.Benchmark/Program.cs +++ b/src/DotTiled.Benchmark/Program.cs @@ -39,7 +39,7 @@ public MapLoading() [BenchmarkCategory("MapFromInMemoryTmxString")] [Benchmark(Baseline = true, Description = "DotTiled")] - public DotTiled.Model LoadWithDotTiledFromInMemoryTmxString() + public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmxString() { using var stringReader = new StringReader(_tmxContents); using var xmlReader = XmlReader.Create(stringReader); @@ -49,7 +49,7 @@ public DotTiled.Model LoadWithDotTiledFromInMemoryTmxString() [BenchmarkCategory("MapFromInMemoryTmjString")] [Benchmark(Baseline = true, Description = "DotTiled")] - public DotTiled.Model LoadWithDotTiledFromInMemoryTmjString() + public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmjString() { using var mapReader = new DotTiled.Serialization.Tmj.TmjMapReader(_tmjContents, _ => throw new Exception(), _ => throw new Exception(), []); return mapReader.ReadMap(); From 55b7b81dbae02ee951547b024311bb78ebbf383a Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Wed, 21 Aug 2024 23:37:09 +0200 Subject: [PATCH 05/23] Add lint step to pull request workflow --- .editorconfig | 224 +++++++++++++++++- .../workflows/{tests.yml => pull-request.yml} | 7 +- Makefile | 39 +-- 3 files changed, 250 insertions(+), 20 deletions(-) rename .github/workflows/{tests.yml => pull-request.yml} (68%) diff --git a/.editorconfig b/.editorconfig index 0c2a84a..d785411 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,11 +1,233 @@ root = true [*.cs] + +#### Core EditorConfig Options #### charset = utf-8 -end_of_line = lf + +# Indentation and spacing indent_size = 2 indent_style = space + +# New line preferences +end_of_line = lf insert_final_newline = true +trim_trailing_whitespace = true + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_property = false + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true +dotnet_style_prefer_collection_expression = when_types_loosely_match +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:silent + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = true +dotnet_style_allow_statement_immediately_after_block_experimental = true + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = false + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true +csharp_style_expression_bodied_constructors = false +csharp_style_expression_bodied_indexers = true +csharp_style_expression_bodied_lambdas = true +csharp_style_expression_bodied_local_functions = false +csharp_style_expression_bodied_methods = false +csharp_style_expression_bodied_operators = false +csharp_style_expression_bodied_properties = true + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_extended_property_pattern = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_pattern_matching = true +csharp_style_prefer_switch_expression = true + +# Null-checking preferences +csharp_style_conditional_delegate_call = true + +# Modifier preferences +csharp_prefer_static_local_function = true +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async +csharp_style_prefer_readonly_struct = true +csharp_style_prefer_readonly_struct_member = true + +# Code-block preferences +csharp_prefer_braces = true +csharp_prefer_simple_using_statement = true +csharp_style_namespace_declarations = block_scoped +csharp_style_prefer_method_group_conversion = true +csharp_style_prefer_primary_constructors = true +csharp_style_prefer_top_level_statements = true + +# Expression-level preferences +csharp_prefer_simple_default_expression = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_implicit_object_creation_when_type_is_apparent = true +csharp_style_inlined_variable_declaration = true +csharp_style_prefer_index_operator = true +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_range_operator = true +csharp_style_prefer_tuple_swap = true +csharp_style_prefer_utf8_string_literals = true +csharp_style_throw_expression = true +csharp_style_unused_value_assignment_preference = discard_variable +csharp_style_unused_value_expression_statement_preference = discard_variable + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true +csharp_style_allow_embedded_statements_on_same_line_experimental = true + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case [.github/**/*.yml] charset = utf-8 diff --git a/.github/workflows/tests.yml b/.github/workflows/pull-request.yml similarity index 68% rename from .github/workflows/tests.yml rename to .github/workflows/pull-request.yml index 3e0d43b..f24db4a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/pull-request.yml @@ -5,7 +5,7 @@ on: - dev jobs: - tests: + build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -19,4 +19,7 @@ jobs: run: dotnet build --no-restore src/DotTiled.sln - name: Test run: dotnet test --no-build --verbosity normal src/DotTiled.sln - \ No newline at end of file + - name: Lint + run: | + dotnet format style --verify-no-changes --verbosity diagnostic src/DotTiled.sln + dotnet format analyzers --verify-no-changes --verbosity diagnostic src/DotTiled.sln diff --git a/Makefile b/Makefile index 5e6402f..3790c68 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,23 @@ -test: - dotnet build src/DotTiled.sln - dotnet test src/DotTiled.sln - -docs-serve: - docfx docs/docfx.json --serve - -docs-build: - cp README.md docs/index.md - docfx docs/docfx.json - -BENCHMARK_SOURCES = DotTiled.Benchmark/Program.cs DotTiled.Benchmark/DotTiled.Benchmark.csproj -BENCHMARK_OUTPUTDIR = DotTiled.Benchmark/BenchmarkDotNet.Artifacts -.PHONY: benchmark -benchmark: $(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md - -$(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md: $(BENCHMARK_SOURCES) +test: + dotnet build src/DotTiled.sln + dotnet test src/DotTiled.sln + +docs-serve: + docfx docs/docfx.json --serve + +docs-build: + cp README.md docs/index.md + docfx docs/docfx.json + +lint: + dotnet build src/DotTiled.sln + dotnet format style --verify-no-changes --verbosity diagnostic src/DotTiled.sln + dotnet format analyzers --verify-no-changes --verbosity diagnostic src/DotTiled.sln + +BENCHMARK_SOURCES = DotTiled.Benchmark/Program.cs DotTiled.Benchmark/DotTiled.Benchmark.csproj +BENCHMARK_OUTPUTDIR = DotTiled.Benchmark/BenchmarkDotNet.Artifacts +.PHONY: benchmark +benchmark: $(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md + +$(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md: $(BENCHMARK_SOURCES) dotnet run --project DotTiled.Benchmark/DotTiled.Benchmark.csproj -c Release -- $(BENCHMARK_OUTPUTDIR) \ No newline at end of file From 7d6ee330a5f1f6282078cbf07f393b5b0b59937e Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Wed, 21 Aug 2024 23:48:11 +0200 Subject: [PATCH 06/23] New editorconfig properties --- .editorconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.editorconfig b/.editorconfig index d785411..04f7e81 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,10 +15,8 @@ insert_final_newline = true trim_trailing_whitespace = true #### .NET Coding Conventions #### - -# Organize usings dotnet_separate_import_directive_groups = false -dotnet_sort_system_directives_first = false +dotnet_sort_system_directives_first = true file_header_template = unset # this. and Me. preferences @@ -229,6 +227,8 @@ dotnet_naming_style.begins_with_i.required_suffix = dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case +dotnet_diagnostic.IDE0005.severity = error + [.github/**/*.yml] charset = utf-8 end_of_line = lf From bb8c3a133c8681dc0dad7a359d8f06d4e840ee7b Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Thu, 22 Aug 2024 00:15:13 +0200 Subject: [PATCH 07/23] Started lint work --- .editorconfig | 23 +++++++++------ src/DotTiled.Benchmark/Program.cs | 28 ++++++++----------- src/DotTiled.Tests/Assert/AssertTileset.cs | 1 - src/DotTiled.Tests/Serialization/TestData.cs | 1 - .../TestData/Map/default-map/default-map.cs | 1 - .../map-external-tileset-multi.cs | 3 -- .../map-external-tileset-wangset.cs | 2 -- .../map-with-common-props.cs | 2 -- .../map-with-custom-type-props.cs | 3 -- .../map-with-embedded-tileset.cs | 2 -- .../map-with-external-tileset.cs | 2 -- .../map-with-flippingflags.cs | 2 -- .../map-with-many-layers.cs | 4 --- .../Serialization/Tmj/TmjMapReaderTests.cs | 2 -- .../Serialization/Tmx/TmxMapReaderTests.cs | 3 -- src/DotTiled/Model/Color.cs | 5 ++-- src/DotTiled/Serialization/Helpers.cs | 2 -- .../Tmj/ExtensionsJsonElement.cs | 7 ++--- src/DotTiled/Serialization/Tmj/Tmj.Data.cs | 7 ++--- src/DotTiled/Serialization/Tmj/Tmj.Group.cs | 1 - .../Serialization/Tmj/Tmj.ImageLayer.cs | 3 -- src/DotTiled/Serialization/Tmj/Tmj.Layer.cs | 2 -- src/DotTiled/Serialization/Tmj/Tmj.Map.cs | 2 -- .../Serialization/Tmj/Tmj.ObjectLayer.cs | 16 +++++------ .../Serialization/Tmj/Tmj.Properties.cs | 7 ++--- .../Serialization/Tmj/Tmj.Template.cs | 2 -- .../Serialization/Tmj/Tmj.TileLayer.cs | 2 -- src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs | 3 -- .../Serialization/Tmj/TmjMapReader.cs | 6 ++-- .../Serialization/Tmj/TsjTilesetReader.cs | 2 +- .../Serialization/Tmx/ExtensionsXmlReader.cs | 10 +++---- src/DotTiled/Serialization/Tmx/Tmx.Data.cs | 6 ++-- src/DotTiled/Serialization/Tmx/Tmx.Map.cs | 8 +++--- .../Serialization/Tmx/Tmx.ObjectLayer.cs | 12 ++++---- .../Serialization/Tmx/Tmx.Properties.cs | 6 ++-- src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs | 19 ++++++------- .../Serialization/Tmx/TmxMapReader.cs | 9 ++---- .../Serialization/Tmx/TsxTilesetReader.cs | 5 ++-- .../Serialization/Tmx/TxTemplateReader.cs | 5 ++-- 39 files changed, 83 insertions(+), 143 deletions(-) diff --git a/.editorconfig b/.editorconfig index 04f7e81..8c68b86 100644 --- a/.editorconfig +++ b/.editorconfig @@ -40,17 +40,17 @@ dotnet_style_require_accessibility_modifiers = for_non_interface_members # Expression-level preferences dotnet_style_coalesce_expression = true -dotnet_style_collection_initializer = true +dotnet_style_collection_initializer = false dotnet_style_explicit_tuple_names = true dotnet_style_namespace_match_folder = true dotnet_style_null_propagation = true dotnet_style_object_initializer = true dotnet_style_operator_placement_when_wrapping = beginning_of_line dotnet_style_prefer_auto_properties = true -dotnet_style_prefer_collection_expression = when_types_loosely_match +dotnet_style_prefer_collection_expression = false dotnet_style_prefer_compound_assignment = true -dotnet_style_prefer_conditional_expression_over_assignment = true -dotnet_style_prefer_conditional_expression_over_return = true +dotnet_style_prefer_conditional_expression_over_assignment = false +dotnet_style_prefer_conditional_expression_over_return = false dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed dotnet_style_prefer_inferred_anonymous_type_member_names = true dotnet_style_prefer_inferred_tuple_names = true @@ -84,7 +84,7 @@ csharp_style_expression_bodied_constructors = false csharp_style_expression_bodied_indexers = true csharp_style_expression_bodied_lambdas = true csharp_style_expression_bodied_local_functions = false -csharp_style_expression_bodied_methods = false +csharp_style_expression_bodied_methods = when_on_single_line csharp_style_expression_bodied_operators = false csharp_style_expression_bodied_properties = true @@ -106,11 +106,11 @@ csharp_style_prefer_readonly_struct = true csharp_style_prefer_readonly_struct_member = true # Code-block preferences -csharp_prefer_braces = true +csharp_prefer_braces = when_multiline csharp_prefer_simple_using_statement = true csharp_style_namespace_declarations = block_scoped csharp_style_prefer_method_group_conversion = true -csharp_style_prefer_primary_constructors = true +csharp_style_prefer_primary_constructors = false csharp_style_prefer_top_level_statements = true # Expression-level preferences @@ -145,7 +145,7 @@ csharp_new_line_before_catch = true csharp_new_line_before_else = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_anonymous_types = true -csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_object_initializers = false csharp_new_line_before_open_brace = all csharp_new_line_between_query_expression_clauses = true @@ -227,7 +227,14 @@ dotnet_naming_style.begins_with_i.required_suffix = dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case +# Diagnostics +dotnet_analyzer_diagnostic.severity = warning + +dotnet_diagnostic.IDE0001.severity = none +dotnet_diagnostic.IDE0004.severity = silent dotnet_diagnostic.IDE0005.severity = error +dotnet_diagnostic.IDE0008.severity = silent +dotnet_diagnostic.IDE0160.severity = none [.github/**/*.yml] charset = utf-8 diff --git a/src/DotTiled.Benchmark/Program.cs b/src/DotTiled.Benchmark/Program.cs index e04c6b1..bf67fd0 100644 --- a/src/DotTiled.Benchmark/Program.cs +++ b/src/DotTiled.Benchmark/Program.cs @@ -1,17 +1,13 @@ -using System; -using System.Collections.Immutable; using System.Runtime.CompilerServices; -using System.Security.Cryptography; using System.Text; using System.Xml; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Columns; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Order; -using BenchmarkDotNet.Reports; using BenchmarkDotNet.Running; -namespace MyBenchmarks +namespace DotTiled.Benchmark { [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] [CategoriesColumn] @@ -19,11 +15,11 @@ namespace MyBenchmarks [HideColumns(["StdDev", "Error", "RatioSD"])] public class MapLoading { - private string _tmxPath = @"DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.tmx"; - private string _tmxContents = ""; + private readonly string _tmxPath = @"DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.tmx"; + private readonly string _tmxContents = ""; - private string _tmjPath = @"DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.tmj"; - private string _tmjContents = ""; + private readonly string _tmjPath = @"DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.tmj"; + private readonly string _tmjContents = ""; public MapLoading() { @@ -31,11 +27,11 @@ public MapLoading() var tmxPath = Path.Combine(basePath, $"../{_tmxPath}"); var tmjPath = Path.Combine(basePath, $"../{_tmjPath}"); - _tmxContents = System.IO.File.ReadAllText(tmxPath); - _tmjContents = System.IO.File.ReadAllText(tmjPath); + _tmxContents = File.ReadAllText(tmxPath); + _tmjContents = File.ReadAllText(tmjPath); } - static string WhereAmI([CallerFilePath] string callerFilePath = "") => callerFilePath; + private static string WhereAmI([CallerFilePath] string callerFilePath = "") => callerFilePath; [BenchmarkCategory("MapFromInMemoryTmxString")] [Benchmark(Baseline = true, Description = "DotTiled")] @@ -43,7 +39,7 @@ public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmxString() { using var stringReader = new StringReader(_tmxContents); using var xmlReader = XmlReader.Create(stringReader); - using var mapReader = new DotTiled.Serialization.Tmx.TmxMapReader(xmlReader, _ => throw new Exception(), _ => throw new Exception(), []); + using var mapReader = new DotTiled.Serialization.Tmx.TmxMapReader(xmlReader, _ => throw new NotSupportedException(), _ => throw new NotSupportedException(), []); return mapReader.ReadMap(); } @@ -51,7 +47,7 @@ public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmxString() [Benchmark(Baseline = true, Description = "DotTiled")] public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmjString() { - using var mapReader = new DotTiled.Serialization.Tmj.TmjMapReader(_tmjContents, _ => throw new Exception(), _ => throw new Exception(), []); + using var mapReader = new DotTiled.Serialization.Tmj.TmjMapReader(_tmjContents, _ => throw new NotSupportedException(), _ => throw new NotSupportedException(), []); return mapReader.ReadMap(); } @@ -84,11 +80,11 @@ public class Program { public static void Main(string[] args) { - var config = BenchmarkDotNet.Configs.DefaultConfig.Instance + var config = DefaultConfig.Instance .WithArtifactsPath(args[0]) .WithOptions(ConfigOptions.DisableOptimizationsValidator) .AddDiagnoser(BenchmarkDotNet.Diagnosers.MemoryDiagnoser.Default); - var summary = BenchmarkRunner.Run(config); + _ = BenchmarkRunner.Run(config); } } } diff --git a/src/DotTiled.Tests/Assert/AssertTileset.cs b/src/DotTiled.Tests/Assert/AssertTileset.cs index 3e4ab28..134cc30 100644 --- a/src/DotTiled.Tests/Assert/AssertTileset.cs +++ b/src/DotTiled.Tests/Assert/AssertTileset.cs @@ -1,5 +1,4 @@ using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData.cs b/src/DotTiled.Tests/Serialization/TestData.cs index 30c4b9f..c36cab5 100644 --- a/src/DotTiled.Tests/Serialization/TestData.cs +++ b/src/DotTiled.Tests/Serialization/TestData.cs @@ -1,6 +1,5 @@ using System.Xml; using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs b/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs index 4eef6de..da726bf 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs @@ -1,5 +1,4 @@ using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Tests; 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 04c425a..6dac137 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 @@ -1,8 +1,5 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs index a894a53..2e4bd61 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs @@ -1,7 +1,5 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs index 14f95ac..ba5cf4f 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs @@ -1,7 +1,5 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs index e7d135c..758c5c3 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs @@ -1,8 +1,5 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs index e9c4e73..863dc75 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs @@ -1,7 +1,5 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs index 055a0c9..3682b73 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs @@ -1,7 +1,5 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs index 96995d7..02a9fc5 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs @@ -1,7 +1,5 @@ using System.Globalization; using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Tests; 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 320fa48..6e4ae55 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 @@ -1,9 +1,5 @@ using System.Numerics; using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs b/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs index a856f68..bdd19e8 100644 --- a/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs @@ -1,6 +1,4 @@ using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; using DotTiled.Serialization.Tmj; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs b/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs index 6a26b62..ee74718 100644 --- a/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs @@ -1,6 +1,3 @@ -using System.Xml; -using DotTiled.Model; -using DotTiled.Model; using DotTiled.Model; using DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Model/Color.cs b/src/DotTiled/Model/Color.cs index 24cf8e5..7de0ab0 100644 --- a/src/DotTiled/Model/Color.cs +++ b/src/DotTiled/Model/Color.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Threading; namespace DotTiled.Model; @@ -40,7 +39,7 @@ public class Color : IParsable, IEquatable /// Thrown in case the provided string is not in a valid format. public static Color Parse(string s, IFormatProvider? provider) { - TryParse(s, provider, out var result); + _ = TryParse(s, provider, out var result); return result ?? throw new FormatException($"Invalid format for TiledColor: {s}"); } @@ -61,7 +60,7 @@ public static bool TryParse( return TryParse($"#{s}", provider, out result); // Format: #RRGGBB or #AARRGGBB - if (s is null || s.Length != 7 && s.Length != 9 || s[0] != '#') + if (s is null || (s.Length != 7 && s.Length != 9) || s[0] != '#') { result = default; return false; diff --git a/src/DotTiled/Serialization/Helpers.cs b/src/DotTiled/Serialization/Helpers.cs index fe401ba..c6cdefe 100644 --- a/src/DotTiled/Serialization/Helpers.cs +++ b/src/DotTiled/Serialization/Helpers.cs @@ -4,8 +4,6 @@ using System.IO.Compression; using System.Linq; using DotTiled.Model; -using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Serialization; diff --git a/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs b/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs index 0e76d84..7717df4 100644 --- a/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs +++ b/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs @@ -9,10 +9,9 @@ internal static class ExtensionsJsonElement { internal static T GetRequiredProperty(this JsonElement element, string propertyName) { - if (!element.TryGetProperty(propertyName, out var property)) - throw new JsonException($"Missing required property '{propertyName}'."); - - return property.GetValueAs(); + return !element.TryGetProperty(propertyName, out var property) + ? throw new JsonException($"Missing required property '{propertyName}'.") + : property.GetValueAs(); } internal static T GetOptionalProperty(this JsonElement element, string propertyName, T defaultValue) diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Data.cs b/src/DotTiled/Serialization/Tmj/Tmj.Data.cs index 2edb93f..c021a6c 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Data.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Data.cs @@ -1,9 +1,5 @@ using System; -using System.Collections.Generic; -using System.Globalization; using System.IO; -using System.IO.Compression; -using System.Linq; using System.Text.Json; using DotTiled.Model; @@ -69,7 +65,8 @@ internal static Data ReadDataWithoutChunks(JsonElement element, DataCompression? { DataCompression.GZip => Helpers.DecompressGZip(stream), DataCompression.ZLib => Helpers.DecompressZLib(stream), - _ => throw new JsonException($"Unsupported compression '{compression}'.") + DataCompression.ZStd => throw new NotSupportedException("ZStd compression is not supported."), + _ => throw new InvalidOperationException($"Unsupported compression '{compression}'.") }; { diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Group.cs b/src/DotTiled/Serialization/Tmj/Tmj.Group.cs index 796458b..0885167 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Group.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Group.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Numerics; using System.Text.Json; using DotTiled.Model; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs index 70d9ce4..794f2b5 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs @@ -1,10 +1,7 @@ -using System; using System.Collections.Generic; using System.Globalization; -using System.Numerics; using System.Text.Json; using DotTiled.Model; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs b/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs index fb02fe5..b9f8de0 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; -using System.Numerics; using System.Text.Json; using DotTiled.Model; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs b/src/DotTiled/Serialization/Tmj/Tmj.Map.cs index 642d8f4..47dde3f 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Map.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; -using System.Linq; using System.Text.Json; using DotTiled.Model; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs index ba01791..6775389 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs @@ -112,8 +112,8 @@ internal static Model.Object ReadObject( var id = element.GetOptionalProperty("id", idDefault); var name = element.GetOptionalProperty("name", nameDefault); var point = element.GetOptionalProperty("point", pointDefault); - var polygon = element.GetOptionalPropertyCustom?>("polygon", e => ReadPoints(e), polygonDefault); - var polyline = element.GetOptionalPropertyCustom?>("polyline", e => ReadPoints(e), polylineDefault); + 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 rotation = element.GetOptionalProperty("rotation", rotationDefault); var text = element.GetOptionalPropertyCustom("text", ReadText, null); @@ -249,12 +249,12 @@ internal static Model.Object ReadObject( } internal static List ReadPoints(JsonElement element) => - element.GetValueAsList(e => - { - var x = e.GetRequiredProperty("x"); - var y = e.GetRequiredProperty("y"); - return new Vector2(x, y); - }); + element.GetValueAsList(e => + { + var x = e.GetRequiredProperty("x"); + var y = e.GetRequiredProperty("y"); + return new Vector2(x, y); + }); internal static TextObject ReadText(JsonElement element) { diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs b/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs index 28aad66..0c35bbe 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Globalization; -using System.IO; using System.Linq; using System.Text.Json; using DotTiled.Model; @@ -102,8 +101,6 @@ internal static Dictionary ReadCustomClassProperties( return resultingProps; } - internal static Dictionary CreateInstanceOfCustomClass(CustomClassDefinition customClassDefinition) - { - return customClassDefinition.Members.ToDictionary(m => m.Name, m => m.Clone()); - } + internal static Dictionary CreateInstanceOfCustomClass(CustomClassDefinition customClassDefinition) => + customClassDefinition.Members.ToDictionary(m => m.Name, m => m.Clone()); } diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Template.cs b/src/DotTiled/Serialization/Tmj/Tmj.Template.cs index 100aaa2..3746b76 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Template.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Template.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; -using System.Numerics; using System.Text.Json; using DotTiled.Model; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs index 3711eb2..353f7fd 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs @@ -1,7 +1,5 @@ -using System; using System.Collections.Generic; using System.Globalization; -using System.Numerics; using System.Text.Json; using DotTiled.Model; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs b/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs index 0d6dfc7..e0e2bd2 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; -using System.IO.Compression; -using System.Linq; using System.Text.Json; using DotTiled.Model; diff --git a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs index 8e5ddd4..c26311b 100644 --- a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs +++ b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Text; using System.Text.Json; using DotTiled.Model; @@ -16,7 +14,7 @@ public class TmjMapReader : IMapReader private readonly Func _externalTilesetResolver; private readonly Func _externalTemplateResolver; - private string _jsonString; + private readonly string _jsonString; private bool disposedValue; private readonly IReadOnlyCollection _customTypeDefinitions; @@ -77,6 +75,6 @@ public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); - System.GC.SuppressFinalize(this); + GC.SuppressFinalize(this); } } diff --git a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs index 84ec60e..aca5556 100644 --- a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs @@ -74,6 +74,6 @@ public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); - System.GC.SuppressFinalize(this); + GC.SuppressFinalize(this); } } diff --git a/src/DotTiled/Serialization/Tmx/ExtensionsXmlReader.cs b/src/DotTiled/Serialization/Tmx/ExtensionsXmlReader.cs index ca5f836..9a8f1d9 100644 --- a/src/DotTiled/Serialization/Tmx/ExtensionsXmlReader.cs +++ b/src/DotTiled/Serialization/Tmx/ExtensionsXmlReader.cs @@ -31,10 +31,8 @@ internal static T GetRequiredAttributeEnum(this XmlReader reader, string attr return enumParser(value); } - internal static string? GetOptionalAttribute(this XmlReader reader, string attribute, string? defaultValue = default) - { - return reader.GetAttribute(attribute) ?? defaultValue; - } + internal static string? GetOptionalAttribute(this XmlReader reader, string attribute, string? defaultValue = default) => + reader.GetAttribute(attribute) ?? defaultValue; internal static T? GetOptionalAttributeParseable(this XmlReader reader, string attribute) where T : struct, IParsable { @@ -84,7 +82,7 @@ internal static List ReadList(this XmlReader reader, string wrapper, strin if (reader.NodeType == XmlNodeType.EndElement) continue; // At end of list, no need to read again - reader.Read(); + _ = reader.Read(); } reader.ReadEndElement(); @@ -135,6 +133,6 @@ internal static List ProcessChildren(this XmlReader reader, string wrapper internal static void SkipXmlDeclaration(this XmlReader reader) { if (reader.NodeType == XmlNodeType.XmlDeclaration) - reader.Read(); + _ = reader.Read(); } } diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Data.cs b/src/DotTiled/Serialization/Tmx/Tmx.Data.cs index 77f7d6a..e1b6111 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Data.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Data.cs @@ -62,10 +62,8 @@ internal static (uint[] GlobalTileIDs, FlippingFlags[] FlippingFlags) ReadAndCle return (clearedGlobalTileIDs, flippingFlags); } - internal static uint[] ReadTileChildrenInWrapper(string wrapper, XmlReader reader) - { - return reader.ReadList(wrapper, "tile", (r) => r.GetOptionalAttributeParseable("gid") ?? 0).ToArray(); - } + internal static uint[] ReadTileChildrenInWrapper(string wrapper, XmlReader reader) => + reader.ReadList(wrapper, "tile", (r) => r.GetOptionalAttributeParseable("gid") ?? 0).ToArray(); internal static uint[] ReadRawData(XmlReader reader, DataEncoding encoding, DataCompression? compression) { diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs b/src/DotTiled/Serialization/Tmx/Tmx.Map.cs index e7a5e35..1987bb1 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Map.cs @@ -25,7 +25,7 @@ internal static Map ReadMap( "isometric" => MapOrientation.Isometric, "staggered" => MapOrientation.Staggered, "hexagonal" => MapOrientation.Hexagonal, - _ => throw new Exception($"Unknown orientation '{s}'") + _ => throw new InvalidOperationException($"Unknown orientation '{s}'") }); var renderOrder = reader.GetOptionalAttributeEnum("renderorder", s => s switch { @@ -33,7 +33,7 @@ internal static Map ReadMap( "right-up" => RenderOrder.RightUp, "left-down" => RenderOrder.LeftDown, "left-up" => RenderOrder.LeftUp, - _ => throw new Exception($"Unknown render order '{s}'") + _ => throw new InvalidOperationException($"Unknown render order '{s}'") }) ?? RenderOrder.RightDown; var compressionLevel = reader.GetOptionalAttributeParseable("compressionlevel") ?? -1; var width = reader.GetRequiredAttributeParseable("width"); @@ -45,13 +45,13 @@ internal static Map ReadMap( { "x" => StaggerAxis.X, "y" => StaggerAxis.Y, - _ => throw new Exception($"Unknown stagger axis '{s}'") + _ => throw new InvalidOperationException($"Unknown stagger axis '{s}'") }); var staggerIndex = reader.GetOptionalAttributeEnum("staggerindex", s => s switch { "odd" => StaggerIndex.Odd, "even" => StaggerIndex.Even, - _ => throw new Exception($"Unknown stagger index '{s}'") + _ => throw new InvalidOperationException($"Unknown stagger index '{s}'") }); var parallaxOriginX = reader.GetOptionalAttributeParseable("parallaxoriginx") ?? 0.0f; var parallaxOriginY = reader.GetOptionalAttributeParseable("parallaxoriginy") ?? 0.0f; diff --git a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs b/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs index 7c04edf..7a375d9 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs @@ -35,7 +35,7 @@ internal static ObjectLayer ReadObjectLayer( { "topdown" => DrawOrder.TopDown, "index" => DrawOrder.Index, - _ => throw new Exception($"Unknown draw order '{s}'") + _ => throw new InvalidOperationException($"Unknown draw order '{s}'") }) ?? DrawOrder.TopDown; // Elements @@ -119,7 +119,7 @@ internal static Model.Object ReadObject( "polygon" => () => Helpers.SetAtMostOnce(ref foundObject, ReadPolygonObject(r), "Object marker"), "polyline" => () => Helpers.SetAtMostOnce(ref foundObject, ReadPolylineObject(r), "Object marker"), "text" => () => Helpers.SetAtMostOnce(ref foundObject, ReadTextObject(r), "Object marker"), - _ => throw new Exception($"Unknown object marker '{elementName}'") + _ => throw new InvalidOperationException($"Unknown object marker '{elementName}'") }); if (foundObject is null) @@ -175,7 +175,7 @@ internal static EllipseObject ReadEllipseObject(XmlReader reader) return new EllipseObject { }; } - internal static EllipseObject OverrideObject(EllipseObject obj, EllipseObject foundObject) => obj; + internal static EllipseObject OverrideObject(EllipseObject obj, EllipseObject _) => obj; internal static PointObject ReadPointObject(XmlReader reader) { @@ -183,7 +183,7 @@ internal static PointObject ReadPointObject(XmlReader reader) return new PointObject { }; } - internal static PointObject OverrideObject(PointObject obj, PointObject foundObject) => obj; + internal static PointObject OverrideObject(PointObject obj, PointObject _) => obj; internal static PolygonObject ReadPolygonObject(XmlReader reader) { @@ -251,14 +251,14 @@ internal static TextObject ReadTextObject(XmlReader reader) "center" => TextHorizontalAlignment.Center, "right" => TextHorizontalAlignment.Right, "justify" => TextHorizontalAlignment.Justify, - _ => throw new Exception($"Unknown horizontal alignment '{s}'") + _ => throw new InvalidOperationException($"Unknown horizontal alignment '{s}'") }) ?? TextHorizontalAlignment.Left; var vAlign = reader.GetOptionalAttributeEnum("valign", s => s switch { "top" => TextVerticalAlignment.Top, "center" => TextVerticalAlignment.Center, "bottom" => TextVerticalAlignment.Bottom, - _ => throw new Exception($"Unknown vertical alignment '{s}'") + _ => throw new InvalidOperationException($"Unknown vertical alignment '{s}'") }) ?? TextVerticalAlignment.Top; // Elements diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs b/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs index 3d5b6c4..9a748d6 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs @@ -66,8 +66,6 @@ internal static ClassProperty ReadClassProperty( throw new XmlException($"Unkonwn custom class definition: {propertyType}"); } - internal static Dictionary CreateInstanceOfCustomClass(CustomClassDefinition customClassDefinition) - { - return customClassDefinition.Members.ToDictionary(m => m.Name, m => m.Clone()); - } + internal static Dictionary CreateInstanceOfCustomClass(CustomClassDefinition customClassDefinition) => + customClassDefinition.Members.ToDictionary(m => m.Name, m => m.Clone()); } diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs b/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs index 6e43455..198f32d 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Xml; @@ -40,19 +41,19 @@ internal static Tileset ReadTileset( "bottomleft" => ObjectAlignment.BottomLeft, "bottom" => ObjectAlignment.Bottom, "bottomright" => ObjectAlignment.BottomRight, - _ => throw new Exception($"Unknown object alignment '{s}'") + _ => throw new InvalidOperationException($"Unknown object alignment '{s}'") }) ?? ObjectAlignment.Unspecified; var renderSize = reader.GetOptionalAttributeEnum("rendersize", s => s switch { "tile" => TileRenderSize.Tile, "grid" => TileRenderSize.Grid, - _ => throw new Exception($"Unknown render size '{s}'") + _ => throw new InvalidOperationException($"Unknown render size '{s}'") }) ?? TileRenderSize.Tile; var fillMode = reader.GetOptionalAttributeEnum("fillmode", s => s switch { "stretch" => FillMode.Stretch, "preserve-aspect-fit" => FillMode.PreserveAspectFit, - _ => throw new Exception($"Unknown fill mode '{s}'") + _ => throw new InvalidOperationException($"Unknown fill mode '{s}'") }) ?? FillMode.Stretch; // Elements @@ -124,7 +125,7 @@ internal static Image ReadImage(XmlReader reader) "jpg" => ImageFormat.Jpg, "bmp" => ImageFormat.Bmp, "gif" => ImageFormat.Gif, - _ => throw new Exception($"Unknown image format '{s}'") + _ => throw new InvalidOperationException($"Unknown image format '{s}'") }); var source = reader.GetOptionalAttribute("source"); var transparentColor = reader.GetOptionalAttributeClass("trans"); @@ -182,7 +183,7 @@ internal static Grid ReadGrid(XmlReader reader) { "orthogonal" => GridOrientation.Orthogonal, "isometric" => GridOrientation.Isometric, - _ => throw new Exception($"Unknown orientation '{s}'") + _ => throw new InvalidOperationException($"Unknown orientation '{s}'") }) ?? GridOrientation.Orthogonal; var width = reader.GetRequiredAttributeParseable("width"); var height = reader.GetRequiredAttributeParseable("height"); @@ -255,10 +256,8 @@ internal static Tile ReadTile( internal static List ReadWangsets( XmlReader reader, - IReadOnlyCollection customTypeDefinitions) - { - return reader.ReadList("wangsets", "wangset", r => ReadWangset(r, customTypeDefinitions)); - } + IReadOnlyCollection customTypeDefinitions) => + reader.ReadList("wangsets", "wangset", r => ReadWangset(r, customTypeDefinitions)); internal static Wangset ReadWangset( XmlReader reader, @@ -334,7 +333,7 @@ internal static WangTile ReadWangTile(XmlReader reader) var wangID = reader.GetRequiredAttributeParseable("wangid", s => { // Comma-separated list of indices (0-254) - var indices = s.Split(',').Select(i => byte.Parse(i)).ToArray(); + var indices = s.Split(',').Select(i => byte.Parse(i, CultureInfo.InvariantCulture)).ToArray(); if (indices.Length > 8) throw new ArgumentException("Wang ID can have at most 8 indices."); return indices; diff --git a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs index be21580..5a99ff6 100644 --- a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs +++ b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs @@ -39,14 +39,11 @@ public TmxMapReader( _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); // Prepare reader - _reader.MoveToContent(); + _ = _reader.MoveToContent(); } /// - public Map ReadMap() - { - return Tmx.ReadMap(_reader, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions); - } + public Map ReadMap() => Tmx.ReadMap(_reader, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions); /// protected virtual void Dispose(bool disposing) @@ -77,6 +74,6 @@ public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); - System.GC.SuppressFinalize(this); + GC.SuppressFinalize(this); } } diff --git a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs index 374a0d1..0034150 100644 --- a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs @@ -35,7 +35,7 @@ public TsxTilesetReader( _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); // Prepare reader - _reader.MoveToContent(); + _ = _reader.MoveToContent(); } /// @@ -49,6 +49,7 @@ protected virtual void Dispose(bool disposing) if (disposing) { // TODO: dispose managed state (managed objects) + _reader.Dispose(); } // TODO: free unmanaged resources (unmanaged objects) and override finalizer @@ -69,6 +70,6 @@ public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); - System.GC.SuppressFinalize(this); + GC.SuppressFinalize(this); } } diff --git a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs index fe93244..fbaf85c 100644 --- a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs +++ b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs @@ -39,7 +39,7 @@ public TxTemplateReader( _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); // Prepare reader - _reader.MoveToContent(); + _ = _reader.MoveToContent(); } /// @@ -53,6 +53,7 @@ protected virtual void Dispose(bool disposing) if (disposing) { // TODO: dispose managed state (managed objects) + _reader.Dispose(); } // TODO: free unmanaged resources (unmanaged objects) and override finalizer @@ -73,6 +74,6 @@ public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); - System.GC.SuppressFinalize(this); + GC.SuppressFinalize(this); } } From b6721934e40519463ffe9f3d801cbec472fba4f3 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Thu, 22 Aug 2024 21:12:16 +0200 Subject: [PATCH 08/23] More lint fixing --- .editorconfig | 6 ++- .github/workflows/pull-request.yml | 8 +-- Makefile | 4 +- src/DotTiled.Tests/Assert/AssertObject.cs | 31 +++-------- src/DotTiled.Tests/Assert/AssertProperties.cs | 35 +++--------- src/DotTiled.Tests/Serialization/TestData.cs | 53 ++++--------------- .../Tmj/ExtensionsJsonElement.cs | 7 +-- 7 files changed, 36 insertions(+), 108 deletions(-) diff --git a/.editorconfig b/.editorconfig index 8c68b86..3c889ed 100644 --- a/.editorconfig +++ b/.editorconfig @@ -42,7 +42,7 @@ dotnet_style_require_accessibility_modifiers = for_non_interface_members dotnet_style_coalesce_expression = true dotnet_style_collection_initializer = false dotnet_style_explicit_tuple_names = true -dotnet_style_namespace_match_folder = true +dotnet_style_namespace_match_folder = false dotnet_style_null_propagation = true dotnet_style_object_initializer = true dotnet_style_operator_placement_when_wrapping = beginning_of_line @@ -116,7 +116,7 @@ csharp_style_prefer_top_level_statements = true # Expression-level preferences csharp_prefer_simple_default_expression = true csharp_style_deconstructed_variable_declaration = true -csharp_style_implicit_object_creation_when_type_is_apparent = true +csharp_style_implicit_object_creation_when_type_is_apparent = false csharp_style_inlined_variable_declaration = true csharp_style_prefer_index_operator = true csharp_style_prefer_local_over_anonymous_function = true @@ -234,7 +234,9 @@ dotnet_diagnostic.IDE0001.severity = none dotnet_diagnostic.IDE0004.severity = silent dotnet_diagnostic.IDE0005.severity = error dotnet_diagnostic.IDE0008.severity = silent +dotnet_diagnostic.IDE0055.severity = silent dotnet_diagnostic.IDE0160.severity = none +dotnet_diagnostic.CA1707.severity = silent [.github/**/*.yml] charset = utf-8 diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index f24db4a..d744fce 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -19,7 +19,7 @@ jobs: run: dotnet build --no-restore src/DotTiled.sln - name: Test run: dotnet test --no-build --verbosity normal src/DotTiled.sln - - name: Lint - run: | - dotnet format style --verify-no-changes --verbosity diagnostic src/DotTiled.sln - dotnet format analyzers --verify-no-changes --verbosity diagnostic src/DotTiled.sln + - name: Lint style + run: dotnet format style --verify-no-changes --verbosity diagnostic src/DotTiled.sln + - name: Lint analyzers + run: dotnet format analyzers --verify-no-changes --verbosity diagnostic src/DotTiled.sln diff --git a/Makefile b/Makefile index 3790c68..c5fa89a 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,8 @@ docs-build: lint: dotnet build src/DotTiled.sln - dotnet format style --verify-no-changes --verbosity diagnostic src/DotTiled.sln - dotnet format analyzers --verify-no-changes --verbosity diagnostic src/DotTiled.sln + dotnet format style --verify-no-changes src/DotTiled.sln + dotnet format analyzers --verify-no-changes src/DotTiled.sln BENCHMARK_SOURCES = DotTiled.Benchmark/Program.cs DotTiled.Benchmark/DotTiled.Benchmark.csproj BENCHMARK_OUTPUTDIR = DotTiled.Benchmark/BenchmarkDotNet.Artifacts diff --git a/src/DotTiled.Tests/Assert/AssertObject.cs b/src/DotTiled.Tests/Assert/AssertObject.cs index d982ebd..bc8e54c 100644 --- a/src/DotTiled.Tests/Assert/AssertObject.cs +++ b/src/DotTiled.Tests/Assert/AssertObject.cs @@ -24,30 +24,15 @@ internal static void AssertObject(Model.Object expected, Model.Object actual) AssertObject((dynamic)expected, (dynamic)actual); } - private static void AssertObject(RectangleObject expected, RectangleObject actual) - { - Assert.True(true); // A rectangle object is the same as the abstract Object - } + private static void AssertObject(RectangleObject _, RectangleObject __) => Assert.True(true); // A rectangle object is the same as the abstract Object - private static void AssertObject(EllipseObject expected, EllipseObject actual) - { - Assert.True(true); // An ellipse object is the same as the abstract Object - } + private static void AssertObject(EllipseObject _, EllipseObject __) => Assert.True(true); // An ellipse object is the same as the abstract Object - private static void AssertObject(PointObject expected, PointObject actual) - { - Assert.True(true); // A point object is the same as the abstract Object - } + private static void AssertObject(PointObject _, PointObject __) => Assert.True(true); // A point object is the same as the abstract Object - private static void AssertObject(PolygonObject expected, PolygonObject actual) - { - AssertEqual(expected.Points, actual.Points, nameof(PolygonObject.Points)); - } + private static void AssertObject(PolygonObject expected, PolygonObject actual) => AssertEqual(expected.Points, actual.Points, nameof(PolygonObject.Points)); - private static void AssertObject(PolylineObject expected, PolylineObject actual) - { - AssertEqual(expected.Points, actual.Points, nameof(PolylineObject.Points)); - } + private static void AssertObject(PolylineObject expected, PolylineObject actual) => AssertEqual(expected.Points, actual.Points, nameof(PolylineObject.Points)); private static void AssertObject(TextObject expected, TextObject actual) { @@ -67,9 +52,5 @@ private static void AssertObject(TextObject expected, TextObject actual) AssertEqual(expected.Text, actual.Text, nameof(TextObject.Text)); } - private static void AssertObject(TileObject expected, TileObject actual) - { - // Attributes - AssertEqual(expected.GID, actual.GID, nameof(TileObject.GID)); - } + private static void AssertObject(TileObject expected, TileObject actual) => AssertEqual(expected.GID, actual.GID, nameof(TileObject.GID)); } diff --git a/src/DotTiled.Tests/Assert/AssertProperties.cs b/src/DotTiled.Tests/Assert/AssertProperties.cs index 16d9cdb..646d6eb 100644 --- a/src/DotTiled.Tests/Assert/AssertProperties.cs +++ b/src/DotTiled.Tests/Assert/AssertProperties.cs @@ -28,40 +28,19 @@ private static void AssertProperty(IProperty expected, IProperty actual) AssertProperties((dynamic)actual, (dynamic)expected); } - private static void AssertProperty(StringProperty expected, StringProperty actual) - { - AssertEqual(expected.Value, actual.Value, "StringProperty.Value"); - } + 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"); - } + private static void AssertProperty(IntProperty expected, IntProperty actual) => AssertEqual(expected.Value, actual.Value, "IntProperty.Value"); - private static void AssertProperty(FloatProperty expected, FloatProperty actual) - { - AssertEqual(expected.Value, actual.Value, "FloatProperty.Value"); - } + private static void AssertProperty(FloatProperty expected, FloatProperty actual) => AssertEqual(expected.Value, actual.Value, "FloatProperty.Value"); - private static void AssertProperty(BoolProperty expected, BoolProperty actual) - { - AssertEqual(expected.Value, actual.Value, "BoolProperty.Value"); - } + private static void AssertProperty(BoolProperty expected, BoolProperty actual) => AssertEqual(expected.Value, actual.Value, "BoolProperty.Value"); - private static void AssertProperty(ColorProperty expected, ColorProperty actual) - { - AssertEqual(expected.Value, actual.Value, "ColorProperty.Value"); - } + private static void AssertProperty(ColorProperty expected, ColorProperty actual) => AssertEqual(expected.Value, actual.Value, "ColorProperty.Value"); - private static void AssertProperty(FileProperty expected, FileProperty actual) - { - AssertEqual(expected.Value, actual.Value, "FileProperty.Value"); - } + private static void AssertProperty(FileProperty expected, FileProperty actual) => AssertEqual(expected.Value, actual.Value, "FileProperty.Value"); - private static void AssertProperty(ObjectProperty expected, ObjectProperty actual) - { - AssertEqual(expected.Value, actual.Value, "ObjectProperty.Value"); - } + private static void AssertProperty(ObjectProperty expected, ObjectProperty actual) => AssertEqual(expected.Value, actual.Value, "ObjectProperty.Value"); private static void AssertProperty(ClassProperty expected, ClassProperty actual) { diff --git a/src/DotTiled.Tests/Serialization/TestData.cs b/src/DotTiled.Tests/Serialization/TestData.cs index c36cab5..f6e49b5 100644 --- a/src/DotTiled.Tests/Serialization/TestData.cs +++ b/src/DotTiled.Tests/Serialization/TestData.cs @@ -32,49 +32,14 @@ private static string ConvertPathToAssemblyResourcePath(string path) => public static IEnumerable MapTests => [ - ["Serialization/TestData/Map/default_map/default-map", (string f) => TestData.DefaultMap(), Array.Empty()], - ["Serialization/TestData/Map/map_with_common_props/map-with-common-props", (string f) => TestData.MapWithCommonProps(), Array.Empty()], - ["Serialization/TestData/Map/map_with_custom_type_props/map-with-custom-type-props", (string f) => TestData.MapWithCustomTypeProps(), TestData.MapWithCustomTypePropsCustomTypeDefinitions()], - ["Serialization/TestData/Map/map_with_embedded_tileset/map-with-embedded-tileset", (string f) => TestData.MapWithEmbeddedTileset(), Array.Empty()], - ["Serialization/TestData/Map/map_with_external_tileset/map-with-external-tileset", (string f) => TestData.MapWithExternalTileset(f), Array.Empty()], - ["Serialization/TestData/Map/map_with_flippingflags/map-with-flippingflags", (string f) => TestData.MapWithFlippingFlags(f), Array.Empty()], - ["Serialization/TestData/Map/map_external_tileset_multi/map-external-tileset-multi", (string f) => TestData.MapExternalTilesetMulti(f), Array.Empty()], - ["Serialization/TestData/Map/map_external_tileset_wangset/map-external-tileset-wangset", (string f) => TestData.MapExternalTilesetWangset(f), Array.Empty()], - ["Serialization/TestData/Map/map_with_many_layers/map-with-many-layers", (string f) => TestData.MapWithManyLayers(f), Array.Empty()], - ]; - - private static CustomTypeDefinition[] typedefs = [ - new CustomClassDefinition - { - Name = "TestClass", - ID = 1, - UseAs = CustomClassUseAs.Property, - Members = [ - new StringProperty - { - Name = "Name", - Value = "" - }, - new FloatProperty - { - Name = "Amount", - Value = 0f - } - ] - }, - new CustomClassDefinition - { - Name = "Test", - ID = 2, - UseAs = CustomClassUseAs.All, - Members = [ - new ClassProperty - { - Name = "Yep", - PropertyType = "TestClass", - Properties = [] - } - ] - } + ["Serialization/TestData/Map/default_map/default-map", (string f) => DefaultMap(), Array.Empty()], + ["Serialization/TestData/Map/map_with_common_props/map-with-common-props", (string f) => MapWithCommonProps(), Array.Empty()], + ["Serialization/TestData/Map/map_with_custom_type_props/map-with-custom-type-props", (string f) => MapWithCustomTypeProps(), MapWithCustomTypePropsCustomTypeDefinitions()], + ["Serialization/TestData/Map/map_with_embedded_tileset/map-with-embedded-tileset", (string f) => MapWithEmbeddedTileset(), Array.Empty()], + ["Serialization/TestData/Map/map_with_external_tileset/map-with-external-tileset", (string f) => MapWithExternalTileset(f), Array.Empty()], + ["Serialization/TestData/Map/map_with_flippingflags/map-with-flippingflags", (string f) => MapWithFlippingFlags(f), Array.Empty()], + ["Serialization/TestData/Map/map_external_tileset_multi/map-external-tileset-multi", (string f) => MapExternalTilesetMulti(f), Array.Empty()], + ["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()], ]; } diff --git a/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs b/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs index 7717df4..0e76d84 100644 --- a/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs +++ b/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs @@ -9,9 +9,10 @@ internal static class ExtensionsJsonElement { internal static T GetRequiredProperty(this JsonElement element, string propertyName) { - return !element.TryGetProperty(propertyName, out var property) - ? throw new JsonException($"Missing required property '{propertyName}'.") - : property.GetValueAs(); + if (!element.TryGetProperty(propertyName, out var property)) + throw new JsonException($"Missing required property '{propertyName}'."); + + return property.GetValueAs(); } internal static T GetOptionalProperty(this JsonElement element, string propertyName, T defaultValue) From 251aa7fc94c0c7485e060408dd452697f7f18151 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Sat, 24 Aug 2024 14:24:14 +0200 Subject: [PATCH 09/23] Make sure linting works as of now, will have to adjust later --- .editorconfig | 5 +++++ Makefile | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 3c889ed..71746d2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -237,6 +237,11 @@ dotnet_diagnostic.IDE0008.severity = silent dotnet_diagnostic.IDE0055.severity = silent dotnet_diagnostic.IDE0160.severity = none dotnet_diagnostic.CA1707.severity = silent +dotnet_diagnostic.CA1852.severity = none +dotnet_diagnostic.CA1805.severity = none +dotnet_diagnostic.CA1720.severity = silent +dotnet_diagnostic.CA1711.severity = silent +dotnet_diagnostic.CA1716.severity = silent [.github/**/*.yml] charset = utf-8 diff --git a/Makefile b/Makefile index c5fa89a..9b64573 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,6 @@ docs-build: docfx docs/docfx.json lint: - dotnet build src/DotTiled.sln dotnet format style --verify-no-changes src/DotTiled.sln dotnet format analyzers --verify-no-changes src/DotTiled.sln From 1c1ba326b283988fbaa0c901db920de55ca71a70 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Sat, 24 Aug 2024 21:38:40 +0200 Subject: [PATCH 10/23] Restructure properties API --- src/DotTiled.Tests/Assert/AssertMap.cs | 2 +- src/DotTiled.Tests/Assert/AssertProperties.cs | 21 ++++++- .../map-with-common-props.cs | 20 +++---- .../map-with-custom-type-props.cs | 26 ++++---- src/DotTiled/Model/Map.cs | 7 ++- src/DotTiled/Model/Properties/BoolProperty.cs | 2 +- .../Model/Properties/ClassProperty.cs | 26 +++++++- .../Model/Properties/ColorProperty.cs | 2 +- src/DotTiled/Model/Properties/FileProperty.cs | 2 +- .../Model/Properties/FloatProperty.cs | 2 +- .../Model/Properties/IHasProperties.cs | 59 +++++++++++++++++++ src/DotTiled/Model/Properties/IProperty.cs | 12 ++++ src/DotTiled/Model/Properties/IntProperty.cs | 2 +- .../Model/Properties/ObjectProperty.cs | 2 +- .../Model/Properties/StringProperty.cs | 2 +- src/DotTiled/Serialization/Helpers.cs | 47 ++++++++++++++- src/DotTiled/Serialization/Tmj/Tmj.Map.cs | 4 +- .../Serialization/Tmj/Tmj.Properties.cs | 52 ++++++++++++---- src/DotTiled/Serialization/Tmx/Tmx.Map.cs | 6 +- .../Serialization/Tmx/Tmx.Properties.cs | 48 ++++++++++++--- 20 files changed, 282 insertions(+), 62 deletions(-) create mode 100644 src/DotTiled/Model/Properties/IHasProperties.cs diff --git a/src/DotTiled.Tests/Assert/AssertMap.cs b/src/DotTiled.Tests/Assert/AssertMap.cs index 6984b79..6f25f45 100644 --- a/src/DotTiled.Tests/Assert/AssertMap.cs +++ b/src/DotTiled.Tests/Assert/AssertMap.cs @@ -91,7 +91,7 @@ internal static void AssertMap(Map expected, Map actual) AssertEqual(expected.NextObjectID, actual.NextObjectID, nameof(Map.NextObjectID)); AssertEqual(expected.Infinite, actual.Infinite, nameof(Map.Infinite)); - AssertProperties(actual.Properties, expected.Properties); + AssertPropertiesList(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 646d6eb..ad4dc53 100644 --- a/src/DotTiled.Tests/Assert/AssertProperties.cs +++ b/src/DotTiled.Tests/Assert/AssertProperties.cs @@ -21,6 +21,25 @@ internal static void AssertProperties(Dictionary? expected, D } } + internal static void AssertPropertiesList(IList? expected, IList? actual) + { + if (expected is null) + { + Assert.Null(actual); + return; + } + + Assert.NotNull(actual); + AssertEqual(expected.Count, actual.Count, "Properties.Count"); + foreach (var prop in expected) + { + Assert.Contains(actual, p => p.Name == prop.Name); + + var actualProp = actual.First(p => p.Name == prop.Name); + AssertProperty((dynamic)prop, (dynamic)actualProp); + } + } + private static void AssertProperty(IProperty expected, IProperty actual) { AssertEqual(expected.Type, actual.Type, "Property.Type"); @@ -45,6 +64,6 @@ private static void AssertProperty(IProperty expected, IProperty actual) private static void AssertProperty(ClassProperty expected, ClassProperty actual) { AssertEqual(expected.PropertyType, actual.PropertyType, "ClassProperty.PropertyType"); - AssertProperties(expected.Properties, actual.Properties); + AssertPropertiesList(expected.Value, actual.Value); } } diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs index ba5cf4f..d5d8c1e 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs @@ -55,15 +55,15 @@ public partial class TestData } } ], - Properties = new Dictionary - { - ["boolprop"] = new BoolProperty { Name = "boolprop", Value = true }, - ["colorprop"] = new ColorProperty { Name = "colorprop", Value = Color.Parse("#ff55ffff", CultureInfo.InvariantCulture) }, - ["fileprop"] = new FileProperty { Name = "fileprop", Value = "file.txt" }, - ["floatprop"] = new FloatProperty { Name = "floatprop", Value = 4.2f }, - ["intprop"] = new IntProperty { Name = "intprop", Value = 8 }, - ["objectprop"] = new ObjectProperty { Name = "objectprop", Value = 5 }, - ["stringprop"] = new StringProperty { Name = "stringprop", Value = "This is a string, hello world!" } - } + Properties = + [ + new BoolProperty { Name = "boolprop", Value = true }, + new ColorProperty { Name = "colorprop", Value = Color.Parse("#ff55ffff", CultureInfo.InvariantCulture) }, + new FileProperty { Name = "fileprop", Value = "file.txt" }, + new FloatProperty { Name = "floatprop", Value = 4.2f }, + new IntProperty { Name = "intprop", Value = 8 }, + new ObjectProperty { Name = "objectprop", Value = 5 }, + new StringProperty { Name = "stringprop", Value = "This is a string, hello world!" } + ] }; } diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs index 758c5c3..2c79478 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs @@ -55,24 +55,22 @@ public partial class TestData } } ], - Properties = new Dictionary - { - ["customclassprop"] = new ClassProperty + Properties = [ + new ClassProperty { Name = "customclassprop", PropertyType = "CustomClass", - Properties = new Dictionary - { - ["boolinclass"] = new BoolProperty { Name = "boolinclass", Value = true }, - ["colorinclass"] = new ColorProperty { Name = "colorinclass", Value = Color.Parse("#000000ff", CultureInfo.InvariantCulture) }, - ["fileinclass"] = new FileProperty { Name = "fileinclass", Value = "" }, - ["floatinclass"] = new FloatProperty { Name = "floatinclass", Value = 13.37f }, - ["intinclass"] = new IntProperty { Name = "intinclass", Value = 0 }, - ["objectinclass"] = new ObjectProperty { Name = "objectinclass", Value = 0 }, - ["stringinclass"] = new StringProperty { Name = "stringinclass", Value = "This is a set string" } - } + Value = [ + new BoolProperty { Name = "boolinclass", Value = true }, + new ColorProperty { Name = "colorinclass", Value = Color.Parse("#000000ff", CultureInfo.InvariantCulture) }, + new FileProperty { Name = "fileinclass", Value = "" }, + new FloatProperty { Name = "floatinclass", Value = 13.37f }, + new IntProperty { Name = "intinclass", Value = 0 }, + new ObjectProperty { Name = "objectinclass", Value = 0 }, + new StringProperty { Name = "stringinclass", Value = "This is a set string" } + ] } - } + ] }; // This comes from map-with-custom-type-props/propertytypes.json diff --git a/src/DotTiled/Model/Map.cs b/src/DotTiled/Model/Map.cs index c9c72dc..48ed975 100644 --- a/src/DotTiled/Model/Map.cs +++ b/src/DotTiled/Model/Map.cs @@ -90,7 +90,7 @@ public enum StaggerIndex /// /// Represents a Tiled map. /// -public class Map +public class Map : HasPropertiesBase { /// /// The TMX format version. Is incremented to match minor Tiled releases. @@ -191,7 +191,10 @@ public class Map /// /// Map properties. /// - public Dictionary? Properties { get; set; } + public List Properties { get; set; } = []; + + /// + public override IList GetProperties() => Properties; /// /// List of tilesets used by the map. diff --git a/src/DotTiled/Model/Properties/BoolProperty.cs b/src/DotTiled/Model/Properties/BoolProperty.cs index bc60a87..315e820 100644 --- a/src/DotTiled/Model/Properties/BoolProperty.cs +++ b/src/DotTiled/Model/Properties/BoolProperty.cs @@ -3,7 +3,7 @@ namespace DotTiled.Model; /// /// Represents a boolean property. /// -public class BoolProperty : IProperty +public class BoolProperty : IProperty { /// public required string Name { get; set; } diff --git a/src/DotTiled/Model/Properties/ClassProperty.cs b/src/DotTiled/Model/Properties/ClassProperty.cs index 50d65ba..eb7efce 100644 --- a/src/DotTiled/Model/Properties/ClassProperty.cs +++ b/src/DotTiled/Model/Properties/ClassProperty.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace DotTiled.Model; @@ -6,7 +7,7 @@ namespace DotTiled.Model; /// /// Represents a class property. /// -public class ClassProperty : IProperty +public class ClassProperty : IHasProperties, IProperty> { /// public required string Name { get; set; } @@ -23,13 +24,32 @@ public class ClassProperty : IProperty /// /// The properties of the class property. /// - public required Dictionary Properties { get; set; } + public required IList Value { get; set; } /// public IProperty Clone() => new ClassProperty { Name = Name, PropertyType = PropertyType, - Properties = Properties.ToDictionary(p => p.Key, p => p.Value.Clone()) + Value = Value.Select(property => property.Clone()).ToList() }; + + /// + public IList GetProperties() => Value; + + /// + public T GetProperty(string name) where T : IProperty => throw new System.NotImplementedException(); + + /// + public bool TryGetProperty(string name, [NotNullWhen(true)] out T? property) where T : IProperty + { + if (Value.FirstOrDefault(_properties => _properties.Name == name) is T prop) + { + property = prop; + return true; + } + + property = default; + return false; + } } diff --git a/src/DotTiled/Model/Properties/ColorProperty.cs b/src/DotTiled/Model/Properties/ColorProperty.cs index aec43f6..7c4a132 100644 --- a/src/DotTiled/Model/Properties/ColorProperty.cs +++ b/src/DotTiled/Model/Properties/ColorProperty.cs @@ -3,7 +3,7 @@ namespace DotTiled.Model; /// /// Represents a color property. /// -public class ColorProperty : IProperty +public class ColorProperty : IProperty { /// public required string Name { get; set; } diff --git a/src/DotTiled/Model/Properties/FileProperty.cs b/src/DotTiled/Model/Properties/FileProperty.cs index 4ed8642..7c65121 100644 --- a/src/DotTiled/Model/Properties/FileProperty.cs +++ b/src/DotTiled/Model/Properties/FileProperty.cs @@ -3,7 +3,7 @@ namespace DotTiled.Model; /// /// Represents a file property. /// -public class FileProperty : IProperty +public class FileProperty : IProperty { /// public required string Name { get; set; } diff --git a/src/DotTiled/Model/Properties/FloatProperty.cs b/src/DotTiled/Model/Properties/FloatProperty.cs index 4c6b51f..57ba928 100644 --- a/src/DotTiled/Model/Properties/FloatProperty.cs +++ b/src/DotTiled/Model/Properties/FloatProperty.cs @@ -3,7 +3,7 @@ namespace DotTiled.Model; /// /// Represents a float property. /// -public class FloatProperty : IProperty +public class FloatProperty : IProperty { /// public required string Name { get; set; } diff --git a/src/DotTiled/Model/Properties/IHasProperties.cs b/src/DotTiled/Model/Properties/IHasProperties.cs new file mode 100644 index 0000000..28b8532 --- /dev/null +++ b/src/DotTiled/Model/Properties/IHasProperties.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace DotTiled.Model; + +/// +/// Interface for objects that have properties attached to them. +/// +public interface IHasProperties +{ + /// + /// The properties attached to the object. + /// + IList GetProperties(); + + /// + /// Tries to get a property of the specified type with the specified name. + /// + /// The type of the property to get. + /// The name of the property to get. + /// The property with the specified name, if found. + /// True if a property with the specified name was found; otherwise, false. + bool TryGetProperty(string name, out T? property) where T : IProperty; + + /// + /// Gets a property of the specified type with the specified name. + /// + /// The type of the property to get. + /// The name of the property to get. + /// The property with the specified name. + T GetProperty(string name) where T : IProperty; +} + +/// +/// Base class for objects that have properties attached to them. +/// +public abstract class HasPropertiesBase : IHasProperties +{ + /// + public abstract IList GetProperties(); + + /// + public T GetProperty(string name) where T : IProperty => throw new System.NotImplementedException(); + + /// + public bool TryGetProperty(string name, [NotNullWhen(true)] out T? property) where T : IProperty + { + var properties = GetProperties(); + if (properties.FirstOrDefault(_properties => _properties.Name == name) is T prop) + { + property = prop; + return true; + } + + property = default; + return false; + } +} diff --git a/src/DotTiled/Model/Properties/IProperty.cs b/src/DotTiled/Model/Properties/IProperty.cs index 262ee09..d2d98e8 100644 --- a/src/DotTiled/Model/Properties/IProperty.cs +++ b/src/DotTiled/Model/Properties/IProperty.cs @@ -22,3 +22,15 @@ public interface IProperty /// An identical, but non-reference-equal, instance of the same property. IProperty Clone(); } + +/// +/// Interface for properties that can be attached to objects, tiles, tilesets, maps etc. +/// +/// The type of the property value. +public interface IProperty : IProperty +{ + /// + /// The value of the property. + /// + public T Value { get; set; } +} diff --git a/src/DotTiled/Model/Properties/IntProperty.cs b/src/DotTiled/Model/Properties/IntProperty.cs index 29f7a1d..27a7afc 100644 --- a/src/DotTiled/Model/Properties/IntProperty.cs +++ b/src/DotTiled/Model/Properties/IntProperty.cs @@ -3,7 +3,7 @@ namespace DotTiled.Model; /// /// Represents an integer property. /// -public class IntProperty : IProperty +public class IntProperty : IProperty { /// public required string Name { get; set; } diff --git a/src/DotTiled/Model/Properties/ObjectProperty.cs b/src/DotTiled/Model/Properties/ObjectProperty.cs index 04b15ba..de8a1e0 100644 --- a/src/DotTiled/Model/Properties/ObjectProperty.cs +++ b/src/DotTiled/Model/Properties/ObjectProperty.cs @@ -3,7 +3,7 @@ namespace DotTiled.Model; /// /// Represents an object property. /// -public class ObjectProperty : IProperty +public class ObjectProperty : IProperty { /// public required string Name { get; set; } diff --git a/src/DotTiled/Model/Properties/StringProperty.cs b/src/DotTiled/Model/Properties/StringProperty.cs index 49d7aec..0c20b29 100644 --- a/src/DotTiled/Model/Properties/StringProperty.cs +++ b/src/DotTiled/Model/Properties/StringProperty.cs @@ -3,7 +3,7 @@ namespace DotTiled.Model; /// /// Represents a string property. /// -public class StringProperty : IProperty +public class StringProperty : IProperty { /// public required string Name { get; set; } diff --git a/src/DotTiled/Serialization/Helpers.cs b/src/DotTiled/Serialization/Helpers.cs index c6cdefe..0028650 100644 --- a/src/DotTiled/Serialization/Helpers.cs +++ b/src/DotTiled/Serialization/Helpers.cs @@ -73,6 +73,9 @@ internal static ImageFormat ParseImageFormatFromSource(string source) }; } + 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) @@ -93,7 +96,7 @@ internal static Dictionary MergeProperties(Dictionary MergeProperties(Dictionary MergePropertiesList(IList? baseProperties, IList? overrideProperties) + { + if (baseProperties is null) + return overrideProperties ?? []; + + if (overrideProperties is null) + return baseProperties; + + var result = baseProperties.Select(x => x.Clone()).ToList(); + foreach (var overrideProp in overrideProperties) + { + if (!result.Any(x => x.Name == overrideProp.Name)) + { + result.Add(overrideProp); + continue; + } + else + { + var existingProp = result.First(x => x.Name == overrideProp.Name); + if (existingProp is ClassProperty classProp) + { + classProp.Value = MergePropertiesList(classProp.Value, ((ClassProperty)overrideProp).Value); + } + else + { + ReplacePropertyInList(result, overrideProp); + } + } + } + + return result; + } + + internal static void ReplacePropertyInList(List properties, IProperty property) + { + var index = properties.FindIndex(p => p.Name == property.Name); + if (index == -1) + properties.Add(property); + else + properties[index] = property; + } + internal static void SetAtMostOnce(ref T? field, T value, string fieldName) { if (field is not null) diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs b/src/DotTiled/Serialization/Tmj/Tmj.Map.cs index 47dde3f..dd1a012 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Map.cs @@ -58,7 +58,7 @@ internal static Map ReadMap( var nextObjectID = element.GetRequiredProperty("nextobjectid"); var infinite = element.GetOptionalProperty("infinite", false); - var properties = element.GetOptionalPropertyCustom?>("properties", el => ReadProperties(el, customTypeDefinitions), null); + var properties = element.GetOptionalPropertyCustom?>("properties", el => ReadPropertiesList(el, customTypeDefinitions), null); 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 static Map ReadMap( NextLayerID = nextLayerID, NextObjectID = nextObjectID, Infinite = infinite, - Properties = properties, + Properties = properties ?? [], Tilesets = tilesets, Layers = layers }; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs b/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs index 0c35bbe..5b25429 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs @@ -43,6 +43,41 @@ internal static Dictionary ReadProperties( return property!; }).ToDictionary(p => p.Name); + internal static List ReadPropertiesList( + 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!; + }); + internal static ClassProperty ReadClassProperty( JsonElement element, IReadOnlyCollection customTypeDefinitions) @@ -54,28 +89,28 @@ internal static ClassProperty ReadClassProperty( if (customTypeDef is CustomClassDefinition ccd) { - var propsInType = CreateInstanceOfCustomClass(ccd); - var props = element.GetOptionalPropertyCustom>("value", el => ReadCustomClassProperties(el, ccd, customTypeDefinitions), []); + var propsInType = Helpers.CreateInstanceOfCustomClass(ccd); + var props = element.GetOptionalPropertyCustom>("value", el => ReadCustomClassProperties(el, ccd, customTypeDefinitions), []); - var mergedProps = Helpers.MergeProperties(propsInType, props); + var mergedProps = Helpers.MergePropertiesList(propsInType, props); return new ClassProperty { Name = name, PropertyType = propertyType, - Properties = mergedProps + Value = props }; } throw new JsonException($"Unknown custom class '{propertyType}'."); } - internal static Dictionary ReadCustomClassProperties( + internal static List ReadCustomClassProperties( JsonElement element, CustomClassDefinition customClassDefinition, IReadOnlyCollection customTypeDefinitions) { - Dictionary resultingProps = []; + List resultingProps = Helpers.CreateInstanceOfCustomClass(customClassDefinition); foreach (var prop in customClassDefinition.Members) { @@ -95,12 +130,9 @@ internal static Dictionary ReadCustomClassProperties( _ => throw new JsonException("Invalid property type") }; - resultingProps[prop.Name] = property; + Helpers.ReplacePropertyInList(resultingProps, property); } return resultingProps; } - - internal static Dictionary CreateInstanceOfCustomClass(CustomClassDefinition customClassDefinition) => - customClassDefinition.Members.ToDictionary(m => m.Name, m => m.Clone()); } diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs b/src/DotTiled/Serialization/Tmx/Tmx.Map.cs index 1987bb1..6dd5ea5 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Map.cs @@ -61,7 +61,7 @@ internal static Map ReadMap( var infinite = (reader.GetOptionalAttributeParseable("infinite") ?? 0) == 1; // At most one of - Dictionary? properties = null; + List? properties = null; // Any number of List layers = []; @@ -69,7 +69,7 @@ internal static Map ReadMap( reader.ProcessChildren("map", (r, elementName) => elementName switch { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(r, customTypeDefinitions), "Properties"), + "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadPropertiesList(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)), @@ -99,7 +99,7 @@ internal static Map ReadMap( NextLayerID = nextLayerID, NextObjectID = nextObjectID, Infinite = infinite, - Properties = properties, + Properties = properties ?? [], Tilesets = tilesets, Layers = layers }; diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs b/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs index 9a748d6..98ee546 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs @@ -43,6 +43,42 @@ internal static Dictionary ReadProperties( }).ToDictionary(x => x.name, x => x.property); } + internal static List ReadPropertiesList( + 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 property; + }); + } + internal static ClassProperty ReadClassProperty( XmlReader reader, IReadOnlyCollection customTypeDefinitions) @@ -54,18 +90,14 @@ internal static ClassProperty ReadClassProperty( if (customTypeDef is CustomClassDefinition ccd) { reader.ReadStartElement("property"); - var propsInType = CreateInstanceOfCustomClass(ccd); - var props = ReadProperties(reader, customTypeDefinitions); - - var mergedProps = Helpers.MergeProperties(propsInType, props); + var propsInType = Helpers.CreateInstanceOfCustomClass(ccd); + var props = ReadPropertiesList(reader, customTypeDefinitions); + var mergedProps = Helpers.MergePropertiesList(propsInType, props); reader.ReadEndElement(); - return new ClassProperty { Name = name, PropertyType = propertyType, Properties = mergedProps }; + return new ClassProperty { Name = name, PropertyType = propertyType, Value = mergedProps }; } throw new XmlException($"Unkonwn custom class definition: {propertyType}"); } - - internal static Dictionary CreateInstanceOfCustomClass(CustomClassDefinition customClassDefinition) => - customClassDefinition.Members.ToDictionary(m => m.Name, m => m.Clone()); } From b46eed774a8816f2795c06ee0c2fe08e97c81229 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Sat, 24 Aug 2024 22:06:14 +0200 Subject: [PATCH 11/23] More property changes --- src/DotTiled.Tests/Serialization/TestData.cs | 16 ++++++++-------- .../map-with-custom-type-props.cs | 2 +- .../Serialization/Tmj/TmjMapReaderTests.cs | 2 +- .../Serialization/Tmx/TmxMapReaderTests.cs | 2 +- src/DotTiled/Model/Properties/ClassProperty.cs | 12 +++++++++++- .../CustomTypes/CustomClassDefinition.cs | 11 ++++++++++- .../CustomTypes/CustomEnumDefinition.cs | 8 +++++++- .../CustomTypes/CustomTypeDefinition.cs | 4 ++-- src/DotTiled/Model/Properties/IHasProperties.cs | 17 +++++++++++++++-- .../Serialization/Tmj/TjTemplateReader.cs | 4 ++-- src/DotTiled/Serialization/Tmj/Tmj.Group.cs | 2 +- .../Serialization/Tmj/Tmj.ImageLayer.cs | 2 +- src/DotTiled/Serialization/Tmj/Tmj.Layer.cs | 2 +- src/DotTiled/Serialization/Tmj/Tmj.Map.cs | 2 +- .../Serialization/Tmj/Tmj.ObjectLayer.cs | 4 ++-- .../Serialization/Tmj/Tmj.Properties.cs | 8 ++++---- src/DotTiled/Serialization/Tmj/Tmj.Template.cs | 2 +- src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs | 2 +- src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs | 8 ++++---- src/DotTiled/Serialization/Tmj/TmjMapReader.cs | 4 ++-- .../Serialization/Tmj/TsjTilesetReader.cs | 4 ++-- src/DotTiled/Serialization/Tmx/Tmx.Map.cs | 2 +- .../Serialization/Tmx/Tmx.ObjectLayer.cs | 6 +++--- .../Serialization/Tmx/Tmx.Properties.cs | 6 +++--- src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs | 6 +++--- src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs | 10 +++++----- src/DotTiled/Serialization/Tmx/TmxMapReader.cs | 4 ++-- .../Serialization/Tmx/TsxTilesetReader.cs | 4 ++-- .../Serialization/Tmx/TxTemplateReader.cs | 4 ++-- 29 files changed, 99 insertions(+), 61 deletions(-) diff --git a/src/DotTiled.Tests/Serialization/TestData.cs b/src/DotTiled.Tests/Serialization/TestData.cs index f6e49b5..b007913 100644 --- a/src/DotTiled.Tests/Serialization/TestData.cs +++ b/src/DotTiled.Tests/Serialization/TestData.cs @@ -32,14 +32,14 @@ private static string ConvertPathToAssemblyResourcePath(string path) => public static IEnumerable MapTests => [ - ["Serialization/TestData/Map/default_map/default-map", (string f) => DefaultMap(), Array.Empty()], - ["Serialization/TestData/Map/map_with_common_props/map-with-common-props", (string f) => MapWithCommonProps(), Array.Empty()], + ["Serialization/TestData/Map/default_map/default-map", (string f) => DefaultMap(), Array.Empty()], + ["Serialization/TestData/Map/map_with_common_props/map-with-common-props", (string f) => MapWithCommonProps(), Array.Empty()], ["Serialization/TestData/Map/map_with_custom_type_props/map-with-custom-type-props", (string f) => MapWithCustomTypeProps(), MapWithCustomTypePropsCustomTypeDefinitions()], - ["Serialization/TestData/Map/map_with_embedded_tileset/map-with-embedded-tileset", (string f) => MapWithEmbeddedTileset(), Array.Empty()], - ["Serialization/TestData/Map/map_with_external_tileset/map-with-external-tileset", (string f) => MapWithExternalTileset(f), Array.Empty()], - ["Serialization/TestData/Map/map_with_flippingflags/map-with-flippingflags", (string f) => MapWithFlippingFlags(f), Array.Empty()], - ["Serialization/TestData/Map/map_external_tileset_multi/map-external-tileset-multi", (string f) => MapExternalTilesetMulti(f), Array.Empty()], - ["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_embedded_tileset/map-with-embedded-tileset", (string f) => MapWithEmbeddedTileset(), Array.Empty()], + ["Serialization/TestData/Map/map_with_external_tileset/map-with-external-tileset", (string f) => MapWithExternalTileset(f), Array.Empty()], + ["Serialization/TestData/Map/map_with_flippingflags/map-with-flippingflags", (string f) => MapWithFlippingFlags(f), Array.Empty()], + ["Serialization/TestData/Map/map_external_tileset_multi/map-external-tileset-multi", (string f) => MapExternalTilesetMulti(f), Array.Empty()], + ["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()], ]; } diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs index 2c79478..ea0575e 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs @@ -74,7 +74,7 @@ public partial class TestData }; // This comes from map-with-custom-type-props/propertytypes.json - public static IReadOnlyCollection MapWithCustomTypePropsCustomTypeDefinitions() => [ + public static IReadOnlyCollection MapWithCustomTypePropsCustomTypeDefinitions() => [ new CustomClassDefinition { Name = "CustomClass", diff --git a/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs b/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs index bdd19e8..3fe6843 100644 --- a/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs @@ -11,7 +11,7 @@ public partial class TmjMapReaderTests public void TmxMapReaderReadMap_ValidTmjExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected( string testDataFile, Func expectedMap, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { // Arrange testDataFile += ".tmj"; diff --git a/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs b/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs index ee74718..fb825ed 100644 --- a/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs @@ -11,7 +11,7 @@ public partial class TmxMapReaderTests public void TmxMapReaderReadMap_ValidXmlExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected( string testDataFile, Func expectedMap, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { // Arrange testDataFile += ".tmx"; diff --git a/src/DotTiled/Model/Properties/ClassProperty.cs b/src/DotTiled/Model/Properties/ClassProperty.cs index eb7efce..5c9d6a5 100644 --- a/src/DotTiled/Model/Properties/ClassProperty.cs +++ b/src/DotTiled/Model/Properties/ClassProperty.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -38,7 +39,16 @@ public class ClassProperty : IHasProperties, IProperty> public IList GetProperties() => Value; /// - public T GetProperty(string name) where T : IProperty => throw new System.NotImplementedException(); + public T GetProperty(string name) where T : IProperty + { + var property = Value.FirstOrDefault(_properties => _properties.Name == name) ?? throw new InvalidOperationException($"Property '{name}' not found."); + if (property is T prop) + { + return prop; + } + + throw new InvalidOperationException($"Property '{name}' is not of type '{typeof(T).Name}'."); + } /// public bool TryGetProperty(string name, [NotNullWhen(true)] out T? property) where T : IProperty diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs b/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs index b5aa0ec..313081f 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs +++ b/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs @@ -65,8 +65,14 @@ public enum CustomClassUseAs /// Represents a custom class definition in Tiled. Refer to the /// documentation of custom types to understand how they work. /// -public class CustomClassDefinition : CustomTypeDefinition +public class CustomClassDefinition : HasPropertiesBase, ICustomTypeDefinition { + /// + public uint ID { get; set; } + + /// + public required string Name { get; set; } + /// /// The color of the custom class inside the Tiled editor. /// @@ -86,4 +92,7 @@ public class CustomClassDefinition : CustomTypeDefinition /// The members of the custom class, with their names, types and default values. /// public List Members { get; set; } = []; + + /// + public override IList GetProperties() => Members; } diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs b/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs index ee40be0..60b7f5b 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs +++ b/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs @@ -22,8 +22,14 @@ public enum CustomEnumStorageType /// Represents a custom enum definition in Tiled. Refer to the /// documentation of custom types to understand how they work. /// -public class CustomEnumDefinition : CustomTypeDefinition +public class CustomEnumDefinition : ICustomTypeDefinition { + /// + public uint ID { get; set; } + + /// + public required string Name { get; set; } + /// /// The storage type of the custom enum. /// diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs b/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs index 3a91b0a..1e595cc 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs +++ b/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs @@ -3,7 +3,7 @@ namespace DotTiled.Model; /// /// Base class for custom type definitions. /// -public abstract class CustomTypeDefinition +public interface ICustomTypeDefinition { /// /// The ID of the custom type. @@ -13,5 +13,5 @@ public abstract class CustomTypeDefinition /// /// The name of the custom type. /// - public string Name { get; set; } = ""; + public string Name { get; set; } } diff --git a/src/DotTiled/Model/Properties/IHasProperties.cs b/src/DotTiled/Model/Properties/IHasProperties.cs index 28b8532..1b124a9 100644 --- a/src/DotTiled/Model/Properties/IHasProperties.cs +++ b/src/DotTiled/Model/Properties/IHasProperties.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -33,7 +34,7 @@ public interface IHasProperties } /// -/// Base class for objects that have properties attached to them. +/// Interface for objects that have properties attached to them. /// public abstract class HasPropertiesBase : IHasProperties { @@ -41,7 +42,19 @@ public abstract class HasPropertiesBase : IHasProperties public abstract IList GetProperties(); /// - public T GetProperty(string name) where T : IProperty => throw new System.NotImplementedException(); + /// Thrown when a property with the specified name is not found. + /// Thrown when a property with the specified name is not of the specified type. + public T GetProperty(string name) where T : IProperty + { + var properties = GetProperties(); + var property = properties.FirstOrDefault(_properties => _properties.Name == name) ?? throw new KeyNotFoundException($"Property '{name}' not found."); + if (property is T prop) + { + return prop; + } + + throw new InvalidCastException($"Property '{name}' is not of type '{typeof(T).Name}'."); + } /// public bool TryGetProperty(string name, [NotNullWhen(true)] out T? property) where T : IProperty diff --git a/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs b/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs index 3a66f1b..c4ada75 100644 --- a/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs +++ b/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs @@ -16,7 +16,7 @@ public class TjTemplateReader : ITemplateReader private readonly string _jsonString; private bool disposedValue; - private readonly IReadOnlyCollection _customTypeDefinitions; + private readonly IReadOnlyCollection _customTypeDefinitions; /// /// Constructs a new . @@ -30,7 +30,7 @@ public TjTemplateReader( string jsonString, Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { _jsonString = jsonString ?? throw new ArgumentNullException(nameof(jsonString)); _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Group.cs b/src/DotTiled/Serialization/Tmj/Tmj.Group.cs index 0885167..ae44a75 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Group.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Group.cs @@ -11,7 +11,7 @@ internal partial class Tmj internal static Group ReadGroup( JsonElement element, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var id = element.GetRequiredProperty("id"); var name = element.GetRequiredProperty("name"); diff --git a/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs index 794f2b5..bbbb151 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs @@ -9,7 +9,7 @@ internal partial class Tmj { internal static ImageLayer ReadImageLayer( JsonElement element, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var id = element.GetRequiredProperty("id"); var name = element.GetRequiredProperty("name"); diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs b/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs index b9f8de0..aeef011 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs @@ -10,7 +10,7 @@ internal partial class Tmj internal static BaseLayer ReadLayer( JsonElement element, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var type = element.GetRequiredProperty("type"); diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs b/src/DotTiled/Serialization/Tmj/Tmj.Map.cs index dd1a012..cdde458 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Map.cs @@ -12,7 +12,7 @@ internal static Map ReadMap( JsonElement element, Func? externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var version = element.GetRequiredProperty("version"); var tiledVersion = element.GetRequiredProperty("tiledversion"); diff --git a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs index 6775389..75d5ee0 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs @@ -12,7 +12,7 @@ internal partial class Tmj internal static ObjectLayer ReadObjectLayer( JsonElement element, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var id = element.GetRequiredProperty("id"); var name = element.GetRequiredProperty("name"); @@ -66,7 +66,7 @@ internal static ObjectLayer ReadObjectLayer( internal static Model.Object ReadObject( JsonElement element, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { uint? idDefault = null; string nameDefault = ""; diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs b/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs index 5b25429..caa5fbe 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs @@ -10,7 +10,7 @@ internal partial class Tmj { internal static Dictionary ReadProperties( JsonElement element, - IReadOnlyCollection customTypeDefinitions) => + IReadOnlyCollection customTypeDefinitions) => element.GetValueAsList(e => { var name = e.GetRequiredProperty("name"); @@ -45,7 +45,7 @@ internal static Dictionary ReadProperties( internal static List ReadPropertiesList( JsonElement element, - IReadOnlyCollection customTypeDefinitions) => + IReadOnlyCollection customTypeDefinitions) => element.GetValueAsList(e => { var name = e.GetRequiredProperty("name"); @@ -80,7 +80,7 @@ internal static List ReadPropertiesList( internal static ClassProperty ReadClassProperty( JsonElement element, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var name = element.GetRequiredProperty("name"); var propertyType = element.GetRequiredProperty("propertytype"); @@ -108,7 +108,7 @@ internal static ClassProperty ReadClassProperty( internal static List ReadCustomClassProperties( JsonElement element, CustomClassDefinition customClassDefinition, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { List resultingProps = Helpers.CreateInstanceOfCustomClass(customClassDefinition); diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Template.cs b/src/DotTiled/Serialization/Tmj/Tmj.Template.cs index 3746b76..71ba1e7 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Template.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Template.cs @@ -11,7 +11,7 @@ internal static Template ReadTemplate( JsonElement element, Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var type = element.GetRequiredProperty("type"); var tileset = element.GetOptionalPropertyCustom("tileset", el => ReadTileset(el, externalTilesetResolver, externalTemplateResolver, customTypeDefinitions), null); diff --git a/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs b/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs index 353f7fd..cdda654 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs @@ -9,7 +9,7 @@ internal partial class Tmj { internal static TileLayer ReadTileLayer( JsonElement element, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var compression = element.GetOptionalPropertyParseable("compression", s => s switch { diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs b/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs index e0e2bd2..7f3d6be 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs +++ b/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs @@ -12,7 +12,7 @@ internal static Tileset ReadTileset( JsonElement element, Func? externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var backgroundColor = element.GetOptionalPropertyParseable("backgroundcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); var @class = element.GetOptionalProperty("class", ""); @@ -162,7 +162,7 @@ internal static TileOffset ReadTileOffset(JsonElement element) internal static List ReadTiles( JsonElement element, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) => + IReadOnlyCollection customTypeDefinitions) => element.GetValueAsList(e => { var animation = e.GetOptionalPropertyCustom?>("animation", e => e.GetValueAsList(ReadFrame), null); @@ -218,7 +218,7 @@ internal static Frame ReadFrame(JsonElement element) internal static Wangset ReadWangset( JsonElement element, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var @clalss = element.GetOptionalProperty("class", ""); var colors = element.GetOptionalPropertyCustom>("colors", e => e.GetValueAsList(el => ReadWangColor(el, customTypeDefinitions)), []); @@ -241,7 +241,7 @@ internal static Wangset ReadWangset( internal static WangColor ReadWangColor( JsonElement element, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var @class = element.GetOptionalProperty("class", ""); var color = element.GetRequiredPropertyParseable("color", s => Color.Parse(s, CultureInfo.InvariantCulture)); diff --git a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs index c26311b..1d277b1 100644 --- a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs +++ b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs @@ -17,7 +17,7 @@ public class TmjMapReader : IMapReader private readonly string _jsonString; private bool disposedValue; - private readonly IReadOnlyCollection _customTypeDefinitions; + private readonly IReadOnlyCollection _customTypeDefinitions; /// /// Constructs a new . @@ -31,7 +31,7 @@ public TmjMapReader( string jsonString, Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { _jsonString = jsonString ?? throw new ArgumentNullException(nameof(jsonString)); _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); diff --git a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs index aca5556..dde9075 100644 --- a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs @@ -15,7 +15,7 @@ public class TsjTilesetReader : ITilesetReader private readonly string _jsonString; private bool disposedValue; - private readonly IReadOnlyCollection _customTypeDefinitions; + private readonly IReadOnlyCollection _customTypeDefinitions; /// /// Constructs a new . @@ -27,7 +27,7 @@ public class TsjTilesetReader : ITilesetReader public TsjTilesetReader( string jsonString, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { _jsonString = jsonString ?? throw new ArgumentNullException(nameof(jsonString)); _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs b/src/DotTiled/Serialization/Tmx/Tmx.Map.cs index 6dd5ea5..cabfdcc 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Map.cs @@ -13,7 +13,7 @@ internal static Map ReadMap( XmlReader reader, Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { // Attributes var version = reader.GetRequiredAttribute("version"); diff --git a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs b/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs index 7a375d9..4929ede 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs @@ -13,7 +13,7 @@ internal partial class Tmx internal static ObjectLayer ReadObjectLayer( XmlReader reader, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { // Attributes var id = reader.GetRequiredAttributeParseable("id"); @@ -75,7 +75,7 @@ internal static ObjectLayer ReadObjectLayer( internal static Model.Object ReadObject( XmlReader reader, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { // Attributes var template = reader.GetOptionalAttribute("template"); @@ -308,7 +308,7 @@ internal static Template ReadTemplate( XmlReader reader, Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { // No attributes diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs b/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs index 98ee546..f641c4f 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs @@ -9,7 +9,7 @@ internal partial class Tmx { internal static Dictionary ReadProperties( XmlReader reader, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { return reader.ReadList("properties", "property", (r) => { @@ -45,7 +45,7 @@ internal static Dictionary ReadProperties( internal static List ReadPropertiesList( XmlReader reader, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { return reader.ReadList("properties", "property", (r) => { @@ -81,7 +81,7 @@ internal static List ReadPropertiesList( internal static ClassProperty ReadClassProperty( XmlReader reader, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var name = reader.GetRequiredAttribute("name"); var propertyType = reader.GetRequiredAttribute("propertytype"); diff --git a/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs b/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs index 8b972a3..320019d 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs @@ -11,7 +11,7 @@ internal partial class Tmx internal static TileLayer ReadTileLayer( XmlReader reader, bool dataUsesChunks, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var id = reader.GetRequiredAttributeParseable("id"); var name = reader.GetOptionalAttribute("name") ?? ""; @@ -61,7 +61,7 @@ internal static TileLayer ReadTileLayer( internal static ImageLayer ReadImageLayer( XmlReader reader, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var id = reader.GetRequiredAttributeParseable("id"); var name = reader.GetOptionalAttribute("name") ?? ""; @@ -112,7 +112,7 @@ internal static ImageLayer ReadImageLayer( internal static Group ReadGroup( XmlReader reader, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { var id = reader.GetRequiredAttributeParseable("id"); var name = reader.GetOptionalAttribute("name") ?? ""; diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs b/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs index 198f32d..6fb1ff5 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs +++ b/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs @@ -14,7 +14,7 @@ internal static Tileset ReadTileset( XmlReader reader, Func? externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { // Attributes var version = reader.GetOptionalAttribute("version"); @@ -207,7 +207,7 @@ internal static Transformations ReadTransformations(XmlReader reader) internal static Tile ReadTile( XmlReader reader, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { // Attributes var id = reader.GetRequiredAttributeParseable("id"); @@ -256,12 +256,12 @@ internal static Tile ReadTile( internal static List ReadWangsets( XmlReader reader, - IReadOnlyCollection customTypeDefinitions) => + IReadOnlyCollection customTypeDefinitions) => reader.ReadList("wangsets", "wangset", r => ReadWangset(r, customTypeDefinitions)); internal static Wangset ReadWangset( XmlReader reader, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { // Attributes var name = reader.GetRequiredAttribute("name"); @@ -297,7 +297,7 @@ internal static Wangset ReadWangset( internal static WangColor ReadWangColor( XmlReader reader, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { // Attributes var name = reader.GetRequiredAttribute("name"); diff --git a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs index 5a99ff6..279c83d 100644 --- a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs +++ b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs @@ -17,7 +17,7 @@ public class TmxMapReader : IMapReader private readonly XmlReader _reader; private bool disposedValue; - private readonly IReadOnlyCollection _customTypeDefinitions; + private readonly IReadOnlyCollection _customTypeDefinitions; /// /// Constructs a new . @@ -31,7 +31,7 @@ public TmxMapReader( XmlReader reader, Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { _reader = reader ?? throw new ArgumentNullException(nameof(reader)); _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); diff --git a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs index 0034150..0b69d4c 100644 --- a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs @@ -16,7 +16,7 @@ public class TsxTilesetReader : ITilesetReader private readonly XmlReader _reader; private bool disposedValue; - private readonly IReadOnlyCollection _customTypeDefinitions; + private readonly IReadOnlyCollection _customTypeDefinitions; /// /// Constructs a new . @@ -28,7 +28,7 @@ public class TsxTilesetReader : ITilesetReader public TsxTilesetReader( XmlReader reader, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { _reader = reader ?? throw new ArgumentNullException(nameof(reader)); _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); diff --git a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs index fbaf85c..ed7ba8e 100644 --- a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs +++ b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs @@ -17,7 +17,7 @@ public class TxTemplateReader : ITemplateReader private readonly XmlReader _reader; private bool disposedValue; - private readonly IReadOnlyCollection _customTypeDefinitions; + private readonly IReadOnlyCollection _customTypeDefinitions; /// /// Constructs a new . @@ -31,7 +31,7 @@ public TxTemplateReader( XmlReader reader, Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + IReadOnlyCollection customTypeDefinitions) { _reader = reader ?? throw new ArgumentNullException(nameof(reader)); _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); From 4580772cede4fd44d5d4b2efdef85a697b7820a2 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Sat, 24 Aug 2024 23:08:24 +0200 Subject: [PATCH 12/23] Fix rest of model to use new structure and prepare docs --- docs/docs/accessing-properties.md | 1 + docs/docs/toc.yml | 3 +- src/DotTiled.Tests/Assert/AssertMap.cs | 2 +- src/DotTiled.Tests/Assert/AssertProperties.cs | 31 +++----------- .../map-external-tileset-multi.cs | 19 ++++----- .../map-with-many-layers.cs | 7 ++-- src/DotTiled/Model/Layers/BaseLayer.cs | 7 +++- src/DotTiled/Model/Layers/Objects/Object.cs | 7 +++- src/DotTiled/Model/Tilesets/Tile.cs | 7 +++- src/DotTiled/Model/Tilesets/Tileset.cs | 11 +++-- src/DotTiled/Model/Tilesets/WangColor.cs | 7 +++- src/DotTiled/Model/Tilesets/Wangset.cs | 7 +++- src/DotTiled/Serialization/Helpers.cs | 36 +--------------- src/DotTiled/Serialization/Tmj/Tmj.Group.cs | 2 +- .../Serialization/Tmj/Tmj.ImageLayer.cs | 2 +- src/DotTiled/Serialization/Tmj/Tmj.Map.cs | 4 +- .../Serialization/Tmj/Tmj.ObjectLayer.cs | 6 +-- .../Serialization/Tmj/Tmj.Properties.cs | 39 +---------------- .../Serialization/Tmj/Tmj.TileLayer.cs | 2 +- src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs | 8 ++-- src/DotTiled/Serialization/Tmx/Tmx.Map.cs | 2 +- .../Serialization/Tmx/Tmx.ObjectLayer.cs | 14 +++---- .../Serialization/Tmx/Tmx.Properties.cs | 42 ++----------------- .../Serialization/Tmx/Tmx.TileLayer.cs | 12 +++--- src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs | 16 +++---- 25 files changed, 94 insertions(+), 200 deletions(-) create mode 100644 docs/docs/accessing-properties.md 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 @@ internal static void AssertMap(Map expected, Map actual) 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 @@ internal static void AssertPropertiesList(IList? expected, IList 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 @@ private static void AssertProperty(IProperty expected, IProperty actual) 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 ImageFormat ParseImageFormatFromSource(string source) 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 IList MergePropertiesList(IList? basePrope 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 static Group ReadGroup( 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 static ImageLayer ReadImageLayer( 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 static Map ReadMap( 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 static Map ReadMap( 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 static ObjectLayer ReadObjectLayer( 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 static Model.Object ReadObject( 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 static Model.Object ReadObject( 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 static ClassProperty ReadClassProperty( 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 static TileLayer ReadTileLayer( 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 static Tileset ReadTileset( "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 static List ReadTiles( 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 static Wangset ReadWangset( 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 static WangColor ReadWangColor( 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 static Map ReadMap( 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 static ObjectLayer ReadObjectLayer( }) ?? DrawOrder.TopDown; // Elements - Dictionary? properties = null; + List? properties = null; List objects = []; reader.ProcessChildren("objectgroup", (r, elementName) => elementName switch @@ -66,7 +66,7 @@ internal static ObjectLayer ReadObjectLayer( ParallaxX = parallaxX, ParallaxY = parallaxY, Color = color, - Properties = properties, + Properties = properties ?? [], DrawOrder = drawOrder, Objects = objects }; @@ -93,7 +93,7 @@ internal static Model.Object ReadObject( 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 static Model.Object ReadObject( // 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 static Model.Object ReadObject( 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 static Model.Object OverrideObject(Model.Object? obj, Model.Object foun 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 static ClassProperty ReadClassProperty( { 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 static TileLayer ReadTileLayer( 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 static TileLayer ReadTileLayer( ParallaxX = parallaxX, ParallaxY = parallaxY, Data = data, - Properties = properties + Properties = properties ?? [] }; } @@ -78,7 +78,7 @@ internal static ImageLayer ReadImageLayer( 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 static ImageLayer ReadImageLayer( OffsetY = offsetY, ParallaxX = parallaxX, ParallaxY = parallaxY, - Properties = properties, + Properties = properties ?? [], Image = image, RepeatX = repeatX, RepeatY = repeatY @@ -125,7 +125,7 @@ internal static Group ReadGroup( 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 static Group ReadGroup( 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 static Tileset ReadTileset( 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 static Tileset ReadTileset( Image = image, TileOffset = tileOffset, Grid = grid, - Properties = properties, + Properties = properties ?? [], Wangsets = wangsets, Transformations = transformations, Tiles = tiles @@ -219,7 +219,7 @@ internal static Tile ReadTile( 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 static Tile ReadTile( 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 static Wangset ReadWangset( var tile = reader.GetRequiredAttributeParseable("tile"); // Elements - Dictionary? properties = null; + List? properties = null; List wangColors = []; List wangTiles = []; @@ -289,7 +289,7 @@ internal static Wangset ReadWangset( Name = name, Class = @class, Tile = tile, - Properties = properties, + Properties = properties ?? [], WangColors = wangColors, WangTiles = wangTiles }; @@ -307,7 +307,7 @@ internal static WangColor ReadWangColor( 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 static WangColor ReadWangColor( Color = color, Tile = tile, Probability = probability, - Properties = properties + Properties = properties ?? [] }; } From 7ca19713215e62fbdbd9d327d90e728deee37d02 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Sun, 25 Aug 2024 00:16:59 +0200 Subject: [PATCH 13/23] A first attempt at documentation for properties --- docs/docs/accessing-properties.md | 96 +++++++++++++++++++++++++- docs/images/monster-spawner-class.png | Bin 0 -> 17831 bytes 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 docs/images/monster-spawner-class.png diff --git a/docs/docs/accessing-properties.md b/docs/docs/accessing-properties.md index 0269b88..04e1846 100644 --- a/docs/docs/accessing-properties.md +++ b/docs/docs/accessing-properties.md @@ -1 +1,95 @@ -# Accessing properties \ No newline at end of file +# Accessing properties + +[Tiled facilitates a very flexible way to store custom data in your maps using properties](https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-properties). Accessing these properties is a common task when working with Tiled maps in your game since it will allow you to fully utilize the strengths of Tiled, such as customizing the behavior of your game objects or setting up the initial state of your game world. + +### All classes that can contain properties + +All classes that can contain custom properties implement the interface in some way. Below is an exhaustive list of all classes that can contain custom properties: + +- + - + - + - + - +- (allows for recursive property objects) +- (used to define custom Tiled property types) +- + - + - + - + - + - + - + - +- +- +- +- + +### How to access properties + +To access the properties on one of the classes listed above, you will make use of the interface. + +In situations where you know that a property must exist, and you simply want to retrieve it, you can use the method like so: + +```csharp +var map = LoadMap(); +var propertyValue = map.GetProperty("boolPropertyInMap").Value; +``` + +If you are unsure whether a property exists, or you want to provide some kind of default behaviour if the property is not present, you can instead use the method like so: + +```csharp +var map = LoadMap(); +if (map.TryGetProperty("boolPropertyInMap", out var property)) +{ + // Do something with existing property + var propertyValue = property.Value; +} +else +{ + // Do something if property does not exist +} +``` + +### All types of properties + +Tiled supports a variety of property types, which are represented in the DotTiled library as classes that implement the interface. Below is a list of all property types that Tiled supports and their corresponding classes in DotTiled: + +- `bool` - +- `color` - +- `float` - +- `file` - +- `int` - +- `object` - +- `string` - + +In addition to these primitive property types, [Tiled also supports more complex property types](https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-types). These custom property types are defined in Tiled according to the linked documentation, and to work with them in DotTiled, you *must* define their equivalences as a collection of . This collection of definitions shall then be passed to the corresponding reader when loading a map, tileset, or template. + +Whenever DotTiled encounters a property that is of type `class` in a Tiled file, it will attempt to find the corresponding definition, and if it does not find one, it will throw an exception. However, if it does find the definition, it will use that definition to know the default values of the properties of that class, and then override those defaults with the values found in the Tiled file. More information about these `class` properties can be found in [the next section](#class-properties). + +Finally, Tiled also allows you to define custom property types that work as enums. These custom property types are just parsed and retrieved as their corresponding storage type. So for a custom property type that is defined as an enum where the values are stored as strings, DotTiled will just parse those as . Similarly, if the values are stored as integers, DotTiled will parse those as . + +### Class properties + +As mentioned, Tiled supports `class` properties which allow you to create hierarchical structures of properties. DotTiled supports this feature through the class. For all your custom `class` types in Tiled, you must create an equivalent and pass it to the corresponding reader when loading a map, tileset, or template. + +For example, if you have a `class` property in Tiled that looks like this: + +![MonsterSpawner class in Tiled UI](../images/monster-spawner-class.png) + +The equivalent definition in DotTiled would look like the following: + +```csharp +var monsterSpawnerDefinition = new CustomClassDefinition +{ + Name = "MonsterSpawner", + UseAs = CustomClassUseAs.All, // Not really validated by DotTiled + Members = [ // Make sure that the default values match the Tiled UI + new BoolProperty { Name = "enabled", Value = true }, + new IntProperty { Name = "maxSpawnAmount", Value = 10 }, + new IntProperty { Name = "minSpawnAmount", Value = 0 }, + new StringProperty { Name = "monsterNames", Value = "" } + ] +}; +``` \ No newline at end of file diff --git a/docs/images/monster-spawner-class.png b/docs/images/monster-spawner-class.png new file mode 100644 index 0000000000000000000000000000000000000000..c3b5ef410d3649cd504f7f4ab564ac5b2b7b3134 GIT binary patch literal 17831 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 literal 0 HcmV?d00001 From eda3fbe308070d40a32d04c0d0518fdb74441fd3 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Sun, 25 Aug 2024 00:37:28 +0200 Subject: [PATCH 14/23] More docs --- docs/docs/accessing-properties.md | 36 +++++++++++++++++++++--------- docs/images/resolve-types.png | Bin 0 -> 19541 bytes 2 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 docs/images/resolve-types.png diff --git a/docs/docs/accessing-properties.md b/docs/docs/accessing-properties.md index 04e1846..59fcfea 100644 --- a/docs/docs/accessing-properties.md +++ b/docs/docs/accessing-properties.md @@ -2,7 +2,7 @@ [Tiled facilitates a very flexible way to store custom data in your maps using properties](https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-properties). Accessing these properties is a common task when working with Tiled maps in your game since it will allow you to fully utilize the strengths of Tiled, such as customizing the behavior of your game objects or setting up the initial state of your game world. -### All classes that can contain properties +## All classes that can contain properties All classes that can contain custom properties implement the interface in some way. Below is an exhaustive list of all classes that can contain custom properties: @@ -26,7 +26,7 @@ All classes that can contain custom properties implement the interface - -### How to access properties +## How to access properties To access the properties on one of the classes listed above, you will make use of the interface. @@ -52,7 +52,9 @@ else } ``` -### All types of properties +For both methods, you can replace `BoolProperty` with any of the property types that Tiled supports. You can find a list of all property types and their corresponding classes in the [next section](#all-types-of-properties). + +## All types of properties Tiled supports a variety of property types, which are represented in the DotTiled library as classes that implement the interface. Below is a list of all property types that Tiled supports and their corresponding classes in DotTiled: @@ -66,11 +68,11 @@ Tiled supports a variety of property types, which are represented in the DotTile In addition to these primitive property types, [Tiled also supports more complex property types](https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-types). These custom property types are defined in Tiled according to the linked documentation, and to work with them in DotTiled, you *must* define their equivalences as a collection of . This collection of definitions shall then be passed to the corresponding reader when loading a map, tileset, or template. -Whenever DotTiled encounters a property that is of type `class` in a Tiled file, it will attempt to find the corresponding definition, and if it does not find one, it will throw an exception. However, if it does find the definition, it will use that definition to know the default values of the properties of that class, and then override those defaults with the values found in the Tiled file. More information about these `class` properties can be found in [the next section](#class-properties). +Whenever DotTiled encounters a property that is of type `class` in a Tiled file, it will attempt to find the corresponding definition, and if it does not find one, it will throw an exception. However, if it does find the definition, it will use that definition to know the default values of the properties of that class, and then override those defaults with the values found in the Tiled file when populating a instance. More information about these `class` properties can be found in [the next section](#class-properties). Finally, Tiled also allows you to define custom property types that work as enums. These custom property types are just parsed and retrieved as their corresponding storage type. So for a custom property type that is defined as an enum where the values are stored as strings, DotTiled will just parse those as . Similarly, if the values are stored as integers, DotTiled will parse those as . -### Class properties +## Class properties As mentioned, Tiled supports `class` properties which allow you to create hierarchical structures of properties. DotTiled supports this feature through the class. For all your custom `class` types in Tiled, you must create an equivalent and pass it to the corresponding reader when loading a map, tileset, or template. @@ -86,10 +88,24 @@ var monsterSpawnerDefinition = new CustomClassDefinition Name = "MonsterSpawner", UseAs = CustomClassUseAs.All, // Not really validated by DotTiled Members = [ // Make sure that the default values match the Tiled UI - new BoolProperty { Name = "enabled", Value = true }, - new IntProperty { Name = "maxSpawnAmount", Value = 10 }, - new IntProperty { Name = "minSpawnAmount", Value = 0 }, - new StringProperty { Name = "monsterNames", Value = "" } + new BoolProperty { Name = "enabled", Value = true }, + new IntProperty { Name = "maxSpawnAmount", Value = 10 }, + new IntProperty { Name = "minSpawnAmount", Value = 0 }, + new StringProperty { Name = "monsterNames", Value = "" } ] }; -``` \ No newline at end of file +``` + +### Resolve object types and properties automatically + +If you don't want to have to rely on creating an equivalent definition for every `class` property that you may be using in your Tiled maps, you can check the `Resolve object types and properties` checkbox in `Edit > Preferences > General | Export Options` in Tiled. + +![Resolve object types and properties](../images/resolve-types.png) + +This will make sure that all properties, even those that do not differ from their default values, are included in the exported map, tileset, or template file. This will allow DotTiled to resolve the properties of the `class` property without needing an equivalent definition. However, you *must* enable a similar configuration flag in DotTiled when loading the map, tileset, or template to make sure that DotTiled knows to not throw an exception when it encounters a `class` property without an equivalent definition. + +### [Future] Automatically map custom property `class` types to C# classes + +In the future, DotTiled will support automatically mapping custom property `class` types to C# classes. This will allow you to define a C# class that matches the structure of the `class` property in Tiled, and DotTiled will automatically map the properties of the `class` property to the properties of the C# class. This will make working with `class` properties much easier and more intuitive. + +The idea is to expand on the interface with a method like `GetMappedProperty(string propertyName)`, where `T` is a class that matches the structure of the `class` property in Tiled. \ No newline at end of file diff --git a/docs/images/resolve-types.png b/docs/images/resolve-types.png new file mode 100644 index 0000000000000000000000000000000000000000..ea66d43618f89214acd5428815ca152ec1cf5f2d GIT binary patch literal 19541 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 NlvRCR_S7u!e*rjBFwFn} literal 0 HcmV?d00001 From 11f1ef783e0f3c255b14567cab1ec5cb239e474d Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Sun, 25 Aug 2024 17:43:13 +0200 Subject: [PATCH 15/23] Tmx reader is now a base abstract class --- src/DotTiled.Benchmark/Program.cs | 2 +- src/DotTiled.Tests/Assert/AssertMap.cs | 2 +- src/DotTiled.Tests/Assert/AssertProperties.cs | 10 + src/DotTiled.Tests/Assert/AssertTileset.cs | 6 +- .../map-with-custom-type-props.cs | 68 ++++ .../map-with-custom-type-props.tmj | 24 ++ .../map-with-custom-type-props.tmx | 4 + .../Serialization/Tmx/TmxMapReaderTests.cs | 10 +- src/DotTiled/Model/Properties/EnumProperty.cs | 50 +++ src/DotTiled/Model/Properties/PropertyType.cs | 7 +- src/DotTiled/Serialization/Tmx/Tmx.Map.cs | 107 ------ .../Serialization/Tmx/Tmx.Properties.cs | 67 ---- .../Serialization/Tmx/Tmx.TileLayer.cs | 157 -------- src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs | 350 ------------------ .../Serialization/Tmx/TmxMapReader.cs | 65 +--- .../{Tmx.Chunk.cs => TmxReaderBase.Chunk.cs} | 17 +- .../{Tmx.Data.cs => TmxReaderBase.Data.cs} | 16 +- .../Serialization/Tmx/TmxReaderBase.Map.cs | 104 ++++++ ...tLayer.cs => TmxReaderBase.ObjectLayer.cs} | 147 ++++---- .../Tmx/TmxReaderBase.Properties.cs | 140 +++++++ .../Tmx/TmxReaderBase.TileLayer.cs | 147 ++++++++ .../Tmx/TmxReaderBase.Tileset.cs | 317 ++++++++++++++++ .../Serialization/Tmx/TmxReaderBase.cs | 74 ++++ .../Serialization/Tmx/TsxTilesetReader.cs | 63 +--- .../Serialization/Tmx/TxTemplateReader.cs | 65 +--- 25 files changed, 1059 insertions(+), 960 deletions(-) create mode 100644 src/DotTiled/Model/Properties/EnumProperty.cs delete mode 100644 src/DotTiled/Serialization/Tmx/Tmx.Map.cs delete mode 100644 src/DotTiled/Serialization/Tmx/Tmx.Properties.cs delete mode 100644 src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs delete mode 100644 src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs rename src/DotTiled/Serialization/Tmx/{Tmx.Chunk.cs => TmxReaderBase.Chunk.cs} (59%) rename src/DotTiled/Serialization/Tmx/{Tmx.Data.cs => TmxReaderBase.Data.cs} (88%) create mode 100644 src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs rename src/DotTiled/Serialization/Tmx/{Tmx.ObjectLayer.cs => TmxReaderBase.ObjectLayer.cs} (58%) create mode 100644 src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs create mode 100644 src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs create mode 100644 src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs create mode 100644 src/DotTiled/Serialization/Tmx/TmxReaderBase.cs diff --git a/src/DotTiled.Benchmark/Program.cs b/src/DotTiled.Benchmark/Program.cs index bf67fd0..3cd6e15 100644 --- a/src/DotTiled.Benchmark/Program.cs +++ b/src/DotTiled.Benchmark/Program.cs @@ -39,7 +39,7 @@ public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmxString() { using var stringReader = new StringReader(_tmxContents); using var xmlReader = XmlReader.Create(stringReader); - using var mapReader = new DotTiled.Serialization.Tmx.TmxMapReader(xmlReader, _ => throw new NotSupportedException(), _ => throw new NotSupportedException(), []); + using var mapReader = new DotTiled.Serialization.Tmx.TmxMapReader(xmlReader, _ => throw new NotSupportedException(), _ => throw new NotSupportedException(), _ => throw new NotSupportedException()); return mapReader.ReadMap(); } diff --git a/src/DotTiled.Tests/Assert/AssertMap.cs b/src/DotTiled.Tests/Assert/AssertMap.cs index 6984b79..358029b 100644 --- a/src/DotTiled.Tests/Assert/AssertMap.cs +++ b/src/DotTiled.Tests/Assert/AssertMap.cs @@ -91,7 +91,7 @@ internal static void AssertMap(Map expected, Map actual) AssertEqual(expected.NextObjectID, actual.NextObjectID, nameof(Map.NextObjectID)); AssertEqual(expected.Infinite, actual.Infinite, nameof(Map.Infinite)); - AssertProperties(actual.Properties, expected.Properties); + AssertProperties(expected.Properties, actual.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 21fa639..84af365 100644 --- a/src/DotTiled.Tests/Assert/AssertProperties.cs +++ b/src/DotTiled.Tests/Assert/AssertProperties.cs @@ -45,4 +45,14 @@ private static void AssertProperty(ClassProperty expected, ClassProperty actual) AssertEqual(expected.PropertyType, actual.PropertyType, "ClassProperty.PropertyType"); AssertProperties(expected.Value, actual.Value); } + + private static void AssertProperty(EnumProperty expected, EnumProperty actual) + { + AssertEqual(expected.PropertyType, actual.PropertyType, "EnumProperty.PropertyType"); + AssertEqual(expected.Value.Count, actual.Value.Count, "EnumProperty.Value.Count"); + foreach (var value in expected.Value) + { + Assert.Contains(actual.Value, v => v == value); + } + } } diff --git a/src/DotTiled.Tests/Assert/AssertTileset.cs b/src/DotTiled.Tests/Assert/AssertTileset.cs index 134cc30..befc79a 100644 --- a/src/DotTiled.Tests/Assert/AssertTileset.cs +++ b/src/DotTiled.Tests/Assert/AssertTileset.cs @@ -141,9 +141,9 @@ private static void AssertTile(Tile expected, Tile actual) AssertEqual(expected.Height, actual.Height, nameof(Tile.Height)); // Elements - AssertProperties(actual.Properties, expected.Properties); - AssertImage(actual.Image, expected.Image); - AssertLayer((BaseLayer?)actual.ObjectLayer, (BaseLayer?)expected.ObjectLayer); + AssertProperties(expected.Properties, actual.Properties); + AssertImage(expected.Image, actual.Image); + AssertLayer((BaseLayer?)expected.ObjectLayer, (BaseLayer?)actual.ObjectLayer); if (expected.Animation is not null) { Assert.NotNull(actual.Animation); diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs index ea0575e..9a965c2 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs @@ -69,6 +69,30 @@ public partial class TestData new ObjectProperty { Name = "objectinclass", Value = 0 }, new StringProperty { Name = "stringinclass", Value = "This is a set string" } ] + }, + new EnumProperty + { + Name = "customenumstringprop", + PropertyType = "CustomEnumString", + Value = new HashSet { "CustomEnumString_2" } + }, + new EnumProperty + { + Name = "customenumstringflagsprop", + PropertyType = "CustomEnumStringFlags", + Value = new HashSet { "CustomEnumStringFlags_1", "CustomEnumStringFlags_2" } + }, + new EnumProperty + { + Name = "customenumintprop", + PropertyType = "CustomEnumInt", + Value = new HashSet { "CustomEnumInt_4" } + }, + new EnumProperty + { + Name = "customenumintflagsprop", + PropertyType = "CustomEnumIntFlags", + Value = new HashSet { "CustomEnumIntFlags_2", "CustomEnumIntFlags_3" } } ] }; @@ -116,6 +140,50 @@ public static IReadOnlyCollection MapWithCustomTypePropsC Value = "" } ] + }, + new CustomEnumDefinition + { + Name = "CustomEnumString", + StorageType = CustomEnumStorageType.String, + ValueAsFlags = false, + Values = [ + "CustomEnumString_1", + "CustomEnumString_2", + "CustomEnumString_3" + ] + }, + new CustomEnumDefinition + { + Name = "CustomEnumStringFlags", + StorageType = CustomEnumStorageType.String, + ValueAsFlags = true, + Values = [ + "CustomEnumStringFlags_1", + "CustomEnumStringFlags_2" + ] + }, + new CustomEnumDefinition + { + Name = "CustomEnumInt", + StorageType = CustomEnumStorageType.Int, + ValueAsFlags = false, + Values = [ + "CustomEnumInt_1", + "CustomEnumInt_2", + "CustomEnumInt_3", + "CustomEnumInt_4", + ] + }, + new CustomEnumDefinition + { + Name = "CustomEnumIntFlags", + StorageType = CustomEnumStorageType.Int, + ValueAsFlags = true, + Values = [ + "CustomEnumIntFlags_1", + "CustomEnumIntFlags_2", + "CustomEnumIntFlags_3" + ] } ]; } diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.tmj b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.tmj index a8c7f43..74f892b 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.tmj +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.tmj @@ -32,6 +32,30 @@ "floatinclass":13.37, "stringinclass":"This is a set string" } + }, + { + "name":"customenumintflagsprop", + "propertytype":"CustomEnumIntFlags", + "type":"int", + "value":6 + }, + { + "name":"customenumintprop", + "propertytype":"CustomEnumInt", + "type":"int", + "value":3 + }, + { + "name":"customenumstringflagsprop", + "propertytype":"CustomEnumStringFlags", + "type":"string", + "value":"CustomEnumStringFlags_1,CustomEnumStringFlags_2" + }, + { + "name":"customenumstringprop", + "propertytype":"CustomEnumString", + "type":"string", + "value":"CustomEnumString_2" }], "renderorder":"right-down", "tiledversion":"1.11.0", diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.tmx b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.tmx index c364577..cadc2fa 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.tmx +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.tmx @@ -8,6 +8,10 @@ + + + + diff --git a/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs b/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs index fb825ed..748d4e3 100644 --- a/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs @@ -20,16 +20,20 @@ public void TmxMapReaderReadMap_ValidXmlExternalTilesetsAndTemplates_ReturnsMapT Template ResolveTemplate(string source) { using var xmlTemplateReader = TestData.GetXmlReaderFor($"{fileDir}/{source}"); - using var templateReader = new TxTemplateReader(xmlTemplateReader, ResolveTileset, ResolveTemplate, customTypeDefinitions); + using var templateReader = new TxTemplateReader(xmlTemplateReader, ResolveTileset, ResolveTemplate, ResolveCustomType); return templateReader.ReadTemplate(); } Tileset ResolveTileset(string source) { using var xmlTilesetReader = TestData.GetXmlReaderFor($"{fileDir}/{source}"); - using var tilesetReader = new TsxTilesetReader(xmlTilesetReader, ResolveTemplate, customTypeDefinitions); + using var tilesetReader = new TsxTilesetReader(xmlTilesetReader, ResolveTileset, ResolveTemplate, ResolveCustomType); return tilesetReader.ReadTileset(); } - using var mapReader = new TmxMapReader(reader, ResolveTileset, ResolveTemplate, customTypeDefinitions); + ICustomTypeDefinition ResolveCustomType(string name) + { + return customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name)!; + } + using var mapReader = new TmxMapReader(reader, ResolveTileset, ResolveTemplate, ResolveCustomType); // Act var map = mapReader.ReadMap(); diff --git a/src/DotTiled/Model/Properties/EnumProperty.cs b/src/DotTiled/Model/Properties/EnumProperty.cs new file mode 100644 index 0000000..19e1b1f --- /dev/null +++ b/src/DotTiled/Model/Properties/EnumProperty.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Linq; + +namespace DotTiled.Model; + +/// +/// Represents an enum property. +/// +public class EnumProperty : IProperty> +{ + /// + public required string Name { get; set; } + + /// + public PropertyType Type => Model.PropertyType.Enum; + + /// + /// The type of the class property. This will be the name of a custom defined + /// type in Tiled. + /// + public required string PropertyType { get; set; } + + /// + /// The value of the enum property. + /// + public required ISet Value { get; set; } + + /// + public IProperty Clone() => new EnumProperty + { + Name = Name, + PropertyType = PropertyType, + Value = Value.ToHashSet() + }; + + /// + /// Determines whether the enum property is equal to the specified value. + /// For enums which have multiple values (e.g. flag enums), this method will only return true if it is the only value. + /// + /// The value to check. + /// True if the enum property is equal to the specified value; otherwise, false. + public bool IsValue(string value) => Value.Contains(value) && Value.Count == 1; + + /// + /// Determines whether the enum property has the specified value. This method is very similar to the common method. + /// + /// The value to check. + /// True if the enum property has the specified value as one of its values; otherwise, false. + public bool HasValue(string value) => Value.Contains(value); +} diff --git a/src/DotTiled/Model/Properties/PropertyType.cs b/src/DotTiled/Model/Properties/PropertyType.cs index d6057cc..451ca5e 100644 --- a/src/DotTiled/Model/Properties/PropertyType.cs +++ b/src/DotTiled/Model/Properties/PropertyType.cs @@ -43,5 +43,10 @@ public enum PropertyType /// /// A class property. /// - Class + Class, + + /// + /// An enum property. + /// + Enum } diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs b/src/DotTiled/Serialization/Tmx/Tmx.Map.cs deleted file mode 100644 index 4ce03a4..0000000 --- a/src/DotTiled/Serialization/Tmx/Tmx.Map.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Xml; -using DotTiled.Model; - -namespace DotTiled.Serialization.Tmx; - -internal partial class Tmx -{ - internal static Map ReadMap( - XmlReader reader, - Func externalTilesetResolver, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - // Attributes - var version = reader.GetRequiredAttribute("version"); - var tiledVersion = reader.GetRequiredAttribute("tiledversion"); - var @class = reader.GetOptionalAttribute("class") ?? ""; - var orientation = reader.GetRequiredAttributeEnum("orientation", s => s switch - { - "orthogonal" => MapOrientation.Orthogonal, - "isometric" => MapOrientation.Isometric, - "staggered" => MapOrientation.Staggered, - "hexagonal" => MapOrientation.Hexagonal, - _ => throw new InvalidOperationException($"Unknown orientation '{s}'") - }); - var renderOrder = reader.GetOptionalAttributeEnum("renderorder", s => s switch - { - "right-down" => RenderOrder.RightDown, - "right-up" => RenderOrder.RightUp, - "left-down" => RenderOrder.LeftDown, - "left-up" => RenderOrder.LeftUp, - _ => throw new InvalidOperationException($"Unknown render order '{s}'") - }) ?? RenderOrder.RightDown; - var compressionLevel = reader.GetOptionalAttributeParseable("compressionlevel") ?? -1; - var width = reader.GetRequiredAttributeParseable("width"); - var height = reader.GetRequiredAttributeParseable("height"); - var tileWidth = reader.GetRequiredAttributeParseable("tilewidth"); - var tileHeight = reader.GetRequiredAttributeParseable("tileheight"); - var hexSideLength = reader.GetOptionalAttributeParseable("hexsidelength"); - var staggerAxis = reader.GetOptionalAttributeEnum("staggeraxis", s => s switch - { - "x" => StaggerAxis.X, - "y" => StaggerAxis.Y, - _ => throw new InvalidOperationException($"Unknown stagger axis '{s}'") - }); - var staggerIndex = reader.GetOptionalAttributeEnum("staggerindex", s => s switch - { - "odd" => StaggerIndex.Odd, - "even" => StaggerIndex.Even, - _ => throw new InvalidOperationException($"Unknown stagger index '{s}'") - }); - var parallaxOriginX = reader.GetOptionalAttributeParseable("parallaxoriginx") ?? 0.0f; - var parallaxOriginY = reader.GetOptionalAttributeParseable("parallaxoriginy") ?? 0.0f; - var backgroundColor = reader.GetOptionalAttributeClass("backgroundcolor") ?? Color.Parse("#00000000", CultureInfo.InvariantCulture); - var nextLayerID = reader.GetRequiredAttributeParseable("nextlayerid"); - var nextObjectID = reader.GetRequiredAttributeParseable("nextobjectid"); - var infinite = (reader.GetOptionalAttributeParseable("infinite") ?? 0) == 1; - - // At most one of - List? properties = null; - - // Any number of - List layers = []; - List tilesets = []; - - reader.ProcessChildren("map", (r, elementName) => elementName switch - { - "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)), - "imagelayer" => () => layers.Add(ReadImageLayer(r, customTypeDefinitions)), - "group" => () => layers.Add(ReadGroup(r, externalTemplateResolver, customTypeDefinitions)), - _ => r.Skip - }); - - return new Map - { - Version = version, - TiledVersion = tiledVersion, - Class = @class, - Orientation = orientation, - RenderOrder = renderOrder, - CompressionLevel = compressionLevel, - Width = width, - Height = height, - TileWidth = tileWidth, - TileHeight = tileHeight, - HexSideLength = hexSideLength, - StaggerAxis = staggerAxis, - StaggerIndex = staggerIndex, - ParallaxOriginX = parallaxOriginX, - ParallaxOriginY = parallaxOriginY, - BackgroundColor = backgroundColor, - NextLayerID = nextLayerID, - NextObjectID = nextObjectID, - Infinite = infinite, - Properties = properties ?? [], - Tilesets = tilesets, - Layers = layers - }; - } -} diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs b/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs deleted file mode 100644 index 2e288a5..0000000 --- a/src/DotTiled/Serialization/Tmx/Tmx.Properties.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Xml; -using DotTiled.Model; - -namespace DotTiled.Serialization.Tmx; - -internal partial class Tmx -{ - internal static List 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 property; - }); - } - - internal static ClassProperty ReadClassProperty( - XmlReader reader, - IReadOnlyCollection customTypeDefinitions) - { - var name = reader.GetRequiredAttribute("name"); - var propertyType = reader.GetRequiredAttribute("propertytype"); - - var customTypeDef = customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == propertyType); - if (customTypeDef is CustomClassDefinition ccd) - { - reader.ReadStartElement("property"); - var propsInType = Helpers.CreateInstanceOfCustomClass(ccd); - var props = ReadProperties(reader, customTypeDefinitions); - var mergedProps = Helpers.MergeProperties(propsInType, props); - - reader.ReadEndElement(); - return new ClassProperty { Name = name, PropertyType = propertyType, Value = mergedProps }; - } - - throw new XmlException($"Unkonwn custom class definition: {propertyType}"); - } -} diff --git a/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs b/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs deleted file mode 100644 index 8605ade..0000000 --- a/src/DotTiled/Serialization/Tmx/Tmx.TileLayer.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml; -using DotTiled.Model; - -namespace DotTiled.Serialization.Tmx; - -internal partial class Tmx -{ - internal static TileLayer ReadTileLayer( - XmlReader reader, - bool dataUsesChunks, - IReadOnlyCollection customTypeDefinitions) - { - var id = reader.GetRequiredAttributeParseable("id"); - var name = reader.GetOptionalAttribute("name") ?? ""; - var @class = reader.GetOptionalAttribute("class") ?? ""; - var x = reader.GetOptionalAttributeParseable("x") ?? 0; - var y = reader.GetOptionalAttributeParseable("y") ?? 0; - var width = reader.GetRequiredAttributeParseable("width"); - var height = reader.GetRequiredAttributeParseable("height"); - var opacity = reader.GetOptionalAttributeParseable("opacity") ?? 1.0f; - var visible = reader.GetOptionalAttributeParseable("visible") ?? true; - var tintColor = reader.GetOptionalAttributeClass("tintcolor"); - var offsetX = reader.GetOptionalAttributeParseable("offsetx") ?? 0.0f; - var offsetY = reader.GetOptionalAttributeParseable("offsety") ?? 0.0f; - var parallaxX = reader.GetOptionalAttributeParseable("parallaxx") ?? 1.0f; - var parallaxY = reader.GetOptionalAttributeParseable("parallaxy") ?? 1.0f; - - List? properties = null; - Data? data = null; - - reader.ProcessChildren("layer", (r, elementName) => elementName switch - { - "data" => () => Helpers.SetAtMostOnce(ref data, ReadData(r, dataUsesChunks), "Data"), - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(r, customTypeDefinitions), "Properties"), - _ => r.Skip - }); - - return new TileLayer - { - ID = id, - Name = name, - Class = @class, - X = x, - Y = y, - Width = width, - Height = height, - Opacity = opacity, - Visible = visible, - TintColor = tintColor, - OffsetX = offsetX, - OffsetY = offsetY, - ParallaxX = parallaxX, - ParallaxY = parallaxY, - Data = data, - Properties = properties ?? [] - }; - } - - internal static ImageLayer ReadImageLayer( - XmlReader reader, - IReadOnlyCollection customTypeDefinitions) - { - var id = reader.GetRequiredAttributeParseable("id"); - var name = reader.GetOptionalAttribute("name") ?? ""; - var @class = reader.GetOptionalAttribute("class") ?? ""; - var x = reader.GetOptionalAttributeParseable("x") ?? 0; - var y = reader.GetOptionalAttributeParseable("y") ?? 0; - var opacity = reader.GetOptionalAttributeParseable("opacity") ?? 1.0f; - var visible = reader.GetOptionalAttributeParseable("visible") ?? true; - var tintColor = reader.GetOptionalAttributeClass("tintcolor"); - var offsetX = reader.GetOptionalAttributeParseable("offsetx") ?? 0.0f; - var offsetY = reader.GetOptionalAttributeParseable("offsety") ?? 0.0f; - var parallaxX = reader.GetOptionalAttributeParseable("parallaxx") ?? 1.0f; - var parallaxY = reader.GetOptionalAttributeParseable("parallaxy") ?? 1.0f; - var repeatX = (reader.GetOptionalAttributeParseable("repeatx") ?? 0) == 1; - var repeatY = (reader.GetOptionalAttributeParseable("repeaty") ?? 0) == 1; - - List? properties = null; - Image? image = null; - - reader.ProcessChildren("imagelayer", (r, elementName) => elementName switch - { - "image" => () => Helpers.SetAtMostOnce(ref image, ReadImage(r), "Image"), - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(r, customTypeDefinitions), "Properties"), - _ => r.Skip - }); - - return new ImageLayer - { - ID = id, - Name = name, - Class = @class, - X = x, - Y = y, - Opacity = opacity, - Visible = visible, - TintColor = tintColor, - OffsetX = offsetX, - OffsetY = offsetY, - ParallaxX = parallaxX, - ParallaxY = parallaxY, - Properties = properties ?? [], - Image = image, - RepeatX = repeatX, - RepeatY = repeatY - }; - } - - internal static Group ReadGroup( - XmlReader reader, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - var id = reader.GetRequiredAttributeParseable("id"); - var name = reader.GetOptionalAttribute("name") ?? ""; - var @class = reader.GetOptionalAttribute("class") ?? ""; - var opacity = reader.GetOptionalAttributeParseable("opacity") ?? 1.0f; - var visible = reader.GetOptionalAttributeParseable("visible") ?? true; - var tintColor = reader.GetOptionalAttributeClass("tintcolor"); - var offsetX = reader.GetOptionalAttributeParseable("offsetx") ?? 0.0f; - var offsetY = reader.GetOptionalAttributeParseable("offsety") ?? 0.0f; - var parallaxX = reader.GetOptionalAttributeParseable("parallaxx") ?? 1.0f; - var parallaxY = reader.GetOptionalAttributeParseable("parallaxy") ?? 1.0f; - - List? properties = null; - List layers = []; - - reader.ProcessChildren("group", (r, elementName) => elementName switch - { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(r, customTypeDefinitions), "Properties"), - "layer" => () => layers.Add(ReadTileLayer(r, false, customTypeDefinitions)), - "objectgroup" => () => layers.Add(ReadObjectLayer(r, externalTemplateResolver, customTypeDefinitions)), - "imagelayer" => () => layers.Add(ReadImageLayer(r, customTypeDefinitions)), - "group" => () => layers.Add(ReadGroup(r, externalTemplateResolver, customTypeDefinitions)), - _ => r.Skip - }); - - return new Group - { - ID = id, - Name = name, - Class = @class, - Opacity = opacity, - Visible = visible, - TintColor = tintColor, - OffsetX = offsetX, - OffsetY = offsetY, - ParallaxX = parallaxX, - ParallaxY = parallaxY, - Properties = properties ?? [], - Layers = layers - }; - } -} diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs b/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs deleted file mode 100644 index 84ccd24..0000000 --- a/src/DotTiled/Serialization/Tmx/Tmx.Tileset.cs +++ /dev/null @@ -1,350 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Xml; -using DotTiled.Model; - -namespace DotTiled.Serialization.Tmx; - -internal partial class Tmx -{ - internal static Tileset ReadTileset( - XmlReader reader, - Func? externalTilesetResolver, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - // Attributes - var version = reader.GetOptionalAttribute("version"); - var tiledVersion = reader.GetOptionalAttribute("tiledversion"); - var firstGID = reader.GetOptionalAttributeParseable("firstgid"); - var source = reader.GetOptionalAttribute("source"); - var name = reader.GetOptionalAttribute("name"); - var @class = reader.GetOptionalAttribute("class") ?? ""; - var tileWidth = reader.GetOptionalAttributeParseable("tilewidth"); - var tileHeight = reader.GetOptionalAttributeParseable("tileheight"); - var spacing = reader.GetOptionalAttributeParseable("spacing") ?? 0; - var margin = reader.GetOptionalAttributeParseable("margin") ?? 0; - var tileCount = reader.GetOptionalAttributeParseable("tilecount"); - var columns = reader.GetOptionalAttributeParseable("columns"); - var objectAlignment = reader.GetOptionalAttributeEnum("objectalignment", s => s switch - { - "unspecified" => ObjectAlignment.Unspecified, - "topleft" => ObjectAlignment.TopLeft, - "top" => ObjectAlignment.Top, - "topright" => ObjectAlignment.TopRight, - "left" => ObjectAlignment.Left, - "center" => ObjectAlignment.Center, - "right" => ObjectAlignment.Right, - "bottomleft" => ObjectAlignment.BottomLeft, - "bottom" => ObjectAlignment.Bottom, - "bottomright" => ObjectAlignment.BottomRight, - _ => throw new InvalidOperationException($"Unknown object alignment '{s}'") - }) ?? ObjectAlignment.Unspecified; - var renderSize = reader.GetOptionalAttributeEnum("rendersize", s => s switch - { - "tile" => TileRenderSize.Tile, - "grid" => TileRenderSize.Grid, - _ => throw new InvalidOperationException($"Unknown render size '{s}'") - }) ?? TileRenderSize.Tile; - var fillMode = reader.GetOptionalAttributeEnum("fillmode", s => s switch - { - "stretch" => FillMode.Stretch, - "preserve-aspect-fit" => FillMode.PreserveAspectFit, - _ => throw new InvalidOperationException($"Unknown fill mode '{s}'") - }) ?? FillMode.Stretch; - - // Elements - Image? image = null; - TileOffset? tileOffset = null; - Grid? grid = null; - List? properties = null; - List? wangsets = null; - Transformations? transformations = null; - List tiles = []; - - reader.ProcessChildren("tileset", (r, elementName) => elementName switch - { - "image" => () => Helpers.SetAtMostOnce(ref image, ReadImage(r), "Image"), - "tileoffset" => () => Helpers.SetAtMostOnce(ref tileOffset, ReadTileOffset(r), "TileOffset"), - "grid" => () => Helpers.SetAtMostOnce(ref grid, ReadGrid(r), "Grid"), - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(r, customTypeDefinitions), "Properties"), - "wangsets" => () => Helpers.SetAtMostOnce(ref wangsets, ReadWangsets(r, customTypeDefinitions), "Wangsets"), - "transformations" => () => Helpers.SetAtMostOnce(ref transformations, ReadTransformations(r), "Transformations"), - "tile" => () => tiles.Add(ReadTile(r, externalTemplateResolver, customTypeDefinitions)), - _ => r.Skip - }); - - // Check if tileset is referring to external file - if (source is not null) - { - if (externalTilesetResolver is null) - throw new InvalidOperationException("External tileset resolver is required to resolve external tilesets."); - - var resolvedTileset = externalTilesetResolver(source); - resolvedTileset.FirstGID = firstGID; - resolvedTileset.Source = source; - return resolvedTileset; - } - - return new Tileset - { - Version = version, - TiledVersion = tiledVersion, - FirstGID = firstGID, - Source = source, - Name = name, - Class = @class, - TileWidth = tileWidth, - TileHeight = tileHeight, - Spacing = spacing, - Margin = margin, - TileCount = tileCount, - Columns = columns, - ObjectAlignment = objectAlignment, - RenderSize = renderSize, - FillMode = fillMode, - Image = image, - TileOffset = tileOffset, - Grid = grid, - Properties = properties ?? [], - Wangsets = wangsets, - Transformations = transformations, - Tiles = tiles - }; - } - - internal static Image ReadImage(XmlReader reader) - { - // Attributes - var format = reader.GetOptionalAttributeEnum("format", s => s switch - { - "png" => ImageFormat.Png, - "jpg" => ImageFormat.Jpg, - "bmp" => ImageFormat.Bmp, - "gif" => ImageFormat.Gif, - _ => throw new InvalidOperationException($"Unknown image format '{s}'") - }); - var source = reader.GetOptionalAttribute("source"); - var transparentColor = reader.GetOptionalAttributeClass("trans"); - var width = reader.GetOptionalAttributeParseable("width"); - var height = reader.GetOptionalAttributeParseable("height"); - - reader.ProcessChildren("image", (r, elementName) => elementName switch - { - "data" => throw new NotSupportedException("Embedded image data is not supported."), - _ => r.Skip - }); - - if (format is null && source is not null) - format = ParseImageFormatFromSource(source); - - return new Image - { - Format = format, - Source = source, - TransparentColor = transparentColor, - Width = width, - Height = height, - }; - } - - - private static ImageFormat ParseImageFormatFromSource(string source) - { - var extension = Path.GetExtension(source).ToLowerInvariant(); - return extension switch - { - ".png" => ImageFormat.Png, - ".gif" => ImageFormat.Gif, - ".jpg" => ImageFormat.Jpg, - ".jpeg" => ImageFormat.Jpg, - ".bmp" => ImageFormat.Bmp, - _ => throw new XmlException($"Unsupported image format '{extension}'") - }; - } - - internal static TileOffset ReadTileOffset(XmlReader reader) - { - // Attributes - var x = reader.GetOptionalAttributeParseable("x") ?? 0f; - var y = reader.GetOptionalAttributeParseable("y") ?? 0f; - - reader.ReadStartElement("tileoffset"); - return new TileOffset { X = x, Y = y }; - } - - internal static Grid ReadGrid(XmlReader reader) - { - // Attributes - var orientation = reader.GetOptionalAttributeEnum("orientation", s => s switch - { - "orthogonal" => GridOrientation.Orthogonal, - "isometric" => GridOrientation.Isometric, - _ => throw new InvalidOperationException($"Unknown orientation '{s}'") - }) ?? GridOrientation.Orthogonal; - var width = reader.GetRequiredAttributeParseable("width"); - var height = reader.GetRequiredAttributeParseable("height"); - - reader.ReadStartElement("grid"); - return new Grid { Orientation = orientation, Width = width, Height = height }; - } - - internal static Transformations ReadTransformations(XmlReader reader) - { - // Attributes - var hFlip = (reader.GetOptionalAttributeParseable("hflip") ?? 0) == 1; - var vFlip = (reader.GetOptionalAttributeParseable("vflip") ?? 0) == 1; - var rotate = (reader.GetOptionalAttributeParseable("rotate") ?? 0) == 1; - var preferUntransformed = (reader.GetOptionalAttributeParseable("preferuntransformed") ?? 0) == 1; - - reader.ReadStartElement("transformations"); - return new Transformations { HFlip = hFlip, VFlip = vFlip, Rotate = rotate, PreferUntransformed = preferUntransformed }; - } - - internal static Tile ReadTile( - XmlReader reader, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - // Attributes - var id = reader.GetRequiredAttributeParseable("id"); - var type = reader.GetOptionalAttribute("type") ?? ""; - var probability = reader.GetOptionalAttributeParseable("probability") ?? 0f; - var x = reader.GetOptionalAttributeParseable("x") ?? 0; - var y = reader.GetOptionalAttributeParseable("y") ?? 0; - var width = reader.GetOptionalAttributeParseable("width"); - var height = reader.GetOptionalAttributeParseable("height"); - - // Elements - List? properties = null; - Image? image = null; - ObjectLayer? objectLayer = null; - List? animation = null; - - reader.ProcessChildren("tile", (r, elementName) => elementName switch - { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(r, customTypeDefinitions), "Properties"), - "image" => () => Helpers.SetAtMostOnce(ref image, ReadImage(r), "Image"), - "objectgroup" => () => Helpers.SetAtMostOnce(ref objectLayer, ReadObjectLayer(r, externalTemplateResolver, customTypeDefinitions), "ObjectLayer"), - "animation" => () => Helpers.SetAtMostOnce(ref animation, r.ReadList("animation", "frame", (ar) => - { - var tileID = ar.GetRequiredAttributeParseable("tileid"); - var duration = ar.GetRequiredAttributeParseable("duration"); - return new Frame { TileID = tileID, Duration = duration }; - }), "Animation"), - _ => r.Skip - }); - - return new Tile - { - ID = id, - Type = type, - Probability = probability, - X = x, - Y = y, - Width = width ?? image?.Width ?? 0, - Height = height ?? image?.Height ?? 0, - Properties = properties ?? [], - Image = image, - ObjectLayer = objectLayer, - Animation = animation - }; - } - - internal static List ReadWangsets( - XmlReader reader, - IReadOnlyCollection customTypeDefinitions) => - reader.ReadList("wangsets", "wangset", r => ReadWangset(r, customTypeDefinitions)); - - internal static Wangset ReadWangset( - XmlReader reader, - IReadOnlyCollection customTypeDefinitions) - { - // Attributes - var name = reader.GetRequiredAttribute("name"); - var @class = reader.GetOptionalAttribute("class") ?? ""; - var tile = reader.GetRequiredAttributeParseable("tile"); - - // Elements - List? properties = null; - List wangColors = []; - List wangTiles = []; - - reader.ProcessChildren("wangset", (r, elementName) => elementName switch - { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(r, customTypeDefinitions), "Properties"), - "wangcolor" => () => wangColors.Add(ReadWangColor(r, customTypeDefinitions)), - "wangtile" => () => wangTiles.Add(ReadWangTile(r)), - _ => r.Skip - }); - - if (wangColors.Count > 254) - throw new ArgumentException("Wangset can have at most 254 Wang colors."); - - return new Wangset - { - Name = name, - Class = @class, - Tile = tile, - Properties = properties ?? [], - WangColors = wangColors, - WangTiles = wangTiles - }; - } - - internal static WangColor ReadWangColor( - XmlReader reader, - IReadOnlyCollection customTypeDefinitions) - { - // Attributes - var name = reader.GetRequiredAttribute("name"); - var @class = reader.GetOptionalAttribute("class") ?? ""; - var color = reader.GetRequiredAttributeParseable("color"); - var tile = reader.GetRequiredAttributeParseable("tile"); - var probability = reader.GetOptionalAttributeParseable("probability") ?? 0f; - - // Elements - List? properties = null; - - reader.ProcessChildren("wangcolor", (r, elementName) => elementName switch - { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(r, customTypeDefinitions), "Properties"), - _ => r.Skip - }); - - return new WangColor - { - Name = name, - Class = @class, - Color = color, - Tile = tile, - Probability = probability, - Properties = properties ?? [] - }; - } - - internal static WangTile ReadWangTile(XmlReader reader) - { - // Attributes - var tileID = reader.GetRequiredAttributeParseable("tileid"); - var wangID = reader.GetRequiredAttributeParseable("wangid", s => - { - // Comma-separated list of indices (0-254) - var indices = s.Split(',').Select(i => byte.Parse(i, CultureInfo.InvariantCulture)).ToArray(); - if (indices.Length > 8) - throw new ArgumentException("Wang ID can have at most 8 indices."); - return indices; - }); - - reader.ReadStartElement("wangtile"); - - return new WangTile - { - TileID = tileID, - WangID = wangID - }; - } -} diff --git a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs index 279c83d..e90caa1 100644 --- a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs +++ b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Xml; using DotTiled.Model; @@ -8,72 +7,20 @@ namespace DotTiled.Serialization.Tmx; /// /// A map reader for the Tiled XML format. /// -public class TmxMapReader : IMapReader +public class TmxMapReader : TmxReaderBase, IMapReader { - // External resolvers - private readonly Func _externalTilesetResolver; - private readonly Func _externalTemplateResolver; - - private readonly XmlReader _reader; - private bool disposedValue; - - private readonly IReadOnlyCollection _customTypeDefinitions; - /// /// Constructs a new . /// - /// An XML reader for reading a Tiled map in the Tiled XML format. - /// A function that resolves external tilesets given their source. - /// A function that resolves external templates given their source. - /// A collection of custom type definitions that can be used to resolve custom types when encountering . - /// Thrown when any of the arguments are null. + /// public TmxMapReader( XmlReader reader, Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - _reader = reader ?? throw new ArgumentNullException(nameof(reader)); - _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); - _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); - _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); - - // Prepare reader - _ = _reader.MoveToContent(); - } - - /// - public Map ReadMap() => Tmx.ReadMap(_reader, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions); - - /// - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - // TODO: dispose managed state (managed objects) - _reader.Dispose(); - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~TmxTiledMapReader() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } + Func customTypeResolver) : base( + reader, externalTilesetResolver, externalTemplateResolver, customTypeResolver) + { } /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); - } + public new Map ReadMap() => base.ReadMap(); } diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Chunk.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Chunk.cs similarity index 59% rename from src/DotTiled/Serialization/Tmx/Tmx.Chunk.cs rename to src/DotTiled/Serialization/Tmx/TmxReaderBase.Chunk.cs index b42ebb0..73c8052 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Chunk.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Chunk.cs @@ -1,27 +1,26 @@ -using System.Xml; using DotTiled.Model; namespace DotTiled.Serialization.Tmx; -internal partial class Tmx +public abstract partial class TmxReaderBase { - internal static Chunk ReadChunk(XmlReader reader, DataEncoding? encoding, DataCompression? compression) + internal Chunk ReadChunk(DataEncoding? encoding, DataCompression? compression) { - var x = reader.GetRequiredAttributeParseable("x"); - var y = reader.GetRequiredAttributeParseable("y"); - var width = reader.GetRequiredAttributeParseable("width"); - var height = reader.GetRequiredAttributeParseable("height"); + var x = _reader.GetRequiredAttributeParseable("x"); + var y = _reader.GetRequiredAttributeParseable("y"); + var width = _reader.GetRequiredAttributeParseable("width"); + var height = _reader.GetRequiredAttributeParseable("height"); var usesTileChildrenInsteadOfRawData = encoding is null; if (usesTileChildrenInsteadOfRawData) { - var globalTileIDsWithFlippingFlags = ReadTileChildrenInWrapper("chunk", reader); + var globalTileIDsWithFlippingFlags = ReadTileChildrenInWrapper("chunk", _reader); var (globalTileIDs, flippingFlags) = ReadAndClearFlippingFlagsFromGIDs(globalTileIDsWithFlippingFlags); return new Chunk { X = x, Y = y, Width = width, Height = height, GlobalTileIDs = globalTileIDs, FlippingFlags = flippingFlags }; } else { - var globalTileIDsWithFlippingFlags = ReadRawData(reader, encoding!.Value, compression); + var globalTileIDsWithFlippingFlags = ReadRawData(_reader, encoding!.Value, compression); var (globalTileIDs, flippingFlags) = ReadAndClearFlippingFlagsFromGIDs(globalTileIDsWithFlippingFlags); return new Chunk { X = x, Y = y, Width = width, Height = height, GlobalTileIDs = globalTileIDs, FlippingFlags = flippingFlags }; } diff --git a/src/DotTiled/Serialization/Tmx/Tmx.Data.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Data.cs similarity index 88% rename from src/DotTiled/Serialization/Tmx/Tmx.Data.cs rename to src/DotTiled/Serialization/Tmx/TmxReaderBase.Data.cs index e1b6111..254c1d3 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.Data.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Data.cs @@ -8,17 +8,17 @@ namespace DotTiled.Serialization.Tmx; -internal partial class Tmx +public abstract partial class TmxReaderBase { - internal static Data ReadData(XmlReader reader, bool usesChunks) + internal Data ReadData(bool usesChunks) { - var encoding = reader.GetOptionalAttributeEnum("encoding", e => e switch + var encoding = _reader.GetOptionalAttributeEnum("encoding", e => e switch { "csv" => DataEncoding.Csv, "base64" => DataEncoding.Base64, _ => throw new XmlException("Invalid encoding") }); - var compression = reader.GetOptionalAttributeEnum("compression", c => c switch + var compression = _reader.GetOptionalAttributeEnum("compression", c => c switch { "gzip" => DataCompression.GZip, "zlib" => DataCompression.ZLib, @@ -28,8 +28,8 @@ internal static Data ReadData(XmlReader reader, bool usesChunks) if (usesChunks) { - var chunks = reader - .ReadList("data", "chunk", (r) => ReadChunk(r, encoding, compression)) + var chunks = _reader + .ReadList("data", "chunk", (r) => ReadChunk(encoding, compression)) .ToArray(); return new Data { Encoding = encoding, Compression = compression, GlobalTileIDs = null, Chunks = chunks }; } @@ -37,12 +37,12 @@ internal static Data ReadData(XmlReader reader, bool usesChunks) var usesTileChildrenInsteadOfRawData = encoding is null && compression is null; if (usesTileChildrenInsteadOfRawData) { - var tileChildrenGlobalTileIDsWithFlippingFlags = ReadTileChildrenInWrapper("data", reader); + var tileChildrenGlobalTileIDsWithFlippingFlags = ReadTileChildrenInWrapper("data", _reader); var (tileChildrenGlobalTileIDs, tileChildrenFlippingFlags) = ReadAndClearFlippingFlagsFromGIDs(tileChildrenGlobalTileIDsWithFlippingFlags); return new Data { Encoding = encoding, Compression = compression, GlobalTileIDs = tileChildrenGlobalTileIDs, FlippingFlags = tileChildrenFlippingFlags, Chunks = null }; } - var rawDataGlobalTileIDsWithFlippingFlags = ReadRawData(reader, encoding!.Value, compression); + var rawDataGlobalTileIDsWithFlippingFlags = ReadRawData(_reader, encoding!.Value, compression); var (rawDataGlobalTileIDs, rawDataFlippingFlags) = ReadAndClearFlippingFlagsFromGIDs(rawDataGlobalTileIDsWithFlippingFlags); return new Data { Encoding = encoding, Compression = compression, GlobalTileIDs = rawDataGlobalTileIDs, FlippingFlags = rawDataFlippingFlags, Chunks = null }; } diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs new file mode 100644 index 0000000..89f0c9b --- /dev/null +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using DotTiled.Model; + +namespace DotTiled.Serialization.Tmx; + +/// +/// Base class for Tiled XML format readers. +/// +public abstract partial class TmxReaderBase +{ + internal Map ReadMap() + { + // Attributes + var version = _reader.GetRequiredAttribute("version"); + var tiledVersion = _reader.GetRequiredAttribute("tiledversion"); + var @class = _reader.GetOptionalAttribute("class") ?? ""; + var orientation = _reader.GetRequiredAttributeEnum("orientation", s => s switch + { + "orthogonal" => MapOrientation.Orthogonal, + "isometric" => MapOrientation.Isometric, + "staggered" => MapOrientation.Staggered, + "hexagonal" => MapOrientation.Hexagonal, + _ => throw new InvalidOperationException($"Unknown orientation '{s}'") + }); + var renderOrder = _reader.GetOptionalAttributeEnum("renderorder", s => s switch + { + "right-down" => RenderOrder.RightDown, + "right-up" => RenderOrder.RightUp, + "left-down" => RenderOrder.LeftDown, + "left-up" => RenderOrder.LeftUp, + _ => throw new InvalidOperationException($"Unknown render order '{s}'") + }) ?? RenderOrder.RightDown; + var compressionLevel = _reader.GetOptionalAttributeParseable("compressionlevel") ?? -1; + var width = _reader.GetRequiredAttributeParseable("width"); + var height = _reader.GetRequiredAttributeParseable("height"); + var tileWidth = _reader.GetRequiredAttributeParseable("tilewidth"); + var tileHeight = _reader.GetRequiredAttributeParseable("tileheight"); + var hexSideLength = _reader.GetOptionalAttributeParseable("hexsidelength"); + var staggerAxis = _reader.GetOptionalAttributeEnum("staggeraxis", s => s switch + { + "x" => StaggerAxis.X, + "y" => StaggerAxis.Y, + _ => throw new InvalidOperationException($"Unknown stagger axis '{s}'") + }); + var staggerIndex = _reader.GetOptionalAttributeEnum("staggerindex", s => s switch + { + "odd" => StaggerIndex.Odd, + "even" => StaggerIndex.Even, + _ => throw new InvalidOperationException($"Unknown stagger index '{s}'") + }); + var parallaxOriginX = _reader.GetOptionalAttributeParseable("parallaxoriginx") ?? 0.0f; + var parallaxOriginY = _reader.GetOptionalAttributeParseable("parallaxoriginy") ?? 0.0f; + var backgroundColor = _reader.GetOptionalAttributeClass("backgroundcolor") ?? Color.Parse("#00000000", CultureInfo.InvariantCulture); + var nextLayerID = _reader.GetRequiredAttributeParseable("nextlayerid"); + var nextObjectID = _reader.GetRequiredAttributeParseable("nextobjectid"); + var infinite = (_reader.GetOptionalAttributeParseable("infinite") ?? 0) == 1; + + // At most one of + List? properties = null; + + // Any number of + List layers = []; + List tilesets = []; + + _reader.ProcessChildren("map", (r, elementName) => elementName switch + { + "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "tileset" => () => tilesets.Add(ReadTileset()), + "layer" => () => layers.Add(ReadTileLayer(infinite)), + "objectgroup" => () => layers.Add(ReadObjectLayer()), + "imagelayer" => () => layers.Add(ReadImageLayer()), + "group" => () => layers.Add(ReadGroup()), + _ => r.Skip + }); + + return new Map + { + Version = version, + TiledVersion = tiledVersion, + Class = @class, + Orientation = orientation, + RenderOrder = renderOrder, + CompressionLevel = compressionLevel, + Width = width, + Height = height, + TileWidth = tileWidth, + TileHeight = tileHeight, + HexSideLength = hexSideLength, + StaggerAxis = staggerAxis, + StaggerIndex = staggerIndex, + ParallaxOriginX = parallaxOriginX, + ParallaxOriginY = parallaxOriginY, + BackgroundColor = backgroundColor, + NextLayerID = nextLayerID, + NextObjectID = nextObjectID, + Infinite = infinite, + Properties = properties ?? [], + Tilesets = tilesets, + Layers = layers + }; + } +} diff --git a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs similarity index 58% rename from src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs rename to src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs index 2ce3ca3..a680544 100644 --- a/src/DotTiled/Serialization/Tmx/Tmx.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs @@ -3,35 +3,31 @@ using System.Globalization; using System.Linq; using System.Numerics; -using System.Xml; using DotTiled.Model; namespace DotTiled.Serialization.Tmx; -internal partial class Tmx +public abstract partial class TmxReaderBase { - internal static ObjectLayer ReadObjectLayer( - XmlReader reader, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + internal ObjectLayer ReadObjectLayer() { // Attributes - var id = reader.GetRequiredAttributeParseable("id"); - var name = reader.GetOptionalAttribute("name") ?? ""; - var @class = reader.GetOptionalAttribute("class") ?? ""; - var x = reader.GetOptionalAttributeParseable("x") ?? 0; - var y = reader.GetOptionalAttributeParseable("y") ?? 0; - var width = reader.GetOptionalAttributeParseable("width"); - var height = reader.GetOptionalAttributeParseable("height"); - var opacity = reader.GetOptionalAttributeParseable("opacity") ?? 1.0f; - var visible = reader.GetOptionalAttributeParseable("visible") ?? true; - var tintColor = reader.GetOptionalAttributeClass("tintcolor"); - var offsetX = reader.GetOptionalAttributeParseable("offsetx") ?? 0.0f; - var offsetY = reader.GetOptionalAttributeParseable("offsety") ?? 0.0f; - var parallaxX = reader.GetOptionalAttributeParseable("parallaxx") ?? 1.0f; - var parallaxY = reader.GetOptionalAttributeParseable("parallaxy") ?? 1.0f; - var color = reader.GetOptionalAttributeClass("color"); - var drawOrder = reader.GetOptionalAttributeEnum("draworder", s => s switch + var id = _reader.GetRequiredAttributeParseable("id"); + var name = _reader.GetOptionalAttribute("name") ?? ""; + var @class = _reader.GetOptionalAttribute("class") ?? ""; + var x = _reader.GetOptionalAttributeParseable("x") ?? 0; + var y = _reader.GetOptionalAttributeParseable("y") ?? 0; + var width = _reader.GetOptionalAttributeParseable("width"); + var height = _reader.GetOptionalAttributeParseable("height"); + var opacity = _reader.GetOptionalAttributeParseable("opacity") ?? 1.0f; + var visible = _reader.GetOptionalAttributeParseable("visible") ?? true; + var tintColor = _reader.GetOptionalAttributeClass("tintcolor"); + var offsetX = _reader.GetOptionalAttributeParseable("offsetx") ?? 0.0f; + var offsetY = _reader.GetOptionalAttributeParseable("offsety") ?? 0.0f; + var parallaxX = _reader.GetOptionalAttributeParseable("parallaxx") ?? 1.0f; + var parallaxY = _reader.GetOptionalAttributeParseable("parallaxy") ?? 1.0f; + var color = _reader.GetOptionalAttributeClass("color"); + var drawOrder = _reader.GetOptionalAttributeEnum("draworder", s => s switch { "topdown" => DrawOrder.TopDown, "index" => DrawOrder.Index, @@ -42,10 +38,10 @@ internal static ObjectLayer ReadObjectLayer( List? properties = null; List objects = []; - reader.ProcessChildren("objectgroup", (r, elementName) => elementName switch + _reader.ProcessChildren("objectgroup", (r, elementName) => elementName switch { - "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(r, customTypeDefinitions), "Properties"), - "object" => () => objects.Add(ReadObject(r, externalTemplateResolver, customTypeDefinitions)), + "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "object" => () => objects.Add(ReadObject()), _ => r.Skip }); @@ -72,16 +68,13 @@ internal static ObjectLayer ReadObjectLayer( }; } - internal static Model.Object ReadObject( - XmlReader reader, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + internal Model.Object ReadObject() { // Attributes - var template = reader.GetOptionalAttribute("template"); + var template = _reader.GetOptionalAttribute("template"); Model.Object? obj = null; if (template is not null) - obj = externalTemplateResolver(template).Object; + obj = _externalTemplateResolver(template).Object; uint? idDefault = obj?.ID ?? null; string nameDefault = obj?.Name ?? ""; @@ -95,30 +88,30 @@ internal static Model.Object ReadObject( bool visibleDefault = obj?.Visible ?? true; List? propertiesDefault = obj?.Properties ?? null; - var id = reader.GetOptionalAttributeParseable("id") ?? idDefault; - var name = reader.GetOptionalAttribute("name") ?? nameDefault; - var type = reader.GetOptionalAttribute("type") ?? typeDefault; - var x = reader.GetOptionalAttributeParseable("x") ?? xDefault; - var y = reader.GetOptionalAttributeParseable("y") ?? yDefault; - var width = reader.GetOptionalAttributeParseable("width") ?? widthDefault; - var height = reader.GetOptionalAttributeParseable("height") ?? heightDefault; - var rotation = reader.GetOptionalAttributeParseable("rotation") ?? rotationDefault; - var gid = reader.GetOptionalAttributeParseable("gid") ?? gidDefault; - var visible = reader.GetOptionalAttributeParseable("visible") ?? visibleDefault; + var id = _reader.GetOptionalAttributeParseable("id") ?? idDefault; + var name = _reader.GetOptionalAttribute("name") ?? nameDefault; + var type = _reader.GetOptionalAttribute("type") ?? typeDefault; + var x = _reader.GetOptionalAttributeParseable("x") ?? xDefault; + var y = _reader.GetOptionalAttributeParseable("y") ?? yDefault; + var width = _reader.GetOptionalAttributeParseable("width") ?? widthDefault; + var height = _reader.GetOptionalAttributeParseable("height") ?? heightDefault; + var rotation = _reader.GetOptionalAttributeParseable("rotation") ?? rotationDefault; + var gid = _reader.GetOptionalAttributeParseable("gid") ?? gidDefault; + var visible = _reader.GetOptionalAttributeParseable("visible") ?? visibleDefault; // Elements Model.Object? foundObject = null; int propertiesCounter = 0; List? properties = propertiesDefault; - reader.ProcessChildren("object", (r, elementName) => elementName switch + _reader.ProcessChildren("object", (r, elementName) => elementName switch { - "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"), - "polyline" => () => Helpers.SetAtMostOnce(ref foundObject, ReadPolylineObject(r), "Object marker"), - "text" => () => Helpers.SetAtMostOnce(ref foundObject, ReadTextObject(r), "Object marker"), + "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties()).ToList(), "Properties", ref propertiesCounter), + "ellipse" => () => Helpers.SetAtMostOnce(ref foundObject, ReadEllipseObject(), "Object marker"), + "point" => () => Helpers.SetAtMostOnce(ref foundObject, ReadPointObject(), "Object marker"), + "polygon" => () => Helpers.SetAtMostOnce(ref foundObject, ReadPolygonObject(), "Object marker"), + "polyline" => () => Helpers.SetAtMostOnce(ref foundObject, ReadPolylineObject(), "Object marker"), + "text" => () => Helpers.SetAtMostOnce(ref foundObject, ReadTextObject(), "Object marker"), _ => throw new InvalidOperationException($"Unknown object marker '{elementName}'") }); @@ -169,26 +162,26 @@ internal static Model.Object OverrideObject(Model.Object? obj, Model.Object foun return OverrideObject((dynamic)obj, (dynamic)foundObject); } - internal static EllipseObject ReadEllipseObject(XmlReader reader) + internal EllipseObject ReadEllipseObject() { - reader.Skip(); + _reader.Skip(); return new EllipseObject { }; } internal static EllipseObject OverrideObject(EllipseObject obj, EllipseObject _) => obj; - internal static PointObject ReadPointObject(XmlReader reader) + internal PointObject ReadPointObject() { - reader.Skip(); + _reader.Skip(); return new PointObject { }; } internal static PointObject OverrideObject(PointObject obj, PointObject _) => obj; - internal static PolygonObject ReadPolygonObject(XmlReader reader) + internal PolygonObject ReadPolygonObject() { // Attributes - var points = reader.GetRequiredAttributeParseable>("points", s => + var points = _reader.GetRequiredAttributeParseable>("points", s => { // Takes on format "x1,y1 x2,y2 x3,y3 ..." var coords = s.Split(' '); @@ -199,7 +192,7 @@ internal static PolygonObject ReadPolygonObject(XmlReader reader) }).ToList(); }); - reader.ReadStartElement("polygon"); + _reader.ReadStartElement("polygon"); return new PolygonObject { Points = points }; } @@ -209,10 +202,10 @@ internal static PolygonObject OverrideObject(PolygonObject obj, PolygonObject fo return obj; } - internal static PolylineObject ReadPolylineObject(XmlReader reader) + internal PolylineObject ReadPolylineObject() { // Attributes - var points = reader.GetRequiredAttributeParseable>("points", s => + var points = _reader.GetRequiredAttributeParseable>("points", s => { // Takes on format "x1,y1 x2,y2 x3,y3 ..." var coords = s.Split(' '); @@ -223,7 +216,7 @@ internal static PolylineObject ReadPolylineObject(XmlReader reader) }).ToList(); }); - reader.ReadStartElement("polyline"); + _reader.ReadStartElement("polyline"); return new PolylineObject { Points = points }; } @@ -233,19 +226,19 @@ internal static PolylineObject OverrideObject(PolylineObject obj, PolylineObject return obj; } - internal static TextObject ReadTextObject(XmlReader reader) + internal TextObject ReadTextObject() { // Attributes - var fontFamily = reader.GetOptionalAttribute("fontfamily") ?? "sans-serif"; - var pixelSize = reader.GetOptionalAttributeParseable("pixelsize") ?? 16; - var wrap = reader.GetOptionalAttributeParseable("wrap") ?? false; - var color = reader.GetOptionalAttributeClass("color") ?? Color.Parse("#000000", CultureInfo.InvariantCulture); - var bold = reader.GetOptionalAttributeParseable("bold") ?? false; - var italic = reader.GetOptionalAttributeParseable("italic") ?? false; - var underline = reader.GetOptionalAttributeParseable("underline") ?? false; - var strikeout = reader.GetOptionalAttributeParseable("strikeout") ?? false; - var kerning = reader.GetOptionalAttributeParseable("kerning") ?? true; - var hAlign = reader.GetOptionalAttributeEnum("halign", s => s switch + var fontFamily = _reader.GetOptionalAttribute("fontfamily") ?? "sans-serif"; + var pixelSize = _reader.GetOptionalAttributeParseable("pixelsize") ?? 16; + var wrap = _reader.GetOptionalAttributeParseable("wrap") ?? false; + var color = _reader.GetOptionalAttributeClass("color") ?? Color.Parse("#000000", CultureInfo.InvariantCulture); + var bold = _reader.GetOptionalAttributeParseable("bold") ?? false; + var italic = _reader.GetOptionalAttributeParseable("italic") ?? false; + var underline = _reader.GetOptionalAttributeParseable("underline") ?? false; + var strikeout = _reader.GetOptionalAttributeParseable("strikeout") ?? false; + var kerning = _reader.GetOptionalAttributeParseable("kerning") ?? true; + var hAlign = _reader.GetOptionalAttributeEnum("halign", s => s switch { "left" => TextHorizontalAlignment.Left, "center" => TextHorizontalAlignment.Center, @@ -253,7 +246,7 @@ internal static TextObject ReadTextObject(XmlReader reader) "justify" => TextHorizontalAlignment.Justify, _ => throw new InvalidOperationException($"Unknown horizontal alignment '{s}'") }) ?? TextHorizontalAlignment.Left; - var vAlign = reader.GetOptionalAttributeEnum("valign", s => s switch + var vAlign = _reader.GetOptionalAttributeEnum("valign", s => s switch { "top" => TextVerticalAlignment.Top, "center" => TextVerticalAlignment.Center, @@ -262,7 +255,7 @@ internal static TextObject ReadTextObject(XmlReader reader) }) ?? TextVerticalAlignment.Top; // Elements - var text = reader.ReadElementContentAsString("text", ""); + var text = _reader.ReadElementContentAsString("text", ""); return new TextObject { @@ -304,11 +297,7 @@ internal static TileObject OverrideObject(TileObject obj, TileObject foundObject return obj; } - internal static Template ReadTemplate( - XmlReader reader, - Func externalTilesetResolver, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + internal Template ReadTemplate() { // No attributes @@ -318,10 +307,10 @@ internal static Template ReadTemplate( // Should contain exactly one of Model.Object? obj = null; - reader.ProcessChildren("template", (r, elementName) => elementName switch + _reader.ProcessChildren("template", (r, elementName) => elementName switch { - "tileset" => () => Helpers.SetAtMostOnce(ref tileset, ReadTileset(r, externalTilesetResolver, externalTemplateResolver, customTypeDefinitions), "Tileset"), - "object" => () => Helpers.SetAtMostOnce(ref obj, ReadObject(r, externalTemplateResolver, customTypeDefinitions), "Object"), + "tileset" => () => Helpers.SetAtMostOnce(ref tileset, ReadTileset(), "Tileset"), + "object" => () => Helpers.SetAtMostOnce(ref obj, ReadObject(), "Object"), _ => r.Skip }); diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs new file mode 100644 index 0000000..1335d75 --- /dev/null +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs @@ -0,0 +1,140 @@ +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using DotTiled.Model; + +namespace DotTiled.Serialization.Tmx; + +public abstract partial class TmxReaderBase +{ + internal List ReadProperties() + { + 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; + var propertyType = r.GetOptionalAttribute("propertytype"); + if (propertyType is not null) + { + return ReadPropertyWithCustomType(); + } + + 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(), + _ => throw new XmlException("Invalid property type") + }; + return property; + }); + } + + internal IProperty ReadPropertyWithCustomType() + { + var isClass = _reader.GetOptionalAttribute("type") == "class"; + + if (isClass) + { + return ReadClassProperty(); + } + + return ReadEnumProperty(); + } + + internal ClassProperty ReadClassProperty() + { + var name = _reader.GetRequiredAttribute("name"); + var propertyType = _reader.GetRequiredAttribute("propertytype"); + + var customTypeDef = _customTypeResolver(propertyType); + if (customTypeDef is CustomClassDefinition ccd) + { + _reader.ReadStartElement("property"); + var propsInType = Helpers.CreateInstanceOfCustomClass(ccd); + var props = ReadProperties(); + var mergedProps = Helpers.MergeProperties(propsInType, props); + + _reader.ReadEndElement(); + return new ClassProperty { Name = name, PropertyType = propertyType, Value = mergedProps }; + } + + throw new XmlException($"Unkonwn custom class definition: {propertyType}"); + } + + internal EnumProperty ReadEnumProperty() + { + var name = _reader.GetRequiredAttribute("name"); + var propertyType = _reader.GetRequiredAttribute("propertytype"); + var typeInXml = _reader.GetOptionalAttributeEnum("type", (s) => s switch + { + "string" => PropertyType.String, + "int" => PropertyType.Int, + _ => throw new XmlException("Invalid property type") + }) ?? PropertyType.String; + var customTypeDef = _customTypeResolver(propertyType); + + if (customTypeDef is not CustomEnumDefinition ced) + throw new XmlException($"Unknown custom enum definition: {propertyType}. Enums must be defined"); + + if (ced.StorageType == CustomEnumStorageType.String) + { + var value = _reader.GetRequiredAttribute("value"); + if (value.Contains(',') && !ced.ValueAsFlags) + throw new XmlException("Enum value must not contain ',' if not ValueAsFlags is set to true."); + + if (ced.ValueAsFlags) + { + var values = value.Split(',').Select(v => v.Trim()).ToHashSet(); + return new EnumProperty { Name = name, PropertyType = propertyType, Value = values }; + } + else + { + return new EnumProperty { Name = name, PropertyType = propertyType, Value = new HashSet { value } }; + } + } + else if (ced.StorageType == CustomEnumStorageType.Int) + { + var value = _reader.GetRequiredAttributeParseable("value"); + if (ced.ValueAsFlags) + { + var allValues = ced.Values; + var enumValues = new HashSet(); + for (var i = 0; i < allValues.Count; i++) + { + var mask = 1 << i; + if ((value & mask) == mask) + { + var enumValue = allValues[i]; + _ = enumValues.Add(enumValue); + } + } + return new EnumProperty { Name = name, PropertyType = propertyType, Value = enumValues }; + } + else + { + var allValues = ced.Values; + var enumValue = allValues[value]; + return new EnumProperty { Name = name, PropertyType = propertyType, Value = new HashSet { enumValue } }; + } + } + + throw new XmlException($"Unknown custom enum storage type: {ced.StorageType}"); + } +} diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs new file mode 100644 index 0000000..f69a739 --- /dev/null +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs @@ -0,0 +1,147 @@ +using System.Collections.Generic; +using System.Linq; +using DotTiled.Model; + +namespace DotTiled.Serialization.Tmx; + +public abstract partial class TmxReaderBase +{ + internal TileLayer ReadTileLayer(bool dataUsesChunks) + { + var id = _reader.GetRequiredAttributeParseable("id"); + var name = _reader.GetOptionalAttribute("name") ?? ""; + var @class = _reader.GetOptionalAttribute("class") ?? ""; + var x = _reader.GetOptionalAttributeParseable("x") ?? 0; + var y = _reader.GetOptionalAttributeParseable("y") ?? 0; + var width = _reader.GetRequiredAttributeParseable("width"); + var height = _reader.GetRequiredAttributeParseable("height"); + var opacity = _reader.GetOptionalAttributeParseable("opacity") ?? 1.0f; + var visible = _reader.GetOptionalAttributeParseable("visible") ?? true; + var tintColor = _reader.GetOptionalAttributeClass("tintcolor"); + var offsetX = _reader.GetOptionalAttributeParseable("offsetx") ?? 0.0f; + var offsetY = _reader.GetOptionalAttributeParseable("offsety") ?? 0.0f; + var parallaxX = _reader.GetOptionalAttributeParseable("parallaxx") ?? 1.0f; + var parallaxY = _reader.GetOptionalAttributeParseable("parallaxy") ?? 1.0f; + + List? properties = null; + 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"), + _ => r.Skip + }); + + return new TileLayer + { + ID = id, + Name = name, + Class = @class, + X = x, + Y = y, + Width = width, + Height = height, + Opacity = opacity, + Visible = visible, + TintColor = tintColor, + OffsetX = offsetX, + OffsetY = offsetY, + ParallaxX = parallaxX, + ParallaxY = parallaxY, + Data = data, + Properties = properties ?? [] + }; + } + + internal ImageLayer ReadImageLayer() + { + var id = _reader.GetRequiredAttributeParseable("id"); + var name = _reader.GetOptionalAttribute("name") ?? ""; + var @class = _reader.GetOptionalAttribute("class") ?? ""; + var x = _reader.GetOptionalAttributeParseable("x") ?? 0; + var y = _reader.GetOptionalAttributeParseable("y") ?? 0; + var opacity = _reader.GetOptionalAttributeParseable("opacity") ?? 1.0f; + var visible = _reader.GetOptionalAttributeParseable("visible") ?? true; + var tintColor = _reader.GetOptionalAttributeClass("tintcolor"); + var offsetX = _reader.GetOptionalAttributeParseable("offsetx") ?? 0.0f; + var offsetY = _reader.GetOptionalAttributeParseable("offsety") ?? 0.0f; + var parallaxX = _reader.GetOptionalAttributeParseable("parallaxx") ?? 1.0f; + var parallaxY = _reader.GetOptionalAttributeParseable("parallaxy") ?? 1.0f; + var repeatX = (_reader.GetOptionalAttributeParseable("repeatx") ?? 0) == 1; + var repeatY = (_reader.GetOptionalAttributeParseable("repeaty") ?? 0) == 1; + + List? properties = null; + Image? image = null; + + _reader.ProcessChildren("imagelayer", (r, elementName) => elementName switch + { + "image" => () => Helpers.SetAtMostOnce(ref image, ReadImage(), "Image"), + "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + _ => r.Skip + }); + + return new ImageLayer + { + ID = id, + Name = name, + Class = @class, + X = x, + Y = y, + Opacity = opacity, + Visible = visible, + TintColor = tintColor, + OffsetX = offsetX, + OffsetY = offsetY, + ParallaxX = parallaxX, + ParallaxY = parallaxY, + Properties = properties ?? [], + Image = image, + RepeatX = repeatX, + RepeatY = repeatY + }; + } + + internal Group ReadGroup() + { + var id = _reader.GetRequiredAttributeParseable("id"); + var name = _reader.GetOptionalAttribute("name") ?? ""; + var @class = _reader.GetOptionalAttribute("class") ?? ""; + var opacity = _reader.GetOptionalAttributeParseable("opacity") ?? 1.0f; + var visible = _reader.GetOptionalAttributeParseable("visible") ?? true; + var tintColor = _reader.GetOptionalAttributeClass("tintcolor"); + var offsetX = _reader.GetOptionalAttributeParseable("offsetx") ?? 0.0f; + var offsetY = _reader.GetOptionalAttributeParseable("offsety") ?? 0.0f; + var parallaxX = _reader.GetOptionalAttributeParseable("parallaxx") ?? 1.0f; + var parallaxY = _reader.GetOptionalAttributeParseable("parallaxy") ?? 1.0f; + + List? properties = null; + List layers = []; + + _reader.ProcessChildren("group", (r, elementName) => elementName switch + { + "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "layer" => () => layers.Add(ReadTileLayer(false)), + "objectgroup" => () => layers.Add(ReadObjectLayer()), + "imagelayer" => () => layers.Add(ReadImageLayer()), + "group" => () => layers.Add(ReadGroup()), + _ => r.Skip + }); + + return new Group + { + ID = id, + Name = name, + Class = @class, + Opacity = opacity, + Visible = visible, + TintColor = tintColor, + OffsetX = offsetX, + OffsetY = offsetY, + ParallaxX = parallaxX, + ParallaxY = parallaxY, + Properties = properties ?? [], + Layers = layers + }; + } +} diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs new file mode 100644 index 0000000..72e66e9 --- /dev/null +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs @@ -0,0 +1,317 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using DotTiled.Model; + +namespace DotTiled.Serialization.Tmx; + +public abstract partial class TmxReaderBase +{ + internal Tileset ReadTileset() + { + // Attributes + var version = _reader.GetOptionalAttribute("version"); + var tiledVersion = _reader.GetOptionalAttribute("tiledversion"); + var firstGID = _reader.GetOptionalAttributeParseable("firstgid"); + var source = _reader.GetOptionalAttribute("source"); + var name = _reader.GetOptionalAttribute("name"); + var @class = _reader.GetOptionalAttribute("class") ?? ""; + var tileWidth = _reader.GetOptionalAttributeParseable("tilewidth"); + var tileHeight = _reader.GetOptionalAttributeParseable("tileheight"); + var spacing = _reader.GetOptionalAttributeParseable("spacing") ?? 0; + var margin = _reader.GetOptionalAttributeParseable("margin") ?? 0; + var tileCount = _reader.GetOptionalAttributeParseable("tilecount"); + var columns = _reader.GetOptionalAttributeParseable("columns"); + var objectAlignment = _reader.GetOptionalAttributeEnum("objectalignment", s => s switch + { + "unspecified" => ObjectAlignment.Unspecified, + "topleft" => ObjectAlignment.TopLeft, + "top" => ObjectAlignment.Top, + "topright" => ObjectAlignment.TopRight, + "left" => ObjectAlignment.Left, + "center" => ObjectAlignment.Center, + "right" => ObjectAlignment.Right, + "bottomleft" => ObjectAlignment.BottomLeft, + "bottom" => ObjectAlignment.Bottom, + "bottomright" => ObjectAlignment.BottomRight, + _ => throw new InvalidOperationException($"Unknown object alignment '{s}'") + }) ?? ObjectAlignment.Unspecified; + var renderSize = _reader.GetOptionalAttributeEnum("rendersize", s => s switch + { + "tile" => TileRenderSize.Tile, + "grid" => TileRenderSize.Grid, + _ => throw new InvalidOperationException($"Unknown render size '{s}'") + }) ?? TileRenderSize.Tile; + var fillMode = _reader.GetOptionalAttributeEnum("fillmode", s => s switch + { + "stretch" => FillMode.Stretch, + "preserve-aspect-fit" => FillMode.PreserveAspectFit, + _ => throw new InvalidOperationException($"Unknown fill mode '{s}'") + }) ?? FillMode.Stretch; + + // Elements + Image? image = null; + TileOffset? tileOffset = null; + Grid? grid = null; + List? properties = null; + List? wangsets = null; + Transformations? transformations = null; + List tiles = []; + + _reader.ProcessChildren("tileset", (r, elementName) => elementName switch + { + "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"), + "wangsets" => () => Helpers.SetAtMostOnce(ref wangsets, ReadWangsets(), "Wangsets"), + "transformations" => () => Helpers.SetAtMostOnce(ref transformations, ReadTransformations(), "Transformations"), + "tile" => () => tiles.Add(ReadTile()), + _ => r.Skip + }); + + // Check if tileset is referring to external file + if (source is not null) + { + var resolvedTileset = _externalTilesetResolver(source); + resolvedTileset.FirstGID = firstGID; + resolvedTileset.Source = source; + return resolvedTileset; + } + + return new Tileset + { + Version = version, + TiledVersion = tiledVersion, + FirstGID = firstGID, + Source = source, + Name = name, + Class = @class, + TileWidth = tileWidth, + TileHeight = tileHeight, + Spacing = spacing, + Margin = margin, + TileCount = tileCount, + Columns = columns, + ObjectAlignment = objectAlignment, + RenderSize = renderSize, + FillMode = fillMode, + Image = image, + TileOffset = tileOffset, + Grid = grid, + Properties = properties ?? [], + Wangsets = wangsets, + Transformations = transformations, + Tiles = tiles + }; + } + + internal Image ReadImage() + { + // Attributes + var format = _reader.GetOptionalAttributeEnum("format", s => s switch + { + "png" => ImageFormat.Png, + "jpg" => ImageFormat.Jpg, + "bmp" => ImageFormat.Bmp, + "gif" => ImageFormat.Gif, + _ => throw new InvalidOperationException($"Unknown image format '{s}'") + }); + var source = _reader.GetOptionalAttribute("source"); + var transparentColor = _reader.GetOptionalAttributeClass("trans"); + var width = _reader.GetOptionalAttributeParseable("width"); + var height = _reader.GetOptionalAttributeParseable("height"); + + _reader.ProcessChildren("image", (r, elementName) => elementName switch + { + "data" => throw new NotSupportedException("Embedded image data is not supported."), + _ => r.Skip + }); + + if (format is null && source is not null) + format = Helpers.ParseImageFormatFromSource(source); + + return new Image + { + Format = format, + Source = source, + TransparentColor = transparentColor, + Width = width, + Height = height, + }; + } + + internal TileOffset ReadTileOffset() + { + // Attributes + var x = _reader.GetOptionalAttributeParseable("x") ?? 0f; + var y = _reader.GetOptionalAttributeParseable("y") ?? 0f; + + _reader.ReadStartElement("tileoffset"); + return new TileOffset { X = x, Y = y }; + } + + internal Grid ReadGrid() + { + // Attributes + var orientation = _reader.GetOptionalAttributeEnum("orientation", s => s switch + { + "orthogonal" => GridOrientation.Orthogonal, + "isometric" => GridOrientation.Isometric, + _ => throw new InvalidOperationException($"Unknown orientation '{s}'") + }) ?? GridOrientation.Orthogonal; + var width = _reader.GetRequiredAttributeParseable("width"); + var height = _reader.GetRequiredAttributeParseable("height"); + + _reader.ReadStartElement("grid"); + return new Grid { Orientation = orientation, Width = width, Height = height }; + } + + internal Transformations ReadTransformations() + { + // Attributes + var hFlip = (_reader.GetOptionalAttributeParseable("hflip") ?? 0) == 1; + var vFlip = (_reader.GetOptionalAttributeParseable("vflip") ?? 0) == 1; + var rotate = (_reader.GetOptionalAttributeParseable("rotate") ?? 0) == 1; + var preferUntransformed = (_reader.GetOptionalAttributeParseable("preferuntransformed") ?? 0) == 1; + + _reader.ReadStartElement("transformations"); + return new Transformations { HFlip = hFlip, VFlip = vFlip, Rotate = rotate, PreferUntransformed = preferUntransformed }; + } + + internal Tile ReadTile() + { + // Attributes + var id = _reader.GetRequiredAttributeParseable("id"); + var type = _reader.GetOptionalAttribute("type") ?? ""; + var probability = _reader.GetOptionalAttributeParseable("probability") ?? 0f; + var x = _reader.GetOptionalAttributeParseable("x") ?? 0; + var y = _reader.GetOptionalAttributeParseable("y") ?? 0; + var width = _reader.GetOptionalAttributeParseable("width"); + var height = _reader.GetOptionalAttributeParseable("height"); + + // Elements + List? properties = null; + Image? image = null; + ObjectLayer? objectLayer = null; + List? animation = null; + + _reader.ProcessChildren("tile", (r, elementName) => elementName switch + { + "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "image" => () => Helpers.SetAtMostOnce(ref image, ReadImage(), "Image"), + "objectgroup" => () => Helpers.SetAtMostOnce(ref objectLayer, ReadObjectLayer(), "ObjectLayer"), + "animation" => () => Helpers.SetAtMostOnce(ref animation, r.ReadList("animation", "frame", (ar) => + { + var tileID = ar.GetRequiredAttributeParseable("tileid"); + var duration = ar.GetRequiredAttributeParseable("duration"); + return new Frame { TileID = tileID, Duration = duration }; + }), "Animation"), + _ => r.Skip + }); + + return new Tile + { + ID = id, + Type = type, + Probability = probability, + X = x, + Y = y, + Width = width ?? image?.Width ?? 0, + Height = height ?? image?.Height ?? 0, + Properties = properties ?? [], + Image = image, + ObjectLayer = objectLayer, + Animation = animation + }; + } + + internal List ReadWangsets() => + _reader.ReadList("wangsets", "wangset", r => ReadWangset()); + + internal Wangset ReadWangset() + { + // Attributes + var name = _reader.GetRequiredAttribute("name"); + var @class = _reader.GetOptionalAttribute("class") ?? ""; + var tile = _reader.GetRequiredAttributeParseable("tile"); + + // Elements + List? properties = null; + List wangColors = []; + List wangTiles = []; + + _reader.ProcessChildren("wangset", (r, elementName) => elementName switch + { + "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + "wangcolor" => () => wangColors.Add(ReadWangColor()), + "wangtile" => () => wangTiles.Add(ReadWangTile()), + _ => r.Skip + }); + + if (wangColors.Count > 254) + throw new ArgumentException("Wangset can have at most 254 Wang colors."); + + return new Wangset + { + Name = name, + Class = @class, + Tile = tile, + Properties = properties ?? [], + WangColors = wangColors, + WangTiles = wangTiles + }; + } + + internal WangColor ReadWangColor() + { + // Attributes + var name = _reader.GetRequiredAttribute("name"); + var @class = _reader.GetOptionalAttribute("class") ?? ""; + var color = _reader.GetRequiredAttributeParseable("color"); + var tile = _reader.GetRequiredAttributeParseable("tile"); + var probability = _reader.GetOptionalAttributeParseable("probability") ?? 0f; + + // Elements + List? properties = null; + + _reader.ProcessChildren("wangcolor", (r, elementName) => elementName switch + { + "properties" => () => Helpers.SetAtMostOnce(ref properties, ReadProperties(), "Properties"), + _ => r.Skip + }); + + return new WangColor + { + Name = name, + Class = @class, + Color = color, + Tile = tile, + Probability = probability, + Properties = properties ?? [] + }; + } + + internal WangTile ReadWangTile() + { + // Attributes + var tileID = _reader.GetRequiredAttributeParseable("tileid"); + var wangID = _reader.GetRequiredAttributeParseable("wangid", s => + { + // Comma-separated list of indices (0-254) + var indices = s.Split(',').Select(i => byte.Parse(i, CultureInfo.InvariantCulture)).ToArray(); + if (indices.Length > 8) + throw new ArgumentException("Wang ID can have at most 8 indices."); + return indices; + }); + + _reader.ReadStartElement("wangtile"); + + return new WangTile + { + TileID = tileID, + WangID = wangID + }; + } +} diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.cs new file mode 100644 index 0000000..5851d76 --- /dev/null +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.cs @@ -0,0 +1,74 @@ +using System; +using System.Xml; +using DotTiled.Model; + +namespace DotTiled.Serialization.Tmx; + +/// +/// Base class for Tiled XML format readers. +/// +public abstract partial class TmxReaderBase : IDisposable +{ + // External resolvers + private readonly Func _externalTilesetResolver; + private readonly Func _externalTemplateResolver; + private readonly Func _customTypeResolver; + + private readonly XmlReader _reader; + private bool disposedValue; + + /// + /// Constructs a new , which is the base class for all Tiled XML format readers. + /// + /// An XML reader for reading a Tiled map in the Tiled XML format. + /// A function that resolves external tilesets given their source. + /// A function that resolves external templates given their source. + /// A function that resolves custom types given their source. + /// Thrown when any of the arguments are null. + protected TmxReaderBase( + XmlReader reader, + Func externalTilesetResolver, + Func externalTemplateResolver, + Func customTypeResolver) + { + _reader = reader ?? throw new ArgumentNullException(nameof(reader)); + _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); + _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); + _customTypeResolver = customTypeResolver ?? throw new ArgumentNullException(nameof(customTypeResolver)); + + // Prepare reader + _ = _reader.MoveToContent(); + } + + /// + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: dispose managed state (managed objects) + _reader.Dispose(); + } + + // TODO: free unmanaged resources (unmanaged objects) and override finalizer + // TODO: set large fields to null + disposedValue = true; + } + } + + // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources + // ~TmxReaderBase() + // { + // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + // Dispose(disposing: false); + // } + + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } +} diff --git a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs index 0b69d4c..176872b 100644 --- a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Xml; using DotTiled.Model; @@ -8,68 +7,20 @@ namespace DotTiled.Serialization.Tmx; /// /// A tileset reader for the Tiled XML format. /// -public class TsxTilesetReader : ITilesetReader +public class TsxTilesetReader : TmxReaderBase, ITilesetReader { - // External resolvers - private readonly Func _externalTemplateResolver; - - private readonly XmlReader _reader; - private bool disposedValue; - - private readonly IReadOnlyCollection _customTypeDefinitions; - /// /// Constructs a new . /// - /// An XML reader for reading a Tiled tileset in the Tiled XML format. - /// A function that resolves external templates given their source. - /// A collection of custom type definitions that can be used to resolve custom types when encountering . - /// Thrown when any of the arguments are null. + /// public TsxTilesetReader( XmlReader reader, + Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - _reader = reader ?? throw new ArgumentNullException(nameof(reader)); - _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); - _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); - - // Prepare reader - _ = _reader.MoveToContent(); - } - - /// - public Tileset ReadTileset() => Tmx.ReadTileset(_reader, null, _externalTemplateResolver, _customTypeDefinitions); - - /// - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - // TODO: dispose managed state (managed objects) - _reader.Dispose(); - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~TsxTilesetReader() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } + Func customTypeResolver) : base( + reader, externalTilesetResolver, externalTemplateResolver, customTypeResolver) + { } /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); - } + public new Tileset ReadTileset() => base.ReadTileset(); } diff --git a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs index ed7ba8e..1ff8445 100644 --- a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs +++ b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Xml; using DotTiled.Model; @@ -8,72 +7,20 @@ namespace DotTiled.Serialization.Tmx; /// /// A template reader for the Tiled XML format. /// -public class TxTemplateReader : ITemplateReader +public class TxTemplateReader : TmxReaderBase, ITemplateReader { - // Resolvers - private readonly Func _externalTilesetResolver; - private readonly Func _externalTemplateResolver; - - private readonly XmlReader _reader; - private bool disposedValue; - - private readonly IReadOnlyCollection _customTypeDefinitions; - /// /// Constructs a new . /// - /// An XML reader for reading a Tiled template in the Tiled XML format. - /// A function that resolves external tilesets given their source. - /// A function that resolves external templates given their source. - /// A collection of custom type definitions that can be used to resolve custom types when encountering . - /// Thrown when any of the arguments are null. + /// public TxTemplateReader( XmlReader reader, Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - _reader = reader ?? throw new ArgumentNullException(nameof(reader)); - _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); - _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); - _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); - - // Prepare reader - _ = _reader.MoveToContent(); - } - - /// - public Template ReadTemplate() => Tmx.ReadTemplate(_reader, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions); - - /// - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - // TODO: dispose managed state (managed objects) - _reader.Dispose(); - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~TxTemplateReader() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } + Func customTypeResolver) : base( + reader, externalTilesetResolver, externalTemplateResolver, customTypeResolver) + { } /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); - } + public new Template ReadTemplate() => base.ReadTemplate(); } From ab8173bb06f4230a4e09aa672ea18419e04dd76c Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Mon, 26 Aug 2024 21:36:44 +0200 Subject: [PATCH 16/23] Tmj reader is now base class and new properties docs --- Makefile | 6 +- ...ing-properties.md => custom-properties.md} | 72 ++++++-- docs/docs/toc.yml | 2 +- docs/images/entity-type-enum.png | Bin 0 -> 11906 bytes src/DotTiled.Benchmark/Program.cs | 2 +- src/DotTiled.Tests/Serialization/TestData.cs | 1 + .../map-with-deep-props.cs | 161 ++++++++++++++++ .../map-with-deep-props.tmj | 55 ++++++ .../map-with-deep-props.tmx | 25 +++ .../Serialization/Tmj/TmjMapReaderTests.cs | 10 +- src/DotTiled/Serialization/Helpers.cs | 21 ++- .../Serialization/Tmj/TjTemplateReader.cs | 64 +------ src/DotTiled/Serialization/Tmj/Tmj.Layer.cs | 26 --- .../Serialization/Tmj/Tmj.Properties.cs | 103 ----------- .../Serialization/Tmj/Tmj.Template.cs | 26 --- .../Serialization/Tmj/TmjMapReader.cs | 63 +------ .../{Tmj.Data.cs => TmjReaderBase.Data.cs} | 2 +- .../{Tmj.Group.cs => TmjReaderBase.Group.cs} | 12 +- ...geLayer.cs => TmjReaderBase.ImageLayer.cs} | 9 +- .../Serialization/Tmj/TmjReaderBase.Layer.cs | 21 +++ .../Tmj/{Tmj.Map.cs => TmjReaderBase.Map.cs} | 15 +- ...tLayer.cs => TmjReaderBase.ObjectLayer.cs} | 21 +-- .../Tmj/TmjReaderBase.Properties.cs | 174 ++++++++++++++++++ .../Tmj/TmjReaderBase.Template.cs | 20 ++ ...ileLayer.cs => TmjReaderBase.TileLayer.cs} | 9 +- ...mj.Tileset.cs => TmjReaderBase.Tileset.cs} | 43 ++--- .../Serialization/Tmj/TmjReaderBase.cs | 74 ++++++++ .../Serialization/Tmj/TsjTilesetReader.cs | 68 +------ .../Tmx/TmxReaderBase.Properties.cs | 30 ++- 29 files changed, 702 insertions(+), 433 deletions(-) rename docs/docs/{accessing-properties.md => custom-properties.md} (59%) create mode 100644 docs/images/entity-type-enum.png create mode 100644 src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.cs create mode 100644 src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.tmj create mode 100644 src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.tmx delete mode 100644 src/DotTiled/Serialization/Tmj/Tmj.Layer.cs delete mode 100644 src/DotTiled/Serialization/Tmj/Tmj.Properties.cs delete mode 100644 src/DotTiled/Serialization/Tmj/Tmj.Template.cs rename src/DotTiled/Serialization/Tmj/{Tmj.Data.cs => TmjReaderBase.Data.cs} (98%) rename src/DotTiled/Serialization/Tmj/{Tmj.Group.cs => TmjReaderBase.Group.cs} (77%) rename src/DotTiled/Serialization/Tmj/{Tmj.ImageLayer.cs => TmjReaderBase.ImageLayer.cs} (88%) create mode 100644 src/DotTiled/Serialization/Tmj/TmjReaderBase.Layer.cs rename src/DotTiled/Serialization/Tmj/{Tmj.Map.cs => TmjReaderBase.Map.cs} (88%) rename src/DotTiled/Serialization/Tmj/{Tmj.ObjectLayer.cs => TmjReaderBase.ObjectLayer.cs} (93%) create mode 100644 src/DotTiled/Serialization/Tmj/TmjReaderBase.Properties.cs create mode 100644 src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs rename src/DotTiled/Serialization/Tmj/{Tmj.TileLayer.cs => TmjReaderBase.TileLayer.cs} (91%) rename src/DotTiled/Serialization/Tmj/{Tmj.Tileset.cs => TmjReaderBase.Tileset.cs} (86%) create mode 100644 src/DotTiled/Serialization/Tmj/TmjReaderBase.cs diff --git a/Makefile b/Makefile index 9b64573..14a40ab 100644 --- a/Makefile +++ b/Makefile @@ -13,10 +13,10 @@ lint: dotnet format style --verify-no-changes src/DotTiled.sln dotnet format analyzers --verify-no-changes src/DotTiled.sln -BENCHMARK_SOURCES = DotTiled.Benchmark/Program.cs DotTiled.Benchmark/DotTiled.Benchmark.csproj -BENCHMARK_OUTPUTDIR = DotTiled.Benchmark/BenchmarkDotNet.Artifacts +BENCHMARK_SOURCES = src/DotTiled.Benchmark/Program.cs src/DotTiled.Benchmark/DotTiled.Benchmark.csproj +BENCHMARK_OUTPUTDIR = src/DotTiled.Benchmark/BenchmarkDotNet.Artifacts .PHONY: benchmark benchmark: $(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md $(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md: $(BENCHMARK_SOURCES) - dotnet run --project DotTiled.Benchmark/DotTiled.Benchmark.csproj -c Release -- $(BENCHMARK_OUTPUTDIR) \ No newline at end of file + dotnet run --project src/DotTiled.Benchmark/DotTiled.Benchmark.csproj -c Release -- $(BENCHMARK_OUTPUTDIR) \ No newline at end of file diff --git a/docs/docs/accessing-properties.md b/docs/docs/custom-properties.md similarity index 59% rename from docs/docs/accessing-properties.md rename to docs/docs/custom-properties.md index 59fcfea..78cbd00 100644 --- a/docs/docs/accessing-properties.md +++ b/docs/docs/custom-properties.md @@ -1,4 +1,4 @@ -# Accessing properties +# Custom properties [Tiled facilitates a very flexible way to store custom data in your maps using properties](https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-properties). Accessing these properties is a common task when working with Tiled maps in your game since it will allow you to fully utilize the strengths of Tiled, such as customizing the behavior of your game objects or setting up the initial state of your game world. @@ -66,15 +66,15 @@ Tiled supports a variety of property types, which are represented in the DotTile - `object` - - `string` - -In addition to these primitive property types, [Tiled also supports more complex property types](https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-types). These custom property types are defined in Tiled according to the linked documentation, and to work with them in DotTiled, you *must* define their equivalences as a collection of . This collection of definitions shall then be passed to the corresponding reader when loading a map, tileset, or template. +In addition to these primitive property types, [Tiled also supports more complex property types](https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-types). These custom property types are defined in Tiled according to the linked documentation, and to work with them in DotTiled, you *must* define their equivalences as a . You must then provide a resolving function to a defined type given a custom type name, as it is defined in Tiled. -Whenever DotTiled encounters a property that is of type `class` in a Tiled file, it will attempt to find the corresponding definition, and if it does not find one, it will throw an exception. However, if it does find the definition, it will use that definition to know the default values of the properties of that class, and then override those defaults with the values found in the Tiled file when populating a instance. More information about these `class` properties can be found in [the next section](#class-properties). +## Custom types -Finally, Tiled also allows you to define custom property types that work as enums. These custom property types are just parsed and retrieved as their corresponding storage type. So for a custom property type that is defined as an enum where the values are stored as strings, DotTiled will just parse those as . Similarly, if the values are stored as integers, DotTiled will parse those as . +Tiled allows you to define custom property types that can be used in your maps. These custom property types can be of type `class` or `enum`. DotTiled supports custom property types by allowing you to define the equivalent in C# and then providing a custom type resolver function that will return the equivalent definition given a custom type name. -## Class properties +### Class properties -As mentioned, Tiled supports `class` properties which allow you to create hierarchical structures of properties. DotTiled supports this feature through the class. For all your custom `class` types in Tiled, you must create an equivalent and pass it to the corresponding reader when loading a map, tileset, or template. +Whenever DotTiled encounters a property that is of type `class` in a Tiled file, it will use the supplied custom type resolver function to retrieve the custom type definition. It will then use that definition to know the default values of the properties of that class, and then override those defaults with the values found in the Tiled file when populating a instance. `class` properties allow you to create hierarchical structures of properties. For example, if you have a `class` property in Tiled that looks like this: @@ -96,16 +96,66 @@ var monsterSpawnerDefinition = new CustomClassDefinition }; ``` -### Resolve object types and properties automatically +### Enum properties -If you don't want to have to rely on creating an equivalent definition for every `class` property that you may be using in your Tiled maps, you can check the `Resolve object types and properties` checkbox in `Edit > Preferences > General | Export Options` in Tiled. +Tiled also allows you to define custom property types that work as enums. Similarly to `class` properties, you must define the equivalent in DotTiled as a . You can then return the corresponding definition in the resolving function. -![Resolve object types and properties](../images/resolve-types.png) +For example, if you have a custom property type in Tiled that looks like this: -This will make sure that all properties, even those that do not differ from their default values, are included in the exported map, tileset, or template file. This will allow DotTiled to resolve the properties of the `class` property without needing an equivalent definition. However, you *must* enable a similar configuration flag in DotTiled when loading the map, tileset, or template to make sure that DotTiled knows to not throw an exception when it encounters a `class` property without an equivalent definition. +![EntityType enum in Tiled UI](../images/entity-type-enum.png) + +The equivalent definition in DotTiled would look like the following: + +```csharp +var entityTypeDefinition = new CustomEnumDefinition +{ + Name = "EntityType", + StorageType = CustomEnumStorageType.String, + ValueAsFlags = false, + Values = [ + "Bomb", + "Chest", + "Flower", + "Chair" + ] +}; +``` ### [Future] Automatically map custom property `class` types to C# classes In the future, DotTiled will support automatically mapping custom property `class` types to C# classes. This will allow you to define a C# class that matches the structure of the `class` property in Tiled, and DotTiled will automatically map the properties of the `class` property to the properties of the C# class. This will make working with `class` properties much easier and more intuitive. -The idea is to expand on the interface with a method like `GetMappedProperty(string propertyName)`, where `T` is a class that matches the structure of the `class` property in Tiled. \ No newline at end of file +The idea is to expand on the interface with a method like `GetMappedProperty(string propertyName)`, where `T` is a class that matches the structure of the `class` property in Tiled. + +This functionality would be accompanied by a way to automatically create a matching given a C# class or enum. Something like this would then be possible: + +```csharp +class MonsterSpawner +{ + public bool Enabled { get; set; } = true; + public int MaxSpawnAmount { get; set; } = 10; + public int MinSpawnAmount { get; set; } = 0; + public string MonsterNames { get; set; } = ""; +} + +enum EntityType +{ + Bomb, + Chest, + Flower, + Chair +} + +var monsterSpawnerDefinition = CustomClassDefinition.FromClass(); +var entityTypeDefinition = CustomEnumDefinition.FromEnum(); + +// ... + +var map = LoadMap(); +var monsterSpawner = map.GetMappedProperty("monsterSpawnerPropertyInMap"); +var entityType = map.GetMappedProperty("entityTypePropertyInMap"); +``` + +Finally, it might be possible to also make some kind of exporting functionality for . Given a collection of custom type definitions, DotTiled could generate a corresponding `propertytypes.json` file that you then can import into Tiled. This would make it so that you only have to define your custom property types once (in C#) and then import them into Tiled to use them in your maps. + +Depending on implementation this might become something that can inhibit native AOT compilation due to potential reflection usage. Source generators could be used to mitigate this, but it is not yet clear how this will be implemented. \ No newline at end of file diff --git a/docs/docs/toc.yml b/docs/docs/toc.yml index d582202..62d2c9d 100644 --- a/docs/docs/toc.yml +++ b/docs/docs/toc.yml @@ -4,4 +4,4 @@ - name: Essentials - href: loading-a-map.md -- href: accessing-properties.md \ No newline at end of file +- href: custom-properties.md \ No newline at end of file diff --git a/docs/images/entity-type-enum.png b/docs/images/entity-type-enum.png new file mode 100644 index 0000000000000000000000000000000000000000..459689b3e63e007155e0d2fd55a9ce1597106305 GIT binary patch literal 11906 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 literal 0 HcmV?d00001 diff --git a/src/DotTiled.Benchmark/Program.cs b/src/DotTiled.Benchmark/Program.cs index 3cd6e15..523a7f1 100644 --- a/src/DotTiled.Benchmark/Program.cs +++ b/src/DotTiled.Benchmark/Program.cs @@ -47,7 +47,7 @@ public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmxString() [Benchmark(Baseline = true, Description = "DotTiled")] public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmjString() { - using var mapReader = new DotTiled.Serialization.Tmj.TmjMapReader(_tmjContents, _ => throw new NotSupportedException(), _ => throw new NotSupportedException(), []); + using var mapReader = new DotTiled.Serialization.Tmj.TmjMapReader(_tmjContents, _ => throw new NotSupportedException(), _ => throw new NotSupportedException(), _ => throw new NotSupportedException()); return mapReader.ReadMap(); } diff --git a/src/DotTiled.Tests/Serialization/TestData.cs b/src/DotTiled.Tests/Serialization/TestData.cs index b007913..1c0b885 100644 --- a/src/DotTiled.Tests/Serialization/TestData.cs +++ b/src/DotTiled.Tests/Serialization/TestData.cs @@ -41,5 +41,6 @@ private static string ConvertPathToAssemblyResourcePath(string path) => ["Serialization/TestData/Map/map_external_tileset_multi/map-external-tileset-multi", (string f) => MapExternalTilesetMulti(f), Array.Empty()], ["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()], ]; } diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.cs new file mode 100644 index 0000000..1b36b4e --- /dev/null +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.cs @@ -0,0 +1,161 @@ +using System.Globalization; +using DotTiled.Model; + +namespace DotTiled.Tests; + +public partial class TestData +{ + public static Map MapWithDeepProps() => new Map + { + Class = "", + Orientation = MapOrientation.Orthogonal, + Width = 5, + Height = 5, + TileWidth = 32, + TileHeight = 32, + Infinite = false, + HexSideLength = null, + StaggerAxis = null, + StaggerIndex = null, + ParallaxOriginX = 0, + ParallaxOriginY = 0, + RenderOrder = RenderOrder.RightDown, + CompressionLevel = -1, + BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture), + 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, + Chunks = null, + Compression = null, + GlobalTileIDs = [ + 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 = [ + 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 ClassProperty + { + Name = "customouterclassprop", + PropertyType = "CustomOuterClass", + Value = [ + new ClassProperty + { + Name = "customclasspropinclass", + PropertyType = "CustomClass", + Value = [ + new BoolProperty { Name = "boolinclass", Value = false }, + new ColorProperty { Name = "colorinclass", Value = Color.Parse("#000000ff", CultureInfo.InvariantCulture) }, + new FileProperty { Name = "fileinclass", Value = "" }, + new FloatProperty { Name = "floatinclass", Value = 0f }, + new IntProperty { Name = "intinclass", Value = 0 }, + new ObjectProperty { Name = "objectinclass", Value = 0 }, + new StringProperty { Name = "stringinclass", Value = "" } + ] + } + ] + }, + new ClassProperty + { + Name = "customouterclasspropset", + PropertyType = "CustomOuterClass", + Value = [ + new ClassProperty + { + Name = "customclasspropinclass", + PropertyType = "CustomClass", + Value = [ + new BoolProperty { Name = "boolinclass", Value = true }, + new ColorProperty { Name = "colorinclass", Value = Color.Parse("#000000ff", CultureInfo.InvariantCulture) }, + new FileProperty { Name = "fileinclass", Value = "" }, + new FloatProperty { Name = "floatinclass", Value = 13.37f }, + new IntProperty { Name = "intinclass", Value = 0 }, + new ObjectProperty { Name = "objectinclass", Value = 0 }, + new StringProperty { Name = "stringinclass", Value = "" } + ] + } + ] + } + ] + }; + + public static IReadOnlyCollection MapWithDeepPropsCustomTypeDefinitions() => [ + new CustomClassDefinition + { + Name = "CustomClass", + UseAs = CustomClassUseAs.Property, + Members = [ + new BoolProperty + { + Name = "boolinclass", + Value = false + }, + new ColorProperty + { + Name = "colorinclass", + Value = Color.Parse("#000000ff", CultureInfo.InvariantCulture) + }, + new FileProperty + { + Name = "fileinclass", + Value = "" + }, + new FloatProperty + { + Name = "floatinclass", + Value = 0f + }, + new IntProperty + { + Name = "intinclass", + Value = 0 + }, + new ObjectProperty + { + Name = "objectinclass", + Value = 0 + }, + new StringProperty + { + Name = "stringinclass", + Value = "" + } + ] + }, + new CustomClassDefinition + { + Name = "CustomOuterClass", + UseAs = CustomClassUseAs.Property, + Members = [ + new ClassProperty + { + Name = "customclasspropinclass", + PropertyType = "CustomClass", + Value = [] // So no overrides of defaults in CustomClass + } + ] + } + ]; +} diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.tmj b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.tmj new file mode 100644 index 0000000..9fa2bba --- /dev/null +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.tmj @@ -0,0 +1,55 @@ +{ "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":"customouterclassprop", + "propertytype":"CustomOuterClass", + "type":"class", + "value": + { + + } + }, + { + "name":"customouterclasspropset", + "propertytype":"CustomOuterClass", + "type":"class", + "value": + { + "customclasspropinclass": + { + "boolinclass":true, + "floatinclass":13.37 + } + } + }], + "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-deep-props/map-with-deep-props.tmx b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.tmx new file mode 100644 index 0000000..56e8f2e --- /dev/null +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.tmx @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + +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/Tmj/TmjMapReaderTests.cs b/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs index 3fe6843..48cc13f 100644 --- a/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs @@ -20,16 +20,20 @@ public void TmxMapReaderReadMap_ValidTmjExternalTilesetsAndTemplates_ReturnsMapT Template ResolveTemplate(string source) { var templateJson = TestData.GetRawStringFor($"{fileDir}/{source}"); - using var templateReader = new TjTemplateReader(templateJson, ResolveTileset, ResolveTemplate, customTypeDefinitions); + using var templateReader = new TjTemplateReader(templateJson, ResolveTileset, ResolveTemplate, ResolveCustomType); return templateReader.ReadTemplate(); } Tileset ResolveTileset(string source) { var tilesetJson = TestData.GetRawStringFor($"{fileDir}/{source}"); - using var tilesetReader = new TsjTilesetReader(tilesetJson, ResolveTemplate, customTypeDefinitions); + using var tilesetReader = new TsjTilesetReader(tilesetJson, ResolveTileset, ResolveTemplate, ResolveCustomType); return tilesetReader.ReadTileset(); } - using var mapReader = new TmjMapReader(json, ResolveTileset, ResolveTemplate, customTypeDefinitions); + ICustomTypeDefinition ResolveCustomType(string name) + { + return customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name)!; + } + using var mapReader = new TmjMapReader(json, ResolveTileset, ResolveTemplate, ResolveCustomType); // Act var map = mapReader.ReadMap(); diff --git a/src/DotTiled/Serialization/Helpers.cs b/src/DotTiled/Serialization/Helpers.cs index 073a19f..1e95695 100644 --- a/src/DotTiled/Serialization/Helpers.cs +++ b/src/DotTiled/Serialization/Helpers.cs @@ -73,8 +73,25 @@ internal static ImageFormat ParseImageFormatFromSource(string source) }; } - internal static List CreateInstanceOfCustomClass(CustomClassDefinition customClassDefinition) => - customClassDefinition.Members.Select(x => x.Clone()).ToList(); + internal static List CreateInstanceOfCustomClass( + CustomClassDefinition customClassDefinition, + Func customTypeResolver) + { + return customClassDefinition.Members.Select(x => + { + if (x is ClassProperty cp) + { + return new ClassProperty + { + Name = cp.Name, + PropertyType = cp.PropertyType, + Value = CreateInstanceOfCustomClass((CustomClassDefinition)customTypeResolver(cp.PropertyType), customTypeResolver) + }; + } + + return x.Clone(); + }).ToList(); + } internal static IList MergeProperties(IList? baseProperties, IList? overrideProperties) { diff --git a/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs b/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs index c4ada75..6a71eb7 100644 --- a/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs +++ b/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using DotTiled.Model; namespace DotTiled.Serialization.Tmj; @@ -7,73 +6,24 @@ namespace DotTiled.Serialization.Tmj; /// /// A template reader for reading Tiled JSON templates. /// -public class TjTemplateReader : ITemplateReader +public class TjTemplateReader : TmjReaderBase, ITemplateReader { - // External resolvers - private readonly Func _externalTilesetResolver; - private readonly Func _externalTemplateResolver; - - private readonly string _jsonString; - private bool disposedValue; - - private readonly IReadOnlyCollection _customTypeDefinitions; - /// /// Constructs a new . /// - /// A string containing a Tiled template in the Tiled JSON format. + /// A string containing a Tiled map in the Tiled JSON format. /// A function that resolves external tilesets given their source. /// A function that resolves external templates given their source. - /// A collection of custom type definitions that can be used to resolve custom types when encountering . + /// A function that resolves custom types given their name. /// Thrown when any of the arguments are null. public TjTemplateReader( string jsonString, Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - _jsonString = jsonString ?? throw new ArgumentNullException(nameof(jsonString)); - _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); - _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); - _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); - } - - /// - public Template ReadTemplate() - { - var jsonDoc = System.Text.Json.JsonDocument.Parse(_jsonString); - var rootElement = jsonDoc.RootElement; - return Tmj.ReadTemplate(rootElement, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions); - } - - /// - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - // TODO: dispose managed state (managed objects) - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~TjTemplateReader() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } + Func customTypeResolver) : base( + jsonString, externalTilesetResolver, externalTemplateResolver, customTypeResolver) + { } /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); - } + public Template ReadTemplate() => ReadTemplate(RootElement); } diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs b/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs deleted file mode 100644 index aeef011..0000000 --- a/src/DotTiled/Serialization/Tmj/Tmj.Layer.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.Json; -using DotTiled.Model; - -namespace DotTiled.Serialization.Tmj; - -internal partial class Tmj -{ - internal static BaseLayer ReadLayer( - JsonElement element, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - var type = element.GetRequiredProperty("type"); - - return type switch - { - "tilelayer" => ReadTileLayer(element, customTypeDefinitions), - "objectgroup" => ReadObjectLayer(element, externalTemplateResolver, customTypeDefinitions), - "imagelayer" => ReadImageLayer(element, customTypeDefinitions), - "group" => ReadGroup(element, externalTemplateResolver, customTypeDefinitions), - _ => throw new JsonException($"Unsupported layer type '{type}'.") - }; - } -} diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs b/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs deleted file mode 100644 index d9777e7..0000000 --- a/src/DotTiled/Serialization/Tmj/Tmj.Properties.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text.Json; -using DotTiled.Model; - -namespace DotTiled.Serialization.Tmj; - -internal partial class Tmj -{ - internal static List 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!; - }); - - internal static ClassProperty ReadClassProperty( - JsonElement element, - IReadOnlyCollection customTypeDefinitions) - { - var name = element.GetRequiredProperty("name"); - var propertyType = element.GetRequiredProperty("propertytype"); - - var customTypeDef = customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == propertyType); - - if (customTypeDef is CustomClassDefinition ccd) - { - var propsInType = Helpers.CreateInstanceOfCustomClass(ccd); - var props = element.GetOptionalPropertyCustom>("value", el => ReadCustomClassProperties(el, ccd, customTypeDefinitions), []); - - var mergedProps = Helpers.MergeProperties(propsInType, props); - - return new ClassProperty - { - Name = name, - PropertyType = propertyType, - Value = props - }; - } - - throw new JsonException($"Unknown custom class '{propertyType}'."); - } - - internal static List ReadCustomClassProperties( - JsonElement element, - CustomClassDefinition customClassDefinition, - IReadOnlyCollection customTypeDefinitions) - { - List resultingProps = Helpers.CreateInstanceOfCustomClass(customClassDefinition); - - foreach (var prop in customClassDefinition.Members) - { - if (!element.TryGetProperty(prop.Name, out var propElement)) - continue; // Property not present in element, therefore will use default value - - IProperty property = prop.Type switch - { - PropertyType.String => new StringProperty { Name = prop.Name, Value = propElement.GetValueAs() }, - PropertyType.Int => new IntProperty { Name = prop.Name, Value = propElement.GetValueAs() }, - PropertyType.Float => new FloatProperty { Name = prop.Name, Value = propElement.GetValueAs() }, - PropertyType.Bool => new BoolProperty { Name = prop.Name, Value = propElement.GetValueAs() }, - PropertyType.Color => new ColorProperty { Name = prop.Name, Value = Color.Parse(propElement.GetValueAs(), CultureInfo.InvariantCulture) }, - PropertyType.File => new FileProperty { Name = prop.Name, Value = propElement.GetValueAs() }, - PropertyType.Object => new ObjectProperty { Name = prop.Name, Value = propElement.GetValueAs() }, - PropertyType.Class => ReadClassProperty(propElement, customTypeDefinitions), - _ => throw new JsonException("Invalid property type") - }; - - Helpers.ReplacePropertyInList(resultingProps, property); - } - - return resultingProps; - } -} diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Template.cs b/src/DotTiled/Serialization/Tmj/Tmj.Template.cs deleted file mode 100644 index 71ba1e7..0000000 --- a/src/DotTiled/Serialization/Tmj/Tmj.Template.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.Json; -using DotTiled.Model; - -namespace DotTiled.Serialization.Tmj; - -internal partial class Tmj -{ - internal static Template ReadTemplate( - JsonElement element, - Func externalTilesetResolver, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - var type = element.GetRequiredProperty("type"); - var tileset = element.GetOptionalPropertyCustom("tileset", el => ReadTileset(el, externalTilesetResolver, externalTemplateResolver, customTypeDefinitions), null); - var @object = element.GetRequiredPropertyCustom("object", el => ReadObject(el, externalTemplateResolver, customTypeDefinitions)); - - return new Template - { - Tileset = tileset, - Object = @object - }; - } -} diff --git a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs index 1d277b1..7ec12e1 100644 --- a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs +++ b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text.Json; using DotTiled.Model; namespace DotTiled.Serialization.Tmj; @@ -8,73 +6,24 @@ namespace DotTiled.Serialization.Tmj; /// /// A map reader for reading Tiled JSON maps. /// -public class TmjMapReader : IMapReader +public class TmjMapReader : TmjReaderBase, IMapReader { - // External resolvers - private readonly Func _externalTilesetResolver; - private readonly Func _externalTemplateResolver; - - private readonly string _jsonString; - private bool disposedValue; - - private readonly IReadOnlyCollection _customTypeDefinitions; - /// /// Constructs a new . /// /// A string containing a Tiled map in the Tiled JSON format. /// A function that resolves external tilesets given their source. /// A function that resolves external templates given their source. - /// A collection of custom type definitions that can be used to resolve custom types when encountering . + /// A function that resolves custom types given their name. /// Thrown when any of the arguments are null. public TmjMapReader( string jsonString, Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - _jsonString = jsonString ?? throw new ArgumentNullException(nameof(jsonString)); - _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); - _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); - _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); - } - - /// - public Map ReadMap() - { - var jsonDoc = JsonDocument.Parse(_jsonString); - var rootElement = jsonDoc.RootElement; - return Tmj.ReadMap(rootElement, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions); - } - - /// - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - // TODO: dispose managed state (managed objects) - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~TmjMapReader() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } + Func customTypeResolver) : base( + jsonString, externalTilesetResolver, externalTemplateResolver, customTypeResolver) + { } /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); - } + public Map ReadMap() => ReadMap(RootElement); } diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Data.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Data.cs similarity index 98% rename from src/DotTiled/Serialization/Tmj/Tmj.Data.cs rename to src/DotTiled/Serialization/Tmj/TmjReaderBase.Data.cs index c021a6c..22a35e2 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Data.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Data.cs @@ -5,7 +5,7 @@ namespace DotTiled.Serialization.Tmj; -internal partial class Tmj +public abstract partial class TmjReaderBase { internal static Data ReadDataAsChunks(JsonElement element, DataCompression? compression, DataEncoding encoding) { diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Group.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs similarity index 77% rename from src/DotTiled/Serialization/Tmj/Tmj.Group.cs rename to src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs index a714038..e132d0c 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Group.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Globalization; using System.Text.Json; @@ -6,12 +5,9 @@ namespace DotTiled.Serialization.Tmj; -internal partial class Tmj +public abstract partial class TmjReaderBase { - internal static Group ReadGroup( - JsonElement element, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + internal Group ReadGroup(JsonElement element) { var id = element.GetRequiredProperty("id"); var name = element.GetRequiredProperty("name"); @@ -23,8 +19,8 @@ internal static Group ReadGroup( 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), []); - var layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(el => ReadLayer(el, externalTemplateResolver, customTypeDefinitions)), []); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); + var layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(ReadLayer), []); return new Group { diff --git a/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs similarity index 88% rename from src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs rename to src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs index 74fb230..576fa52 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.ImageLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs @@ -1,15 +1,12 @@ -using System.Collections.Generic; using System.Globalization; using System.Text.Json; using DotTiled.Model; namespace DotTiled.Serialization.Tmj; -internal partial class Tmj +public abstract partial class TmjReaderBase { - internal static ImageLayer ReadImageLayer( - JsonElement element, - IReadOnlyCollection customTypeDefinitions) + internal ImageLayer ReadImageLayer(JsonElement element) { var id = element.GetRequiredProperty("id"); var name = element.GetRequiredProperty("name"); @@ -21,7 +18,7 @@ internal static ImageLayer ReadImageLayer( 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), []); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); var image = element.GetRequiredProperty("image"); var repeatX = element.GetOptionalProperty("repeatx", false); diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Layer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Layer.cs new file mode 100644 index 0000000..9e01d84 --- /dev/null +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Layer.cs @@ -0,0 +1,21 @@ +using System.Text.Json; +using DotTiled.Model; + +namespace DotTiled.Serialization.Tmj; + +public abstract partial class TmjReaderBase +{ + internal BaseLayer ReadLayer(JsonElement element) + { + var type = element.GetRequiredProperty("type"); + + return type switch + { + "tilelayer" => ReadTileLayer(element), + "objectgroup" => ReadObjectLayer(element), + "imagelayer" => ReadImageLayer(element), + "group" => ReadGroup(element), + _ => throw new JsonException($"Unsupported layer type '{type}'.") + }; + } +} diff --git a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs similarity index 88% rename from src/DotTiled/Serialization/Tmj/Tmj.Map.cs rename to src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs index eeb47b0..47abc66 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Map.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Globalization; using System.Text.Json; @@ -6,13 +5,9 @@ namespace DotTiled.Serialization.Tmj; -internal partial class Tmj +public abstract partial class TmjReaderBase { - internal static Map ReadMap( - JsonElement element, - Func? externalTilesetResolver, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + internal Map ReadMap(JsonElement element) { var version = element.GetRequiredProperty("version"); var tiledVersion = element.GetRequiredProperty("tiledversion"); @@ -58,10 +53,10 @@ internal static Map ReadMap( var nextObjectID = element.GetRequiredProperty("nextobjectid"); var infinite = element.GetOptionalProperty("infinite", false); - var properties = element.GetOptionalPropertyCustom("properties", el => ReadProperties(el, customTypeDefinitions), []); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); - 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)), []); + List layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(el => ReadLayer(el)), []); + List tilesets = element.GetOptionalPropertyCustom>("tilesets", e => e.GetValueAsList(el => ReadTileset(el)), []); return new Map { diff --git a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs similarity index 93% rename from src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs rename to src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs index 589c151..cae4790 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Globalization; using System.Numerics; @@ -7,12 +6,9 @@ namespace DotTiled.Serialization.Tmj; -internal partial class Tmj +public abstract partial class TmjReaderBase { - internal static ObjectLayer ReadObjectLayer( - JsonElement element, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + internal ObjectLayer ReadObjectLayer(JsonElement element) { var id = element.GetRequiredProperty("id"); var name = element.GetRequiredProperty("name"); @@ -24,7 +20,7 @@ internal static ObjectLayer ReadObjectLayer( 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), []); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); var x = element.GetOptionalProperty("x", 0); var y = element.GetOptionalProperty("y", 0); @@ -38,7 +34,7 @@ internal static ObjectLayer ReadObjectLayer( _ => throw new JsonException($"Unknown draw order '{s}'.") }, DrawOrder.TopDown); - var objects = element.GetOptionalPropertyCustom>("objects", e => e.GetValueAsList(el => ReadObject(el, externalTemplateResolver, customTypeDefinitions)), []); + var objects = element.GetOptionalPropertyCustom>("objects", e => e.GetValueAsList(el => ReadObject(el)), []); return new ObjectLayer { @@ -63,10 +59,7 @@ internal static ObjectLayer ReadObjectLayer( }; } - internal static Model.Object ReadObject( - JsonElement element, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + internal Model.Object ReadObject(JsonElement element) { uint? idDefault = null; string nameDefault = ""; @@ -87,7 +80,7 @@ internal static Model.Object ReadObject( var template = element.GetOptionalProperty("template", null); if (template is not null) { - var resolvedTemplate = externalTemplateResolver(template); + var resolvedTemplate = _externalTemplateResolver(template); var templObj = resolvedTemplate.Object; idDefault = templObj.ID; @@ -114,7 +107,7 @@ internal static Model.Object ReadObject( 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", ReadProperties, 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/TmjReaderBase.Properties.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Properties.cs new file mode 100644 index 0000000..c5b6a7d --- /dev/null +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Properties.cs @@ -0,0 +1,174 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.Json; +using DotTiled.Model; + +namespace DotTiled.Serialization.Tmj; + +public abstract partial class TmjReaderBase +{ + internal List ReadProperties(JsonElement element) => + 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); + var propertyType = e.GetOptionalProperty("propertytype", null); + if (propertyType is not null) + { + return ReadPropertyWithCustomType(e); + } + + 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 => throw new JsonException("Class property must have a property type"), + PropertyType.Enum => throw new JsonException("Enum property must have a property type"), + _ => throw new JsonException("Invalid property type") + }; + + return property!; + }); + + internal IProperty ReadPropertyWithCustomType(JsonElement element) + { + var isClass = element.GetOptionalProperty("type", null) == "class"; + if (isClass) + { + return ReadClassProperty(element); + } + + return ReadEnumProperty(element); + } + + internal ClassProperty ReadClassProperty(JsonElement element) + { + var name = element.GetRequiredProperty("name"); + var propertyType = element.GetRequiredProperty("propertytype"); + var customTypeDef = _customTypeResolver(propertyType); + + if (customTypeDef is CustomClassDefinition ccd) + { + var propsInType = Helpers.CreateInstanceOfCustomClass(ccd, _customTypeResolver); + var props = element.GetOptionalPropertyCustom>("value", e => ReadPropertiesInsideClass(e, ccd), []); + var mergedProps = Helpers.MergeProperties(propsInType, props); + + return new ClassProperty + { + Name = name, + PropertyType = propertyType, + Value = mergedProps + }; + } + + throw new JsonException($"Unknown custom class '{propertyType}'."); + } + + internal List ReadPropertiesInsideClass( + JsonElement element, + CustomClassDefinition customClassDefinition) + { + List resultingProps = []; + + foreach (var prop in customClassDefinition.Members) + { + if (!element.TryGetProperty(prop.Name, out var propElement)) + continue; + + IProperty property = prop.Type switch + { + PropertyType.String => new StringProperty { Name = prop.Name, Value = propElement.GetValueAs() }, + PropertyType.Int => new IntProperty { Name = prop.Name, Value = propElement.GetValueAs() }, + PropertyType.Float => new FloatProperty { Name = prop.Name, Value = propElement.GetValueAs() }, + PropertyType.Bool => new BoolProperty { Name = prop.Name, Value = propElement.GetValueAs() }, + PropertyType.Color => new ColorProperty { Name = prop.Name, Value = Color.Parse(propElement.GetValueAs(), CultureInfo.InvariantCulture) }, + PropertyType.File => new FileProperty { Name = prop.Name, Value = propElement.GetValueAs() }, + PropertyType.Object => new ObjectProperty { Name = prop.Name, Value = propElement.GetValueAs() }, + PropertyType.Class => new ClassProperty { Name = prop.Name, PropertyType = ((ClassProperty)prop).PropertyType, Value = ReadPropertiesInsideClass(propElement, (CustomClassDefinition)_customTypeResolver(((ClassProperty)prop).PropertyType)) }, + PropertyType.Enum => ReadEnumProperty(propElement), + _ => throw new JsonException("Invalid property type") + }; + + resultingProps.Add(property); + } + + return resultingProps; + } + + internal EnumProperty ReadEnumProperty(JsonElement element) + { + var name = element.GetRequiredProperty("name"); + var propertyType = element.GetRequiredProperty("propertytype"); + var typeInXml = element.GetOptionalPropertyParseable("type", (s) => s switch + { + "string" => PropertyType.String, + "int" => PropertyType.Int, + _ => throw new JsonException("Invalid property type") + }, PropertyType.String); + var customTypeDef = _customTypeResolver(propertyType); + + if (customTypeDef is not CustomEnumDefinition ced) + throw new JsonException($"Unknown custom enum '{propertyType}'. Enums must be defined"); + + if (ced.StorageType == CustomEnumStorageType.String) + { + var value = element.GetRequiredProperty("value"); + if (value.Contains(',') && !ced.ValueAsFlags) + throw new JsonException("Enum value must not contain ',' if not ValueAsFlags is set to true."); + + if (ced.ValueAsFlags) + { + var values = value.Split(',').Select(v => v.Trim()).ToHashSet(); + return new EnumProperty { Name = name, PropertyType = propertyType, Value = values }; + } + else + { + return new EnumProperty { Name = name, PropertyType = propertyType, Value = new HashSet { value } }; + } + } + else if (ced.StorageType == CustomEnumStorageType.Int) + { + var value = element.GetRequiredProperty("value"); + if (ced.ValueAsFlags) + { + var allValues = ced.Values; + var enumValues = new HashSet(); + for (var i = 0; i < allValues.Count; i++) + { + var mask = 1 << i; + if ((value & mask) == mask) + { + var enumValue = allValues[i]; + _ = enumValues.Add(enumValue); + } + } + return new EnumProperty { Name = name, PropertyType = propertyType, Value = enumValues }; + } + else + { + var allValues = ced.Values; + var enumValue = allValues[value]; + return new EnumProperty { Name = name, PropertyType = propertyType, Value = new HashSet { enumValue } }; + } + } + + throw new JsonException($"Unknown custom enum '{propertyType}'. Enums must be defined"); + } +} diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs new file mode 100644 index 0000000..45031db --- /dev/null +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs @@ -0,0 +1,20 @@ +using System.Text.Json; +using DotTiled.Model; + +namespace DotTiled.Serialization.Tmj; + +public abstract partial class TmjReaderBase +{ + internal Template ReadTemplate(JsonElement element) + { + var type = element.GetRequiredProperty("type"); + var tileset = element.GetOptionalPropertyCustom("tileset", ReadTileset, null); + var @object = element.GetRequiredPropertyCustom("object", ReadObject); + + return new Template + { + Tileset = tileset, + Object = @object + }; + } +} diff --git a/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs similarity index 91% rename from src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs rename to src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs index 905e447..ecc74d8 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs @@ -1,15 +1,12 @@ -using System.Collections.Generic; using System.Globalization; using System.Text.Json; using DotTiled.Model; namespace DotTiled.Serialization.Tmj; -internal partial class Tmj +public abstract partial class TmjReaderBase { - internal static TileLayer ReadTileLayer( - JsonElement element, - IReadOnlyCollection customTypeDefinitions) + internal TileLayer ReadTileLayer(JsonElement element) { var compression = element.GetOptionalPropertyParseable("compression", s => s switch { @@ -35,7 +32,7 @@ internal static TileLayer ReadTileLayer( 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), []); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); 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/TmjReaderBase.Tileset.cs similarity index 86% rename from src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs rename to src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs index 466b5d3..5fef5f3 100644 --- a/src/DotTiled/Serialization/Tmj/Tmj.Tileset.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Globalization; using System.Text.Json; @@ -6,13 +5,9 @@ namespace DotTiled.Serialization.Tmj; -internal partial class Tmj +public abstract partial class TmjReaderBase { - internal static Tileset ReadTileset( - JsonElement element, - Func? externalTilesetResolver, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) + internal Tileset ReadTileset(JsonElement element) { var backgroundColor = element.GetOptionalPropertyParseable("backgroundcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); var @class = element.GetOptionalProperty("class", ""); @@ -44,7 +39,7 @@ internal static Tileset ReadTileset( "bottomright" => ObjectAlignment.BottomRight, _ => throw new JsonException($"Unknown object alignment '{s}'") }, ObjectAlignment.Unspecified); - var properties = element.GetOptionalPropertyCustom("properties", el => ReadProperties(el, customTypeDefinitions), []); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); var source = element.GetOptionalProperty("source", null); var spacing = element.GetOptionalProperty("spacing", null); var tileCount = element.GetOptionalProperty("tilecount", null); @@ -57,20 +52,17 @@ internal static Tileset ReadTileset( "grid" => TileRenderSize.Grid, _ => throw new JsonException($"Unknown tile render size '{s}'") }, TileRenderSize.Tile); - var tiles = element.GetOptionalPropertyCustom>("tiles", el => ReadTiles(el, externalTemplateResolver, customTypeDefinitions), []); + var tiles = element.GetOptionalPropertyCustom>("tiles", ReadTiles, []); var tileWidth = element.GetOptionalProperty("tilewidth", null); var transparentColor = element.GetOptionalPropertyParseable("transparentcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); var type = element.GetOptionalProperty("type", null); var version = element.GetOptionalProperty("version", null); var transformations = element.GetOptionalPropertyCustom("transformations", ReadTransformations, null); - var wangsets = element.GetOptionalPropertyCustom?>("wangsets", el => el.GetValueAsList(e => ReadWangset(e, customTypeDefinitions)), null); + var wangsets = element.GetOptionalPropertyCustom?>("wangsets", el => el.GetValueAsList(e => ReadWangset(e)), null); if (source is not null) { - if (externalTilesetResolver is null) - throw new JsonException("External tileset resolver is required to resolve external tilesets."); - - var resolvedTileset = externalTilesetResolver(source); + var resolvedTileset = _externalTilesetResolver(source); resolvedTileset.FirstGID = firstGID; resolvedTileset.Source = source; return resolvedTileset; @@ -159,10 +151,7 @@ internal static TileOffset ReadTileOffset(JsonElement element) }; } - internal static List ReadTiles( - JsonElement element, - Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) => + internal List ReadTiles(JsonElement element) => element.GetValueAsList(e => { var animation = e.GetOptionalPropertyCustom?>("animation", e => e.GetValueAsList(ReadFrame), null); @@ -174,9 +163,9 @@ internal static List ReadTiles( var y = e.GetOptionalProperty("y", 0); var width = e.GetOptionalProperty("width", imageWidth ?? 0); var height = e.GetOptionalProperty("height", imageHeight ?? 0); - var objectGroup = e.GetOptionalPropertyCustom("objectgroup", e => ReadObjectLayer(e, externalTemplateResolver, customTypeDefinitions), null); + var objectGroup = e.GetOptionalPropertyCustom("objectgroup", e => ReadObjectLayer(e), null); var probability = e.GetOptionalProperty("probability", 0.0f); - var properties = e.GetOptionalPropertyCustom("properties", el => ReadProperties(el, customTypeDefinitions), []); + var properties = e.GetOptionalPropertyCustom("properties", ReadProperties, []); // var terrain, replaced by wangsets var type = e.GetOptionalProperty("type", ""); @@ -216,14 +205,12 @@ internal static Frame ReadFrame(JsonElement element) }; } - internal static Wangset ReadWangset( - JsonElement element, - IReadOnlyCollection customTypeDefinitions) + internal Wangset ReadWangset(JsonElement element) { var @clalss = element.GetOptionalProperty("class", ""); - var colors = element.GetOptionalPropertyCustom>("colors", e => e.GetValueAsList(el => ReadWangColor(el, customTypeDefinitions)), []); + var colors = element.GetOptionalPropertyCustom>("colors", e => e.GetValueAsList(el => ReadWangColor(el)), []); var name = element.GetRequiredProperty("name"); - var properties = element.GetOptionalPropertyCustom("properties", e => ReadProperties(e, customTypeDefinitions), []); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); var tile = element.GetOptionalProperty("tile", 0); var type = element.GetOptionalProperty("type", ""); var wangTiles = element.GetOptionalPropertyCustom>("wangtiles", e => e.GetValueAsList(ReadWangTile), []); @@ -239,15 +226,13 @@ internal static Wangset ReadWangset( }; } - internal static WangColor ReadWangColor( - JsonElement element, - IReadOnlyCollection customTypeDefinitions) + internal WangColor ReadWangColor(JsonElement element) { var @class = element.GetOptionalProperty("class", ""); 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), []); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); var tile = element.GetOptionalProperty("tile", 0); return new WangColor diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.cs new file mode 100644 index 0000000..4ae338f --- /dev/null +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.cs @@ -0,0 +1,74 @@ +using System; +using System.Text.Json; +using DotTiled.Model; + +namespace DotTiled.Serialization.Tmj; + +/// +/// Base class for Tiled JSON format readers. +/// +public abstract partial class TmjReaderBase : IDisposable +{ + // External resolvers + private readonly Func _externalTilesetResolver; + private readonly Func _externalTemplateResolver; + private readonly Func _customTypeResolver; + + /// + /// The root element of the JSON document being read. + /// + protected JsonElement RootElement { get; private set; } + + private bool disposedValue; + + /// + /// Constructs a new . + /// + /// A string containing a Tiled map in the Tiled JSON format. + /// A function that resolves external tilesets given their source. + /// A function that resolves external templates given their source. + /// A collection of custom type definitions that can be used to resolve custom types when encountering . + /// Thrown when any of the arguments are null. + protected TmjReaderBase( + string jsonString, + Func externalTilesetResolver, + Func externalTemplateResolver, + Func customTypeResolver) + { + RootElement = JsonDocument.Parse(jsonString ?? throw new ArgumentNullException(nameof(jsonString))).RootElement; + _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); + _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); + _customTypeResolver = customTypeResolver ?? throw new ArgumentNullException(nameof(customTypeResolver)); + } + + /// + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: dispose managed state (managed objects) + } + + // TODO: free unmanaged resources (unmanaged objects) and override finalizer + // TODO: set large fields to null + disposedValue = true; + } + } + + // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources + // ~TmjMapReader() + // { + // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + // Dispose(disposing: false); + // } + + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } +} diff --git a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs index dde9075..8c918b5 100644 --- a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using DotTiled.Model; namespace DotTiled.Serialization.Tmj; @@ -7,73 +6,24 @@ namespace DotTiled.Serialization.Tmj; /// /// A tileset reader for the Tiled JSON format. /// -public class TsjTilesetReader : ITilesetReader +public class TsjTilesetReader : TmjReaderBase, ITilesetReader { - // External resolvers - private readonly Func _externalTemplateResolver; - - private readonly string _jsonString; - private bool disposedValue; - - private readonly IReadOnlyCollection _customTypeDefinitions; - /// /// Constructs a new . /// - /// A string containing a Tiled tileset in the Tiled JSON format. + /// A string containing a Tiled map in the Tiled JSON format. + /// A function that resolves external tilesets given their source. /// A function that resolves external templates given their source. - /// A collection of custom type definitions that can be used to resolve custom types when encountering . + /// A function that resolves custom types given their name. /// Thrown when any of the arguments are null. public TsjTilesetReader( string jsonString, + Func externalTilesetResolver, Func externalTemplateResolver, - IReadOnlyCollection customTypeDefinitions) - { - _jsonString = jsonString ?? throw new ArgumentNullException(nameof(jsonString)); - _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); - _customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions)); - } - - /// - public Tileset ReadTileset() - { - var jsonDoc = System.Text.Json.JsonDocument.Parse(_jsonString); - var rootElement = jsonDoc.RootElement; - return Tmj.ReadTileset( - rootElement, - _ => throw new NotSupportedException("External tilesets cannot refer to other external tilesets."), - _externalTemplateResolver, - _customTypeDefinitions); - } - - /// - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - // TODO: dispose managed state (managed objects) - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~TsjTilesetReader() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } + Func customTypeResolver) : base( + jsonString, externalTilesetResolver, externalTemplateResolver, customTypeResolver) + { } /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); - } + public Tileset ReadTileset() => ReadTileset(RootElement); } diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs index 1335d75..863e125 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs @@ -9,6 +9,9 @@ public abstract partial class TmxReaderBase { internal List ReadProperties() { + if (!_reader.IsStartElement("properties")) + return []; + return _reader.ReadList("properties", "property", (r) => { var name = r.GetRequiredAttribute("name"); @@ -39,7 +42,8 @@ internal List ReadProperties() 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(), + PropertyType.Class => throw new XmlException("Class property must have a property type"), + PropertyType.Enum => throw new XmlException("Enum property must have a property type"), _ => throw new XmlException("Invalid property type") }; return property; @@ -49,7 +53,6 @@ internal List ReadProperties() internal IProperty ReadPropertyWithCustomType() { var isClass = _reader.GetOptionalAttribute("type") == "class"; - if (isClass) { return ReadClassProperty(); @@ -62,17 +65,24 @@ internal ClassProperty ReadClassProperty() { var name = _reader.GetRequiredAttribute("name"); var propertyType = _reader.GetRequiredAttribute("propertytype"); - var customTypeDef = _customTypeResolver(propertyType); + if (customTypeDef is CustomClassDefinition ccd) { - _reader.ReadStartElement("property"); - var propsInType = Helpers.CreateInstanceOfCustomClass(ccd); - var props = ReadProperties(); - var mergedProps = Helpers.MergeProperties(propsInType, props); - - _reader.ReadEndElement(); - return new ClassProperty { Name = name, PropertyType = propertyType, Value = mergedProps }; + if (!_reader.IsEmptyElement) + { + _reader.ReadStartElement("property"); + var propsInType = Helpers.CreateInstanceOfCustomClass(ccd, _customTypeResolver); + var props = ReadProperties(); + var mergedProps = Helpers.MergeProperties(propsInType, props); + _reader.ReadEndElement(); + return new ClassProperty { Name = name, PropertyType = propertyType, Value = mergedProps }; + } + else + { + var propsInType = Helpers.CreateInstanceOfCustomClass(ccd, _customTypeResolver); + return new ClassProperty { Name = name, PropertyType = propertyType, Value = propsInType }; + } } throw new XmlException($"Unkonwn custom class definition: {propertyType}"); From 39b7625c23a5dd40da3e58d53e6ee5f4bb5b894e Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Tue, 27 Aug 2024 22:31:48 +0200 Subject: [PATCH 17/23] Add NuGet metadata to library and add two new workflows for master pull requests and releases on github --- .github/workflows/master-pr.yml | 37 +++++++++++++++++++++++++++++ .github/workflows/release-nuget.yml | 30 +++++++++++++++++++++++ LICENSE | 21 ++++++++++++++++ Makefile | 5 +++- src/DotTiled/DotTiled.csproj | 21 ++++++++++++++++ 5 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/master-pr.yml create mode 100644 .github/workflows/release-nuget.yml create mode 100644 LICENSE diff --git a/.github/workflows/master-pr.yml b/.github/workflows/master-pr.yml new file mode 100644 index 0000000..1193a75 --- /dev/null +++ b/.github/workflows/master-pr.yml @@ -0,0 +1,37 @@ +on: + pull_request: + branches: + - master + +jobs: + check-pr-version: + runs-on: ubuntu-latest + steps: + - name: Checkout PR branch + uses: actions/checkout@v3 + + - name: Get version from PR branch + id: pr_version + run: | + PR_VERSION=$(grep '' **/*.csproj | sed -E 's/.*(.*)<\/Version>.*/\1/') + echo "PR_VERSION=$PR_VERSION" >> $GITHUB_ENV + + - name: Checkout master branch + run: | + git fetch origin master + git checkout origin/master + + - name: Get version from master branch + id: master_version + run: | + MASTER_VERSION=$(grep '' **/*.csproj | sed -E 's/.*(.*)<\/Version>.*/\1/') + echo "MASTER_VERSION=$MASTER_VERSION" >> $GITHUB_ENV + + - name: Compare versions + run: | + if [ "$(printf '%s\n' "$PR_VERSION" "$MASTER_VERSION" | sort -V | head -n1)" = "$PR_VERSION" ] && [ "$PR_VERSION" != "$MASTER_VERSION" ]; then + echo "Version in PR is not higher than master." + exit 1 + else + echo "Version in PR is higher than master." + fi diff --git a/.github/workflows/release-nuget.yml b/.github/workflows/release-nuget.yml new file mode 100644 index 0000000..cc90ca5 --- /dev/null +++ b/.github/workflows/release-nuget.yml @@ -0,0 +1,30 @@ +on: + release: + types: [published] + +jobs: + release-nuget: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + - name: Restore dependencies + run: dotnet restore src/DotTiled.sln + - name: Build + run: dotnet build --no-restore src/DotTiled.sln + - name: Test + run: dotnet test --no-build --verbosity normal src/DotTiled.sln + - name: Lint style + run: dotnet format style --verify-no-changes --verbosity diagnostic src/DotTiled.sln + - name: Lint analyzers + run: dotnet format analyzers --verify-no-changes --verbosity diagnostic src/DotTiled.sln + - name: Pack + run: make pack + - name: Publish to NuGet.org + run: | + dotnet nuget push ./nupkg/*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json --skip-duplicate + dotnet nuget push ./nupkg/*.snupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json --skip-duplicate diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c6014ab --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Daniel Cronqvist (daniel@dcronqvist.se) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Makefile b/Makefile index 14a40ab..601eda2 100644 --- a/Makefile +++ b/Makefile @@ -13,10 +13,13 @@ lint: dotnet format style --verify-no-changes src/DotTiled.sln dotnet format analyzers --verify-no-changes src/DotTiled.sln +pack: + dotnet pack src/DotTiled/DotTiled.csproj -c Release -o ./nupkg -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg + BENCHMARK_SOURCES = src/DotTiled.Benchmark/Program.cs src/DotTiled.Benchmark/DotTiled.Benchmark.csproj BENCHMARK_OUTPUTDIR = src/DotTiled.Benchmark/BenchmarkDotNet.Artifacts .PHONY: benchmark benchmark: $(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md - + $(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md: $(BENCHMARK_SOURCES) dotnet run --project src/DotTiled.Benchmark/DotTiled.Benchmark.csproj -c Release -- $(BENCHMARK_OUTPUTDIR) \ No newline at end of file diff --git a/src/DotTiled/DotTiled.csproj b/src/DotTiled/DotTiled.csproj index 0a2dfe8..d00569d 100644 --- a/src/DotTiled/DotTiled.csproj +++ b/src/DotTiled/DotTiled.csproj @@ -6,4 +6,25 @@ true + + DotTiled + dcronqvist + DotTiled + DotTiled is a general-purpose Tiled map parser for all your .NET needs. + git + https://github.com/dcronqvist/DotTiled + README.md + gamedev;window;parser;tiled;mapeditor + https://github.com/dcronqvist/DotTiled + true + Copyright © 2024 dcronqvist + LICENSE + 1.0.0 + + + + + + + From aa8b3904420f11dd4690c2079011670d73fce89a Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Wed, 28 Aug 2024 19:38:38 +0200 Subject: [PATCH 18/23] Add agnostic readers --- .../Serialization/MapReaderTests.cs | 50 ++++++++++ src/DotTiled/Serialization/Helpers.cs | 2 + src/DotTiled/Serialization/MapReader.cs | 92 +++++++++++++++++++ src/DotTiled/Serialization/TemplateReader.cs | 92 +++++++++++++++++++ src/DotTiled/Serialization/TilesetReader.cs | 92 +++++++++++++++++++ 5 files changed, 328 insertions(+) create mode 100644 src/DotTiled.Tests/Serialization/MapReaderTests.cs create mode 100644 src/DotTiled/Serialization/MapReader.cs create mode 100644 src/DotTiled/Serialization/TemplateReader.cs create mode 100644 src/DotTiled/Serialization/TilesetReader.cs diff --git a/src/DotTiled.Tests/Serialization/MapReaderTests.cs b/src/DotTiled.Tests/Serialization/MapReaderTests.cs new file mode 100644 index 0000000..c6e3ec7 --- /dev/null +++ b/src/DotTiled.Tests/Serialization/MapReaderTests.cs @@ -0,0 +1,50 @@ +using DotTiled.Model; +using DotTiled.Serialization; + +namespace DotTiled.Tests; + +public partial class MapReaderTests +{ + public static IEnumerable Maps => TestData.MapTests; + [Theory] + [MemberData(nameof(Maps))] + public void MapReaderReadMap_ValidFilesExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected( + string testDataFile, + Func expectedMap, + IReadOnlyCollection customTypeDefinitions) + { + // Arrange + string[] fileFormats = [".tmx", ".tmj"]; + + foreach (var fileFormat in fileFormats) + { + var testDataFileWithFormat = testDataFile + fileFormat; + var fileDir = Path.GetDirectoryName(testDataFileWithFormat); + var mapString = TestData.GetRawStringFor(testDataFileWithFormat); + Template ResolveTemplate(string source) + { + var templateString = TestData.GetRawStringFor($"{fileDir}/{source}"); + using var templateReader = new TemplateReader(templateString, ResolveTileset, ResolveTemplate, ResolveCustomType); + return templateReader.ReadTemplate(); + } + Tileset ResolveTileset(string source) + { + var tilesetString = TestData.GetRawStringFor($"{fileDir}/{source}"); + using var tilesetReader = new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType); + return tilesetReader.ReadTileset(); + } + ICustomTypeDefinition ResolveCustomType(string name) + { + return customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name)!; + } + using var mapReader = new MapReader(mapString, ResolveTileset, ResolveTemplate, ResolveCustomType); + + // Act + var map = mapReader.ReadMap(); + + // Assert + Assert.NotNull(map); + DotTiledAssert.AssertMap(expectedMap(fileFormat[1..]), map); + } + } +} diff --git a/src/DotTiled/Serialization/Helpers.cs b/src/DotTiled/Serialization/Helpers.cs index 1e95695..d47d627 100644 --- a/src/DotTiled/Serialization/Helpers.cs +++ b/src/DotTiled/Serialization/Helpers.cs @@ -151,4 +151,6 @@ internal static void SetAtMostOnceUsingCounter(ref T? field, T value, string field = value; counter++; } + + internal static bool StringIsXml(string s) => s.StartsWith(" +/// Reads a map from a string, regardless of format. +/// +public class MapReader : IMapReader +{ + // External resolvers + private readonly Func _externalTilesetResolver; + private readonly Func _externalTemplateResolver; + private readonly Func _customTypeResolver; + + private readonly StringReader? _mapStringReader; + private readonly XmlReader? _xmlReader; + private readonly IMapReader _mapReader; + private bool disposedValue; + + /// + /// Constructs a new , capable of reading a map from a string, regardless of format. + /// + /// The string containing the map data. + /// A function that resolves external tilesets given their source. + /// A function that resolves external templates given their source. + /// A function that resolves custom types given their source. + /// Thrown when any of the arguments are null. + public MapReader( + string map, + Func externalTilesetResolver, + Func externalTemplateResolver, + Func customTypeResolver) + { + _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); + _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); + _customTypeResolver = customTypeResolver ?? throw new ArgumentNullException(nameof(customTypeResolver)); + + // Prepare reader + if (Helpers.StringIsXml(map)) + { + _mapStringReader = new StringReader(map); + _xmlReader = XmlReader.Create(_mapStringReader); + _mapReader = new TmxMapReader(_xmlReader, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver); + } + else + { + _mapReader = new TmjMapReader(map, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver); + } + } + + /// + public Map ReadMap() => _mapReader.ReadMap(); + + /// + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: dispose managed state (managed objects) + _mapStringReader?.Dispose(); + _xmlReader?.Dispose(); + _mapReader.Dispose(); + } + + // TODO: free unmanaged resources (unmanaged objects) and override finalizer + // TODO: set large fields to null + disposedValue = true; + } + } + + // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources + // ~MapReader() + // { + // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + // Dispose(disposing: false); + // } + + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } +} diff --git a/src/DotTiled/Serialization/TemplateReader.cs b/src/DotTiled/Serialization/TemplateReader.cs new file mode 100644 index 0000000..f354c21 --- /dev/null +++ b/src/DotTiled/Serialization/TemplateReader.cs @@ -0,0 +1,92 @@ +using System; +using System.IO; +using System.Xml; +using DotTiled.Model; +using DotTiled.Serialization.Tmj; +using DotTiled.Serialization.Tmx; + +namespace DotTiled.Serialization; + +/// +/// Reads a template from a string, regardless of format. +/// +public class TemplateReader : ITemplateReader +{ + // External resolvers + private readonly Func _externalTilesetResolver; + private readonly Func _externalTemplateResolver; + private readonly Func _customTypeResolver; + + private readonly StringReader? _templateStringReader; + private readonly XmlReader? _xmlReader; + private readonly ITemplateReader _templateReader; + private bool disposedValue; + + /// + /// Constructs a new , capable of reading a template from a string, regardless of format. + /// + /// The string containing the template data. + /// A function that resolves external tilesets given their source. + /// A function that resolves external templates given their source. + /// A function that resolves custom types given their source. + /// Thrown when any of the arguments are null. + public TemplateReader( + string template, + Func externalTilesetResolver, + Func externalTemplateResolver, + Func customTypeResolver) + { + _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); + _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); + _customTypeResolver = customTypeResolver ?? throw new ArgumentNullException(nameof(customTypeResolver)); + + // Prepare reader + if (Helpers.StringIsXml(template)) + { + _templateStringReader = new StringReader(template); + _xmlReader = XmlReader.Create(_templateStringReader); + _templateReader = new TxTemplateReader(_xmlReader, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver); + } + else + { + _templateReader = new TjTemplateReader(template, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver); + } + } + + /// + public Template ReadTemplate() => _templateReader.ReadTemplate(); + + /// + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: dispose managed state (managed objects) + _templateStringReader?.Dispose(); + _xmlReader?.Dispose(); + _templateReader.Dispose(); + } + + // TODO: free unmanaged resources (unmanaged objects) and override finalizer + // TODO: set large fields to null + disposedValue = true; + } + } + + // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources + // ~MapReader() + // { + // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + // Dispose(disposing: false); + // } + + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } +} diff --git a/src/DotTiled/Serialization/TilesetReader.cs b/src/DotTiled/Serialization/TilesetReader.cs new file mode 100644 index 0000000..55f0099 --- /dev/null +++ b/src/DotTiled/Serialization/TilesetReader.cs @@ -0,0 +1,92 @@ +using System; +using System.IO; +using System.Xml; +using DotTiled.Model; +using DotTiled.Serialization.Tmj; +using DotTiled.Serialization.Tmx; + +namespace DotTiled.Serialization; + +/// +/// Reads a tileset from a string, regardless of format. +/// +public class TilesetReader : ITilesetReader +{ + // External resolvers + private readonly Func _externalTilesetResolver; + private readonly Func _externalTemplateResolver; + private readonly Func _customTypeResolver; + + private readonly StringReader? _tilesetStringReader; + private readonly XmlReader? _xmlReader; + private readonly ITilesetReader _tilesetReader; + private bool disposedValue; + + /// + /// Constructs a new , capable of reading a tileset from a string, regardless of format. + /// + /// The string containing the tileset data. + /// A function that resolves external tilesets given their source. + /// A function that resolves external templates given their source. + /// A function that resolves custom types given their source. + /// Thrown when any of the arguments are null. + public TilesetReader( + string tileset, + Func externalTilesetResolver, + Func externalTemplateResolver, + Func customTypeResolver) + { + _externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver)); + _externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver)); + _customTypeResolver = customTypeResolver ?? throw new ArgumentNullException(nameof(customTypeResolver)); + + // Prepare reader + if (Helpers.StringIsXml(tileset)) + { + _tilesetStringReader = new StringReader(tileset); + _xmlReader = XmlReader.Create(_tilesetStringReader); + _tilesetReader = new TsxTilesetReader(_xmlReader, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver); + } + else + { + _tilesetReader = new TsjTilesetReader(tileset, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver); + } + } + + /// + public Tileset ReadTileset() => _tilesetReader.ReadTileset(); + + /// + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: dispose managed state (managed objects) + _tilesetStringReader?.Dispose(); + _xmlReader?.Dispose(); + _tilesetReader.Dispose(); + } + + // TODO: free unmanaged resources (unmanaged objects) and override finalizer + // TODO: set large fields to null + disposedValue = true; + } + } + + // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources + // ~MapReader() + // { + // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + // Dispose(disposing: false); + // } + + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } +} From a9ad1840b022e018750b3239889cb63b1b7a583a Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Wed, 28 Aug 2024 16:53:49 +0200 Subject: [PATCH 19/23] Add some docs --- .../{ => essentials}/custom-properties.md | 4 +- docs/docs/essentials/loading-maps.md | 43 +++++++++++++++++++ docs/docs/loading-a-map.md | 1 - docs/docs/toc.yml | 4 +- 4 files changed, 47 insertions(+), 5 deletions(-) rename docs/docs/{ => essentials}/custom-properties.md (96%) create mode 100644 docs/docs/essentials/loading-maps.md delete mode 100644 docs/docs/loading-a-map.md diff --git a/docs/docs/custom-properties.md b/docs/docs/essentials/custom-properties.md similarity index 96% rename from docs/docs/custom-properties.md rename to docs/docs/essentials/custom-properties.md index 78cbd00..934882c 100644 --- a/docs/docs/custom-properties.md +++ b/docs/docs/essentials/custom-properties.md @@ -78,7 +78,7 @@ Whenever DotTiled encounters a property that is of type `class` in a Tiled file, For example, if you have a `class` property in Tiled that looks like this: -![MonsterSpawner class in Tiled UI](../images/monster-spawner-class.png) +![MonsterSpawner class in Tiled UI](../../images/monster-spawner-class.png) The equivalent definition in DotTiled would look like the following: @@ -102,7 +102,7 @@ Tiled also allows you to define custom property types that work as enums. Simila For example, if you have a custom property type in Tiled that looks like this: -![EntityType enum in Tiled UI](../images/entity-type-enum.png) +![EntityType enum in Tiled UI](../../images/entity-type-enum.png) The equivalent definition in DotTiled would look like the following: diff --git a/docs/docs/essentials/loading-maps.md b/docs/docs/essentials/loading-maps.md new file mode 100644 index 0000000..d9db195 --- /dev/null +++ b/docs/docs/essentials/loading-maps.md @@ -0,0 +1,43 @@ +# Loading maps + +Loading maps with DotTiled is straightforward and easy. The class is a representation of a Tiled map, mimicking the structure of a Tiled map file. Map files can either be in the [`.tmx`/XML](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/) or [`.tmj`/json](https://doc.mapeditor.org/en/stable/reference/json-map-format/) format. DotTiled supports **both** formats fully. + +> [!TIP] +> Using the `.tmj` file format will result in not having the same amount of information as for `.tmx` format. This is due to the fact that the `.tmj` format does not include the full information that the `.tmx` format does. This is not a problem with DotTiled, but rather a limitation of the `.tmj` format. + +## External resolution + +Tiled maps may consist of several external files, such as tilesets and object templates. In Tiled map files, these are typically referenced by their path relative to the map file. It would be annoying to have to first load all these external resources before loading a map, so loading a map with DotTiled is designed in a way that you only have to provide a function that resolves these external resources. This way, DotTiled will figure out which external resources are needed and will invoke the corresponding resolver function to load them. + +Loading a map, tileset, or template will require you to specify **three** resolver functions + +### `Func` - Tileset resolver + +This function is used to resolve external tilesets by their source path. The function should return a instance given the source path of the tileset. If you just want to load tilesets from the file system, you can use something like this: + +```csharp +Tileset ResolveTileset(string source) +{ + +} +``` + +- `Func` - Template resolver, which resolves a template by its source path +- `Func` - Custom type resolver, which resolves a custom type by its name + +The first two resolver functions are used to resolve external tilesets and object templates. The third resolver function is used to resolve custom types that are defined in Tiled maps. Please refer to the [custom properties](custom-properties.md) documentation for more information on custom types. + + +------------- + +### [OLD] + +To be completely agnostic about how you may store/retrieve your tilesets, DotTiled will invoke a supplied `Func` where you can resolve the tileset by its source path. This is useful for scenarios where you may want to load tilesets in custom ways, such as from a database or a custom file format. + +```csharp +Tileset ResolveTileset(string source) +{ + var xmlStringReader = CustomContentManager.ReadString(source); + var xmlReader = XmlReader.Create(xmlStringReader); + var tilesetReader = new TmxTilesetReader(xmlReader, ResolveTileset, ResolveTemplate, ResolveCustomType); +} \ No newline at end of file diff --git a/docs/docs/loading-a-map.md b/docs/docs/loading-a-map.md deleted file mode 100644 index 9a7dc64..0000000 --- a/docs/docs/loading-a-map.md +++ /dev/null @@ -1 +0,0 @@ -# Loading a map \ No newline at end of file diff --git a/docs/docs/toc.yml b/docs/docs/toc.yml index 62d2c9d..6a04547 100644 --- a/docs/docs/toc.yml +++ b/docs/docs/toc.yml @@ -3,5 +3,5 @@ - href: quickstart.md - name: Essentials -- href: loading-a-map.md -- href: custom-properties.md \ No newline at end of file +- href: essentials/loading-maps.md +- href: essentials/custom-properties.md \ No newline at end of file From b9b5f7fc1c74de5ca65adf39d61e95575cb50217 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Wed, 28 Aug 2024 23:37:50 +0200 Subject: [PATCH 20/23] More docs --- docs/docs/essentials/loading-maps.md | 75 ++++++++++++++++++++++------ docs/docs/quickstart.md | 47 ++++++++++++++++- 2 files changed, 105 insertions(+), 17 deletions(-) diff --git a/docs/docs/essentials/loading-maps.md b/docs/docs/essentials/loading-maps.md index d9db195..c1598ec 100644 --- a/docs/docs/essentials/loading-maps.md +++ b/docs/docs/essentials/loading-maps.md @@ -2,14 +2,14 @@ Loading maps with DotTiled is straightforward and easy. The class is a representation of a Tiled map, mimicking the structure of a Tiled map file. Map files can either be in the [`.tmx`/XML](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/) or [`.tmj`/json](https://doc.mapeditor.org/en/stable/reference/json-map-format/) format. DotTiled supports **both** formats fully. -> [!TIP] -> Using the `.tmj` file format will result in not having the same amount of information as for `.tmx` format. This is due to the fact that the `.tmj` format does not include the full information that the `.tmx` format does. This is not a problem with DotTiled, but rather a limitation of the `.tmj` format. +> [!NOTE] +> Using the `.tmj` file format will result in not having the same amount of information as for the `.tmx` format. This is due to the fact that the `.tmj` format does not include the full information that the `.tmx` format does. This is not a problem with DotTiled, but rather a limitation of the `.tmj` format. ## External resolution -Tiled maps may consist of several external files, such as tilesets and object templates. In Tiled map files, these are typically referenced by their path relative to the map file. It would be annoying to have to first load all these external resources before loading a map, so loading a map with DotTiled is designed in a way that you only have to provide a function that resolves these external resources. This way, DotTiled will figure out which external resources are needed and will invoke the corresponding resolver function to load them. +Tiled maps may consist of several external files, such as tilesets or object templates. In Tiled map files, they are typically referenced by their path relative to the map file. It would be annoying to have to first load all these external resources before loading a map (which is how some other similar libraries work), so loading a map with DotTiled is designed in a way that you only have to provide a function that resolves these external resources. This way, DotTiled will figure out which external resources are needed and will invoke the corresponding resolver function to load them. -Loading a map, tileset, or template will require you to specify **three** resolver functions +Loading a map, tileset, or template will require you to specify **three** resolver functions. We'll go through each of them below. ### `Func` - Tileset resolver @@ -18,26 +18,69 @@ This function is used to resolve external tilesets by their source path. The fun ```csharp Tileset ResolveTileset(string source) { - + using var tilesetFileReader = new StreamReader(source); + var tilesetString = tilesetReader.ReadToEnd(); + using var tilesetReader = new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType); + return tilesetReader.ReadTileset(); } ``` -- `Func` - Template resolver, which resolves a template by its source path -- `Func` - Custom type resolver, which resolves a custom type by its name +But, DotTiled is designed this way so you can retrieve your external resources from anywhere, such as a database or a custom file format, by implementing your own resolver function however you like. If you have some other means of accessing resources, you can use that instead of the file system. -The first two resolver functions are used to resolve external tilesets and object templates. The third resolver function is used to resolve custom types that are defined in Tiled maps. Please refer to the [custom properties](custom-properties.md) documentation for more information on custom types. +```csharp +Tileset ResolveTileset(string source) +{ + var tilesetString = ContentManager.GetString($"tilesets/{source}"); + using var tilesetReader = new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType); + return tilesetReader.ReadTileset(); +} +``` +### `Func` - Template resolver -------------- - -### [OLD] +This function is used to resolve external object templates by their source path. The function should return a instance given the source path of the template. If you just want to load templates from the file system, you can use something very similar to the tileset resolver by replacing with . -To be completely agnostic about how you may store/retrieve your tilesets, DotTiled will invoke a supplied `Func` where you can resolve the tileset by its source path. This is useful for scenarios where you may want to load tilesets in custom ways, such as from a database or a custom file format. +### `Func` - Custom type resolver + +This function is used to resolve custom types that are defined in Tiled maps. Please refer to the [custom properties](custom-properties.md) documentation for more information on custom types. The function should return a instance given the custom type's name. + +## Putting it all together + +The following classes are the readers that you will need to use to read the map, tileset, and template: , , and . + +Here is an example of how you can load a map with DotTiled: ```csharp +string mapPath = "path/to/map.tmx"; +string mapDirectory = Path.GetDirectoryName(mapPath); + Tileset ResolveTileset(string source) { - var xmlStringReader = CustomContentManager.ReadString(source); - var xmlReader = XmlReader.Create(xmlStringReader); - var tilesetReader = new TmxTilesetReader(xmlReader, ResolveTileset, ResolveTemplate, ResolveCustomType); -} \ No newline at end of file + string tilesetPath = Path.Combine(mapDirectory, source); + using var tilesetFileReader = new StreamReader(tilesetPath); + var tilesetString = tilesetReader.ReadToEnd(); + using var tilesetReader = new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType); + return tilesetReader.ReadTileset(); +} + +Template ResolveTemplate(string source) +{ + string templatePath = Path.Combine(mapDirectory, source); + using var templateFileReader = new StreamReader(templatePath); + var templateString = templateReader.ReadToEnd(); + using var templateReader = new TemplateReader(templateString, ResolveTileset, ResolveTemplate, ResolveCustomType); + return templateReader.ReadTemplate(); +} + +ICustomTypeDefinition ResolveCustomType(string name) +{ + var allDefinedTypes = [ ... ]; + return allDefinedTypes.FirstOrDefault(type => type.Name == name); +} + +using var mapFileReader = new StreamReader(mapPath); +var mapString = mapFileReader.ReadToEnd(); +using var mapReader = new MapReader(mapString, ResolveTileset, ResolveTemplate, ResolveCustomType); + +var map = mapReader.ReadMap(); +``` \ No newline at end of file diff --git a/docs/docs/quickstart.md b/docs/docs/quickstart.md index 1d2e852..8d067eb 100644 --- a/docs/docs/quickstart.md +++ b/docs/docs/quickstart.md @@ -1 +1,46 @@ -# Quick Start \ No newline at end of file +# Quick Start + +Install DotTiled from NuGet: + +```bash +dotnet add package DotTiled +``` + +Load a map from file system: + +```csharp +string mapPath = "path/to/map.tmx"; +string mapDirectory = Path.GetDirectoryName(mapPath); + +Tileset ResolveTileset(string source) +{ + string tilesetPath = Path.Combine(mapDirectory, source); + using var tilesetFileReader = new StreamReader(tilesetPath); + var tilesetString = tilesetReader.ReadToEnd(); + using var tilesetReader = new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType); + return tilesetReader.ReadTileset(); +} + +Template ResolveTemplate(string source) +{ + string templatePath = Path.Combine(mapDirectory, source); + using var templateFileReader = new StreamReader(templatePath); + var templateString = templateReader.ReadToEnd(); + using var templateReader = new TemplateReader(templateString, ResolveTileset, ResolveTemplate, ResolveCustomType); + return templateReader.ReadTemplate(); +} + +ICustomTypeDefinition ResolveCustomType(string name) +{ + var allDefinedTypes = [ ... ]; + return allDefinedTypes.FirstOrDefault(type => type.Name == name); +} + +using var mapFileReader = new StreamReader(mapPath); +var mapString = mapFileReader.ReadToEnd(); +using var mapReader = new MapReader(mapString, ResolveTileset, ResolveTemplate, ResolveCustomType); + +var map = mapReader.ReadMap(); +``` + +If the above looks intimidating, don't worry! DotTiled is designed to be flexible and allow you to load maps from any source, such as a database or a custom file format. The above example is just one way to load a map from a file system. Please look at [Loading Maps](essentials/loading-maps.md) for more information on how to load maps from different sources. \ No newline at end of file From 3ea0e6ca13ef2d37c50c67a3fbc4cb9ead8119ee Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Fri, 30 Aug 2024 19:48:24 +0200 Subject: [PATCH 21/23] Update README --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 48772d1..8739d03 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ DotTiled is a simple and easy-to-use library for loading, saving, and managing [Tiled maps and tilesets](https://mapeditor.org) in your .NET projects. After [TiledCS](https://github.com/TheBoneJarmer/TiledCS) unfortunately became unmaintained (since 2022), I aimed to create a new library that could fill its shoes. DotTiled is the result of that effort. -DotTiled is designed to be a lightweight and efficient library that provides a simple API for loading and managing Tiled maps and tilesets. It is built with performance in mind and aims to be as fast and memory-efficient as possible. Targeting `netstandard2.0` and `net8.0` allows DotTiled to be used in popular game engines like Unity and Godot, as well as in popular game development frameworks like MonoGame. +DotTiled is designed to be a lightweight and efficient library that provides a simple API for loading and managing Tiled maps and tilesets. It is built with performance in mind and aims to be as fast and memory-efficient as possible. - [Alternative libraries and comparison + benchmarks](#alternative-libraries-and-comparison) - [Feature coverage comparison](#feature-coverage-comparison) -- [Installing DotTiled](#installing-dottiled) +- [Quick Start](#quick-start) # Alternative libraries and comparison @@ -20,7 +20,7 @@ Other similar libraries exist, and you may want to consider them for your projec | Benchmark (time)* | 1.00 | 1.83 | 2.16 | - | - | - | | Benchmark (memory)* | 1.00 | 1.43 | 2.03 | - | - | - | | .NET Targets | `net8.0` |`net6.0`
`net7.0`|`netstandard2.1`|`netstandard2.0`|`netstandard2.0`|`net45`| -| Docs |Usage,
XML Docs|Usage|Usage, API,
XML Docs|Usage, API|Usage, XML Docs|Usage, XML Docs| +| Docs |Usage, API,
XML Docs|Usage|Usage, API,
XML Docs|Usage, API|Usage, XML Docs|Usage, XML Docs| | License | MIT | MIT | MIT | Apache-2.0 | MIT | BSD 3-Clause | > [!NOTE] @@ -73,10 +73,12 @@ Below is a comparison of the feature coverage of DotTiled and other similar libr > [!NOTE] > ✅ Full support. ⚠️ Partial support, see respective library for details about supported features. ❌ No support. -# Installing DotTiled +# Quick Start DotTiled is available as a NuGet package. You can install it by using the NuGet Package Manager UI in Visual Studio, or equivalent, or using the following command for the .NET CLI: ```pwsh dotnet add package DotTiled ``` + +Then head to the detailed [documentation](https://dcronqvist.github.io/DotTiled/docs/quickstart.html) for more information on how to use DotTiled in your project. From d85494e7a98ae461a11490f5df3970989df63593 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Fri, 30 Aug 2024 20:11:33 +0200 Subject: [PATCH 22/23] Remove .Model namespace as it is unnecessary --- docs/docs/essentials/custom-properties.md | 76 +++++++++---------- docs/docs/essentials/loading-maps.md | 10 +-- src/DotTiled.Benchmark/Program.cs | 4 +- src/DotTiled.Tests/Assert/AssertData.cs | 2 - src/DotTiled.Tests/Assert/AssertImage.cs | 2 - src/DotTiled.Tests/Assert/AssertLayer.cs | 2 - src/DotTiled.Tests/Assert/AssertMap.cs | 1 - src/DotTiled.Tests/Assert/AssertObject.cs | 26 +++---- src/DotTiled.Tests/Assert/AssertProperties.cs | 2 - src/DotTiled.Tests/Assert/AssertTileset.cs | 2 - .../Serialization/MapReaderTests.cs | 1 - src/DotTiled.Tests/Serialization/TestData.cs | 1 - .../TestData/Map/default-map/default-map.cs | 2 - .../map-external-tileset-multi.cs | 1 - .../map-external-tileset-wangset.cs | 1 - .../map-with-common-props.cs | 1 - .../map-with-custom-type-props.cs | 1 - .../map-with-deep-props.cs | 1 - .../map-with-embedded-tileset.cs | 1 - .../map-with-external-tileset.cs | 1 - .../map-with-flippingflags.cs | 1 - .../map-with-many-layers.cs | 1 - .../Serialization/Tmj/TmjMapReaderTests.cs | 1 - .../Serialization/Tmx/TmxMapReaderTests.cs | 1 - src/DotTiled/{Model => }/Color.cs | 2 +- src/DotTiled/{Model => }/Layers/BaseLayer.cs | 2 +- src/DotTiled/{Model => }/Layers/Data.cs | 2 +- src/DotTiled/{Model => }/Layers/Group.cs | 2 +- src/DotTiled/{Model => }/Layers/ImageLayer.cs | 2 +- .../{Model => }/Layers/ObjectLayer.cs | 2 +- .../Layers/Objects/EllipseObject.cs | 2 +- .../{Model => }/Layers/Objects/Object.cs | 2 +- .../{Model => }/Layers/Objects/PointObject.cs | 2 +- .../Layers/Objects/PolygonObject.cs | 2 +- .../Layers/Objects/PolylineObject.cs | 2 +- .../Layers/Objects/RectangleObject.cs | 2 +- .../{Model => }/Layers/Objects/TextObject.cs | 2 +- .../{Model => }/Layers/Objects/TileObject.cs | 2 +- src/DotTiled/{Model => }/Layers/TileLayer.cs | 2 +- src/DotTiled/{Model => }/Map.cs | 2 +- .../{Model => }/Properties/BoolProperty.cs | 2 +- .../{Model => }/Properties/ClassProperty.cs | 4 +- .../{Model => }/Properties/ColorProperty.cs | 2 +- .../CustomTypes/CustomClassDefinition.cs | 2 +- .../CustomTypes/CustomEnumDefinition.cs | 2 +- .../CustomTypes/CustomTypeDefinition.cs | 2 +- .../{Model => }/Properties/EnumProperty.cs | 4 +- .../{Model => }/Properties/FileProperty.cs | 2 +- .../{Model => }/Properties/FloatProperty.cs | 2 +- .../{Model => }/Properties/IHasProperties.cs | 2 +- .../{Model => }/Properties/IProperty.cs | 2 +- .../{Model => }/Properties/IntProperty.cs | 2 +- .../{Model => }/Properties/ObjectProperty.cs | 2 +- .../{Model => }/Properties/PropertyType.cs | 2 +- .../{Model => }/Properties/StringProperty.cs | 2 +- src/DotTiled/Serialization/Helpers.cs | 1 - src/DotTiled/Serialization/IMapReader.cs | 1 - src/DotTiled/Serialization/ITemplateReader.cs | 1 - src/DotTiled/Serialization/ITilesetReader.cs | 1 - src/DotTiled/Serialization/MapReader.cs | 1 - src/DotTiled/Serialization/TemplateReader.cs | 1 - src/DotTiled/Serialization/TilesetReader.cs | 1 - .../Serialization/Tmj/TjTemplateReader.cs | 1 - .../Serialization/Tmj/TmjMapReader.cs | 1 - .../Serialization/Tmj/TmjReaderBase.Data.cs | 1 - .../Serialization/Tmj/TmjReaderBase.Group.cs | 1 - .../Tmj/TmjReaderBase.ImageLayer.cs | 1 - .../Serialization/Tmj/TmjReaderBase.Layer.cs | 1 - .../Serialization/Tmj/TmjReaderBase.Map.cs | 1 - .../Tmj/TmjReaderBase.ObjectLayer.cs | 5 +- .../Tmj/TmjReaderBase.Properties.cs | 1 - .../Tmj/TmjReaderBase.Template.cs | 3 +- .../Tmj/TmjReaderBase.TileLayer.cs | 1 - .../Tmj/TmjReaderBase.Tileset.cs | 1 - .../Serialization/Tmj/TmjReaderBase.cs | 1 - .../Serialization/Tmj/TsjTilesetReader.cs | 1 - .../Serialization/Tmx/TmxMapReader.cs | 1 - .../Serialization/Tmx/TmxReaderBase.Chunk.cs | 2 - .../Serialization/Tmx/TmxReaderBase.Data.cs | 1 - .../Serialization/Tmx/TmxReaderBase.Map.cs | 1 - .../Tmx/TmxReaderBase.ObjectLayer.cs | 13 ++-- .../Tmx/TmxReaderBase.Properties.cs | 1 - .../Tmx/TmxReaderBase.TileLayer.cs | 1 - .../Tmx/TmxReaderBase.Tileset.cs | 1 - .../Serialization/Tmx/TmxReaderBase.cs | 1 - .../Serialization/Tmx/TsxTilesetReader.cs | 1 - .../Serialization/Tmx/TxTemplateReader.cs | 1 - src/DotTiled/{Model => }/Template.cs | 4 +- src/DotTiled/{Model => }/Tilesets/Frame.cs | 2 +- src/DotTiled/{Model => }/Tilesets/Grid.cs | 2 +- src/DotTiled/{Model => }/Tilesets/Image.cs | 2 +- src/DotTiled/{Model => }/Tilesets/Tile.cs | 2 +- .../{Model => }/Tilesets/TileOffset.cs | 2 +- src/DotTiled/{Model => }/Tilesets/Tileset.cs | 2 +- .../{Model => }/Tilesets/Transformations.cs | 2 +- .../{Model => }/Tilesets/WangColor.cs | 2 +- src/DotTiled/{Model => }/Tilesets/WangTile.cs | 2 +- src/DotTiled/{Model => }/Tilesets/Wangset.cs | 2 +- 98 files changed, 112 insertions(+), 171 deletions(-) rename src/DotTiled/{Model => }/Color.cs (99%) rename src/DotTiled/{Model => }/Layers/BaseLayer.cs (98%) rename src/DotTiled/{Model => }/Layers/Data.cs (99%) rename src/DotTiled/{Model => }/Layers/Group.cs (91%) rename src/DotTiled/{Model => }/Layers/ImageLayer.cs (96%) rename src/DotTiled/{Model => }/Layers/ObjectLayer.cs (98%) rename src/DotTiled/{Model => }/Layers/Objects/EllipseObject.cs (91%) rename src/DotTiled/{Model => }/Layers/Objects/Object.cs (98%) rename src/DotTiled/{Model => }/Layers/Objects/PointObject.cs (89%) rename src/DotTiled/{Model => }/Layers/Objects/PolygonObject.cs (95%) rename src/DotTiled/{Model => }/Layers/Objects/PolylineObject.cs (95%) rename src/DotTiled/{Model => }/Layers/Objects/RectangleObject.cs (91%) rename src/DotTiled/{Model => }/Layers/Objects/TextObject.cs (98%) rename src/DotTiled/{Model => }/Layers/Objects/TileObject.cs (87%) rename src/DotTiled/{Model => }/Layers/TileLayer.cs (96%) rename src/DotTiled/{Model => }/Map.cs (99%) rename src/DotTiled/{Model => }/Properties/BoolProperty.cs (94%) rename src/DotTiled/{Model => }/Properties/ClassProperty.cs (95%) rename src/DotTiled/{Model => }/Properties/ColorProperty.cs (94%) rename src/DotTiled/{Model => }/Properties/CustomTypes/CustomClassDefinition.cs (98%) rename src/DotTiled/{Model => }/Properties/CustomTypes/CustomEnumDefinition.cs (97%) rename src/DotTiled/{Model => }/Properties/CustomTypes/CustomTypeDefinition.cs (92%) rename src/DotTiled/{Model => }/Properties/EnumProperty.cs (95%) rename src/DotTiled/{Model => }/Properties/FileProperty.cs (94%) rename src/DotTiled/{Model => }/Properties/FloatProperty.cs (94%) rename src/DotTiled/{Model => }/Properties/IHasProperties.cs (98%) rename src/DotTiled/{Model => }/Properties/IProperty.cs (97%) rename src/DotTiled/{Model => }/Properties/IntProperty.cs (94%) rename src/DotTiled/{Model => }/Properties/ObjectProperty.cs (95%) rename src/DotTiled/{Model => }/Properties/PropertyType.cs (96%) rename src/DotTiled/{Model => }/Properties/StringProperty.cs (94%) rename src/DotTiled/{Model => }/Template.cs (80%) rename src/DotTiled/{Model => }/Tilesets/Frame.cs (93%) rename src/DotTiled/{Model => }/Tilesets/Grid.cs (96%) rename src/DotTiled/{Model => }/Tilesets/Image.cs (97%) rename src/DotTiled/{Model => }/Tilesets/Tile.cs (98%) rename src/DotTiled/{Model => }/Tilesets/TileOffset.cs (93%) rename src/DotTiled/{Model => }/Tilesets/Tileset.cs (99%) rename src/DotTiled/{Model => }/Tilesets/Transformations.cs (96%) rename src/DotTiled/{Model => }/Tilesets/WangColor.cs (97%) rename src/DotTiled/{Model => }/Tilesets/WangTile.cs (92%) rename src/DotTiled/{Model => }/Tilesets/Wangset.cs (97%) diff --git a/docs/docs/essentials/custom-properties.md b/docs/docs/essentials/custom-properties.md index 934882c..b18ba7f 100644 --- a/docs/docs/essentials/custom-properties.md +++ b/docs/docs/essentials/custom-properties.md @@ -4,40 +4,40 @@ ## All classes that can contain properties -All classes that can contain custom properties implement the interface in some way. Below is an exhaustive list of all classes that can contain custom properties: - -- - - - - - - - - -- (allows for recursive property objects) -- (used to define custom Tiled property types) -- - - - - - - - - - - - - - - -- -- -- -- +All classes that can contain custom properties implement the interface in some way. Below is an exhaustive list of all classes that can contain custom properties: + +- + - + - + - + - +- (allows for recursive property objects) +- (used to define custom Tiled property types) +- + - + - + - + - + - + - + - +- +- +- +- ## How to access properties -To access the properties on one of the classes listed above, you will make use of the interface. +To access the properties on one of the classes listed above, you will make use of the interface. -In situations where you know that a property must exist, and you simply want to retrieve it, you can use the method like so: +In situations where you know that a property must exist, and you simply want to retrieve it, you can use the method like so: ```csharp var map = LoadMap(); var propertyValue = map.GetProperty("boolPropertyInMap").Value; ``` -If you are unsure whether a property exists, or you want to provide some kind of default behaviour if the property is not present, you can instead use the method like so: +If you are unsure whether a property exists, or you want to provide some kind of default behaviour if the property is not present, you can instead use the method like so: ```csharp var map = LoadMap(); @@ -56,17 +56,17 @@ For both methods, you can replace `BoolProperty` with any of the property types ## All types of properties -Tiled supports a variety of property types, which are represented in the DotTiled library as classes that implement the interface. Below is a list of all property types that Tiled supports and their corresponding classes in DotTiled: +Tiled supports a variety of property types, which are represented in the DotTiled library as classes that implement the interface. Below is a list of all property types that Tiled supports and their corresponding classes in DotTiled: -- `bool` - -- `color` - -- `float` - -- `file` - -- `int` - -- `object` - -- `string` - +- `bool` - +- `color` - +- `float` - +- `file` - +- `int` - +- `object` - +- `string` - -In addition to these primitive property types, [Tiled also supports more complex property types](https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-types). These custom property types are defined in Tiled according to the linked documentation, and to work with them in DotTiled, you *must* define their equivalences as a . You must then provide a resolving function to a defined type given a custom type name, as it is defined in Tiled. +In addition to these primitive property types, [Tiled also supports more complex property types](https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-types). These custom property types are defined in Tiled according to the linked documentation, and to work with them in DotTiled, you *must* define their equivalences as a . You must then provide a resolving function to a defined type given a custom type name, as it is defined in Tiled. ## Custom types @@ -74,7 +74,7 @@ Tiled allows you to define custom property types that can be used in your maps. ### Class properties -Whenever DotTiled encounters a property that is of type `class` in a Tiled file, it will use the supplied custom type resolver function to retrieve the custom type definition. It will then use that definition to know the default values of the properties of that class, and then override those defaults with the values found in the Tiled file when populating a instance. `class` properties allow you to create hierarchical structures of properties. +Whenever DotTiled encounters a property that is of type `class` in a Tiled file, it will use the supplied custom type resolver function to retrieve the custom type definition. It will then use that definition to know the default values of the properties of that class, and then override those defaults with the values found in the Tiled file when populating a instance. `class` properties allow you to create hierarchical structures of properties. For example, if you have a `class` property in Tiled that looks like this: @@ -98,7 +98,7 @@ var monsterSpawnerDefinition = new CustomClassDefinition ### Enum properties -Tiled also allows you to define custom property types that work as enums. Similarly to `class` properties, you must define the equivalent in DotTiled as a . You can then return the corresponding definition in the resolving function. +Tiled also allows you to define custom property types that work as enums. Similarly to `class` properties, you must define the equivalent in DotTiled as a . You can then return the corresponding definition in the resolving function. For example, if you have a custom property type in Tiled that looks like this: @@ -125,9 +125,9 @@ var entityTypeDefinition = new CustomEnumDefinition In the future, DotTiled will support automatically mapping custom property `class` types to C# classes. This will allow you to define a C# class that matches the structure of the `class` property in Tiled, and DotTiled will automatically map the properties of the `class` property to the properties of the C# class. This will make working with `class` properties much easier and more intuitive. -The idea is to expand on the interface with a method like `GetMappedProperty(string propertyName)`, where `T` is a class that matches the structure of the `class` property in Tiled. +The idea is to expand on the interface with a method like `GetMappedProperty(string propertyName)`, where `T` is a class that matches the structure of the `class` property in Tiled. -This functionality would be accompanied by a way to automatically create a matching given a C# class or enum. Something like this would then be possible: +This functionality would be accompanied by a way to automatically create a matching given a C# class or enum. Something like this would then be possible: ```csharp class MonsterSpawner @@ -156,6 +156,6 @@ var monsterSpawner = map.GetMappedProperty("monsterSpawnerProper var entityType = map.GetMappedProperty("entityTypePropertyInMap"); ``` -Finally, it might be possible to also make some kind of exporting functionality for . Given a collection of custom type definitions, DotTiled could generate a corresponding `propertytypes.json` file that you then can import into Tiled. This would make it so that you only have to define your custom property types once (in C#) and then import them into Tiled to use them in your maps. +Finally, it might be possible to also make some kind of exporting functionality for . Given a collection of custom type definitions, DotTiled could generate a corresponding `propertytypes.json` file that you then can import into Tiled. This would make it so that you only have to define your custom property types once (in C#) and then import them into Tiled to use them in your maps. Depending on implementation this might become something that can inhibit native AOT compilation due to potential reflection usage. Source generators could be used to mitigate this, but it is not yet clear how this will be implemented. \ No newline at end of file diff --git a/docs/docs/essentials/loading-maps.md b/docs/docs/essentials/loading-maps.md index c1598ec..b34b964 100644 --- a/docs/docs/essentials/loading-maps.md +++ b/docs/docs/essentials/loading-maps.md @@ -1,9 +1,9 @@ # Loading maps -Loading maps with DotTiled is straightforward and easy. The class is a representation of a Tiled map, mimicking the structure of a Tiled map file. Map files can either be in the [`.tmx`/XML](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/) or [`.tmj`/json](https://doc.mapeditor.org/en/stable/reference/json-map-format/) format. DotTiled supports **both** formats fully. +Loading maps with DotTiled is straightforward and easy. The class is a representation of a Tiled map, mimicking the structure of a Tiled map file. Map files can either be in the [`.tmx`/XML](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/) or [`.tmj`/json](https://doc.mapeditor.org/en/stable/reference/json-map-format/) format. DotTiled supports **both** formats fully. > [!NOTE] -> Using the `.tmj` file format will result in not having the same amount of information as for the `.tmx` format. This is due to the fact that the `.tmj` format does not include the full information that the `.tmx` format does. This is not a problem with DotTiled, but rather a limitation of the `.tmj` format. +> Using the `.tmj` file format will result in not having the same amount of information as for the `.tmx` format. This is due to the fact that the `.tmj` format does not include the full information that the `.tmx` format does. This is not a problem with DotTiled, but rather a limitation of the `.tmj` format. ## External resolution @@ -13,7 +13,7 @@ Loading a map, tileset, or template will require you to specify **three** resolv ### `Func` - Tileset resolver -This function is used to resolve external tilesets by their source path. The function should return a instance given the source path of the tileset. If you just want to load tilesets from the file system, you can use something like this: +This function is used to resolve external tilesets by their source path. The function should return a instance given the source path of the tileset. If you just want to load tilesets from the file system, you can use something like this: ```csharp Tileset ResolveTileset(string source) @@ -38,11 +38,11 @@ Tileset ResolveTileset(string source) ### `Func` - Template resolver -This function is used to resolve external object templates by their source path. The function should return a instance given the source path of the template. If you just want to load templates from the file system, you can use something very similar to the tileset resolver by replacing with . +This function is used to resolve external object templates by their source path. The function should return a instance given the source path of the template. If you just want to load templates from the file system, you can use something very similar to the tileset resolver by replacing with . ### `Func` - Custom type resolver -This function is used to resolve custom types that are defined in Tiled maps. Please refer to the [custom properties](custom-properties.md) documentation for more information on custom types. The function should return a instance given the custom type's name. +This function is used to resolve custom types that are defined in Tiled maps. Please refer to the [custom properties](custom-properties.md) documentation for more information on custom types. The function should return a instance given the custom type's name. ## Putting it all together diff --git a/src/DotTiled.Benchmark/Program.cs b/src/DotTiled.Benchmark/Program.cs index 523a7f1..40e695b 100644 --- a/src/DotTiled.Benchmark/Program.cs +++ b/src/DotTiled.Benchmark/Program.cs @@ -35,7 +35,7 @@ public MapLoading() [BenchmarkCategory("MapFromInMemoryTmxString")] [Benchmark(Baseline = true, Description = "DotTiled")] - public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmxString() + public DotTiled.Map LoadWithDotTiledFromInMemoryTmxString() { using var stringReader = new StringReader(_tmxContents); using var xmlReader = XmlReader.Create(stringReader); @@ -45,7 +45,7 @@ public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmxString() [BenchmarkCategory("MapFromInMemoryTmjString")] [Benchmark(Baseline = true, Description = "DotTiled")] - public DotTiled.Model.Map LoadWithDotTiledFromInMemoryTmjString() + public DotTiled.Map LoadWithDotTiledFromInMemoryTmjString() { using var mapReader = new DotTiled.Serialization.Tmj.TmjMapReader(_tmjContents, _ => throw new NotSupportedException(), _ => throw new NotSupportedException(), _ => throw new NotSupportedException()); return mapReader.ReadMap(); diff --git a/src/DotTiled.Tests/Assert/AssertData.cs b/src/DotTiled.Tests/Assert/AssertData.cs index 3ddcf4a..31ffff2 100644 --- a/src/DotTiled.Tests/Assert/AssertData.cs +++ b/src/DotTiled.Tests/Assert/AssertData.cs @@ -1,5 +1,3 @@ -using DotTiled.Model; - namespace DotTiled.Tests; public static partial class DotTiledAssert diff --git a/src/DotTiled.Tests/Assert/AssertImage.cs b/src/DotTiled.Tests/Assert/AssertImage.cs index 51a9b82..a674faa 100644 --- a/src/DotTiled.Tests/Assert/AssertImage.cs +++ b/src/DotTiled.Tests/Assert/AssertImage.cs @@ -1,5 +1,3 @@ -using DotTiled.Model; - namespace DotTiled.Tests; public static partial class DotTiledAssert diff --git a/src/DotTiled.Tests/Assert/AssertLayer.cs b/src/DotTiled.Tests/Assert/AssertLayer.cs index 89886cc..5432d62 100644 --- a/src/DotTiled.Tests/Assert/AssertLayer.cs +++ b/src/DotTiled.Tests/Assert/AssertLayer.cs @@ -1,5 +1,3 @@ -using DotTiled.Model; - namespace DotTiled.Tests; public static partial class DotTiledAssert diff --git a/src/DotTiled.Tests/Assert/AssertMap.cs b/src/DotTiled.Tests/Assert/AssertMap.cs index 358029b..0110f51 100644 --- a/src/DotTiled.Tests/Assert/AssertMap.cs +++ b/src/DotTiled.Tests/Assert/AssertMap.cs @@ -1,6 +1,5 @@ using System.Collections; using System.Numerics; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Assert/AssertObject.cs b/src/DotTiled.Tests/Assert/AssertObject.cs index bc8e54c..2dfb2d9 100644 --- a/src/DotTiled.Tests/Assert/AssertObject.cs +++ b/src/DotTiled.Tests/Assert/AssertObject.cs @@ -1,22 +1,22 @@ -using DotTiled.Model; - namespace DotTiled.Tests; public static partial class DotTiledAssert { - internal static void AssertObject(Model.Object expected, Model.Object actual) + internal static void AssertObject(DotTiled.Object expected, DotTiled.Object actual) { // Attributes - AssertEqual(expected.ID, actual.ID, nameof(Model.Object.ID)); - AssertEqual(expected.Name, actual.Name, nameof(Model.Object.Name)); - AssertEqual(expected.Type, actual.Type, nameof(Model.Object.Type)); - AssertEqual(expected.X, actual.X, nameof(Model.Object.X)); - AssertEqual(expected.Y, actual.Y, nameof(Model.Object.Y)); - AssertEqual(expected.Width, actual.Width, nameof(Model.Object.Width)); - AssertEqual(expected.Height, actual.Height, nameof(Model.Object.Height)); - AssertEqual(expected.Rotation, actual.Rotation, nameof(Model.Object.Rotation)); - AssertEqual(expected.Visible, actual.Visible, nameof(Model.Object.Visible)); - AssertEqual(expected.Template, actual.Template, nameof(Model.Object.Template)); +#pragma warning disable IDE0002 + AssertEqual(expected.ID, actual.ID, nameof(DotTiled.Object.ID)); + AssertEqual(expected.Name, actual.Name, nameof(DotTiled.Object.Name)); + AssertEqual(expected.Type, actual.Type, nameof(DotTiled.Object.Type)); + AssertEqual(expected.X, actual.X, nameof(DotTiled.Object.X)); + AssertEqual(expected.Y, actual.Y, nameof(DotTiled.Object.Y)); + AssertEqual(expected.Width, actual.Width, nameof(DotTiled.Object.Width)); + AssertEqual(expected.Height, actual.Height, nameof(DotTiled.Object.Height)); + AssertEqual(expected.Rotation, actual.Rotation, nameof(DotTiled.Object.Rotation)); + AssertEqual(expected.Visible, actual.Visible, nameof(DotTiled.Object.Visible)); + AssertEqual(expected.Template, actual.Template, nameof(DotTiled.Object.Template)); +#pragma warning restore IDE0002 AssertProperties(expected.Properties, actual.Properties); diff --git a/src/DotTiled.Tests/Assert/AssertProperties.cs b/src/DotTiled.Tests/Assert/AssertProperties.cs index 84af365..843d8d0 100644 --- a/src/DotTiled.Tests/Assert/AssertProperties.cs +++ b/src/DotTiled.Tests/Assert/AssertProperties.cs @@ -1,5 +1,3 @@ -using DotTiled.Model; - namespace DotTiled.Tests; public static partial class DotTiledAssert diff --git a/src/DotTiled.Tests/Assert/AssertTileset.cs b/src/DotTiled.Tests/Assert/AssertTileset.cs index befc79a..4646a85 100644 --- a/src/DotTiled.Tests/Assert/AssertTileset.cs +++ b/src/DotTiled.Tests/Assert/AssertTileset.cs @@ -1,5 +1,3 @@ -using DotTiled.Model; - namespace DotTiled.Tests; public static partial class DotTiledAssert diff --git a/src/DotTiled.Tests/Serialization/MapReaderTests.cs b/src/DotTiled.Tests/Serialization/MapReaderTests.cs index c6e3ec7..885f57e 100644 --- a/src/DotTiled.Tests/Serialization/MapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/MapReaderTests.cs @@ -1,4 +1,3 @@ -using DotTiled.Model; using DotTiled.Serialization; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData.cs b/src/DotTiled.Tests/Serialization/TestData.cs index 1c0b885..7f68c9e 100644 --- a/src/DotTiled.Tests/Serialization/TestData.cs +++ b/src/DotTiled.Tests/Serialization/TestData.cs @@ -1,5 +1,4 @@ using System.Xml; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs b/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs index da726bf..eff73d9 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.cs @@ -1,5 +1,3 @@ -using DotTiled.Model; - namespace DotTiled.Tests; public partial class TestData 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 a937685..28d6272 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 @@ -1,5 +1,4 @@ using System.Globalization; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs index 2e4bd61..9aaa7d7 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-external-tileset-wangset/map-external-tileset-wangset.cs @@ -1,5 +1,4 @@ using System.Globalization; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs index d5d8c1e..fdedbf8 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-common-props/map-with-common-props.cs @@ -1,5 +1,4 @@ using System.Globalization; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs index 9a965c2..56759d4 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-custom-type-props/map-with-custom-type-props.cs @@ -1,5 +1,4 @@ using System.Globalization; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.cs index 1b36b4e..90aac6c 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-deep-props/map-with-deep-props.cs @@ -1,5 +1,4 @@ using System.Globalization; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs index 863dc75..fb3c95f 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-embedded-tileset/map-with-embedded-tileset.cs @@ -1,5 +1,4 @@ using System.Globalization; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs index 3682b73..10c4d67 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-external-tileset/map-with-external-tileset.cs @@ -1,5 +1,4 @@ using System.Globalization; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs index 02a9fc5..4e181c4 100644 --- a/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs +++ b/src/DotTiled.Tests/Serialization/TestData/Map/map-with-flippingflags/map-with-flippingflags.cs @@ -1,5 +1,4 @@ using System.Globalization; -using DotTiled.Model; namespace DotTiled.Tests; 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 ba0013a..64974bc 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 @@ -1,5 +1,4 @@ using System.Numerics; -using DotTiled.Model; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs b/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs index 48cc13f..a896a48 100644 --- a/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/Tmj/TmjMapReaderTests.cs @@ -1,4 +1,3 @@ -using DotTiled.Model; using DotTiled.Serialization.Tmj; namespace DotTiled.Tests; diff --git a/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs b/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs index 748d4e3..b6e5813 100644 --- a/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/Tmx/TmxMapReaderTests.cs @@ -1,4 +1,3 @@ -using DotTiled.Model; using DotTiled.Serialization.Tmx; namespace DotTiled.Tests; diff --git a/src/DotTiled/Model/Color.cs b/src/DotTiled/Color.cs similarity index 99% rename from src/DotTiled/Model/Color.cs rename to src/DotTiled/Color.cs index 7de0ab0..367c942 100644 --- a/src/DotTiled/Model/Color.cs +++ b/src/DotTiled/Color.cs @@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a Tiled color. diff --git a/src/DotTiled/Model/Layers/BaseLayer.cs b/src/DotTiled/Layers/BaseLayer.cs similarity index 98% rename from src/DotTiled/Model/Layers/BaseLayer.cs rename to src/DotTiled/Layers/BaseLayer.cs index a16b41a..f00cc01 100644 --- a/src/DotTiled/Model/Layers/BaseLayer.cs +++ b/src/DotTiled/Layers/BaseLayer.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotTiled.Model; +namespace DotTiled; /// /// Base class for all layer types in a map. diff --git a/src/DotTiled/Model/Layers/Data.cs b/src/DotTiled/Layers/Data.cs similarity index 99% rename from src/DotTiled/Model/Layers/Data.cs rename to src/DotTiled/Layers/Data.cs index d2a9686..6c74edf 100644 --- a/src/DotTiled/Model/Layers/Data.cs +++ b/src/DotTiled/Layers/Data.cs @@ -1,6 +1,6 @@ using System; -namespace DotTiled.Model; +namespace DotTiled; /// /// Specifies the encoding used to encode the tile layer data. diff --git a/src/DotTiled/Model/Layers/Group.cs b/src/DotTiled/Layers/Group.cs similarity index 91% rename from src/DotTiled/Model/Layers/Group.cs rename to src/DotTiled/Layers/Group.cs index f770c63..703e938 100644 --- a/src/DotTiled/Model/Layers/Group.cs +++ b/src/DotTiled/Layers/Group.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a group of layers, to form a hierarchy. diff --git a/src/DotTiled/Model/Layers/ImageLayer.cs b/src/DotTiled/Layers/ImageLayer.cs similarity index 96% rename from src/DotTiled/Model/Layers/ImageLayer.cs rename to src/DotTiled/Layers/ImageLayer.cs index e0bb110..11c157a 100644 --- a/src/DotTiled/Model/Layers/ImageLayer.cs +++ b/src/DotTiled/Layers/ImageLayer.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents an image layer in a map. diff --git a/src/DotTiled/Model/Layers/ObjectLayer.cs b/src/DotTiled/Layers/ObjectLayer.cs similarity index 98% rename from src/DotTiled/Model/Layers/ObjectLayer.cs rename to src/DotTiled/Layers/ObjectLayer.cs index 60acc13..c39b445 100644 --- a/src/DotTiled/Model/Layers/ObjectLayer.cs +++ b/src/DotTiled/Layers/ObjectLayer.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents the order in which objects can be drawn. diff --git a/src/DotTiled/Model/Layers/Objects/EllipseObject.cs b/src/DotTiled/Layers/Objects/EllipseObject.cs similarity index 91% rename from src/DotTiled/Model/Layers/Objects/EllipseObject.cs rename to src/DotTiled/Layers/Objects/EllipseObject.cs index 7e777de..75db631 100644 --- a/src/DotTiled/Model/Layers/Objects/EllipseObject.cs +++ b/src/DotTiled/Layers/Objects/EllipseObject.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// An ellipse object in a map. The existing , , , diff --git a/src/DotTiled/Model/Layers/Objects/Object.cs b/src/DotTiled/Layers/Objects/Object.cs similarity index 98% rename from src/DotTiled/Model/Layers/Objects/Object.cs rename to src/DotTiled/Layers/Objects/Object.cs index f2990dc..fe97131 100644 --- a/src/DotTiled/Model/Layers/Objects/Object.cs +++ b/src/DotTiled/Layers/Objects/Object.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotTiled.Model; +namespace DotTiled; /// /// Base class for objects in object layers. diff --git a/src/DotTiled/Model/Layers/Objects/PointObject.cs b/src/DotTiled/Layers/Objects/PointObject.cs similarity index 89% rename from src/DotTiled/Model/Layers/Objects/PointObject.cs rename to src/DotTiled/Layers/Objects/PointObject.cs index 44eada8..0c53e1b 100644 --- a/src/DotTiled/Model/Layers/Objects/PointObject.cs +++ b/src/DotTiled/Layers/Objects/PointObject.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// A point object in a map. The existing and properties are used to diff --git a/src/DotTiled/Model/Layers/Objects/PolygonObject.cs b/src/DotTiled/Layers/Objects/PolygonObject.cs similarity index 95% rename from src/DotTiled/Model/Layers/Objects/PolygonObject.cs rename to src/DotTiled/Layers/Objects/PolygonObject.cs index 09805d8..2cf3895 100644 --- a/src/DotTiled/Model/Layers/Objects/PolygonObject.cs +++ b/src/DotTiled/Layers/Objects/PolygonObject.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Numerics; -namespace DotTiled.Model; +namespace DotTiled; /// /// A polygon object in a map. The existing and properties are used as diff --git a/src/DotTiled/Model/Layers/Objects/PolylineObject.cs b/src/DotTiled/Layers/Objects/PolylineObject.cs similarity index 95% rename from src/DotTiled/Model/Layers/Objects/PolylineObject.cs rename to src/DotTiled/Layers/Objects/PolylineObject.cs index d267c07..d755521 100644 --- a/src/DotTiled/Model/Layers/Objects/PolylineObject.cs +++ b/src/DotTiled/Layers/Objects/PolylineObject.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Numerics; -namespace DotTiled.Model; +namespace DotTiled; /// /// A polyline object in a map. The existing and properties are used as diff --git a/src/DotTiled/Model/Layers/Objects/RectangleObject.cs b/src/DotTiled/Layers/Objects/RectangleObject.cs similarity index 91% rename from src/DotTiled/Model/Layers/Objects/RectangleObject.cs rename to src/DotTiled/Layers/Objects/RectangleObject.cs index 99c6cff..8e71ee8 100644 --- a/src/DotTiled/Model/Layers/Objects/RectangleObject.cs +++ b/src/DotTiled/Layers/Objects/RectangleObject.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// A rectangle object in a map. The existing , , , diff --git a/src/DotTiled/Model/Layers/Objects/TextObject.cs b/src/DotTiled/Layers/Objects/TextObject.cs similarity index 98% rename from src/DotTiled/Model/Layers/Objects/TextObject.cs rename to src/DotTiled/Layers/Objects/TextObject.cs index 9c5ed2d..48a095c 100644 --- a/src/DotTiled/Model/Layers/Objects/TextObject.cs +++ b/src/DotTiled/Layers/Objects/TextObject.cs @@ -1,6 +1,6 @@ using System.Globalization; -namespace DotTiled.Model; +namespace DotTiled; /// /// The horizontal alignment of text. diff --git a/src/DotTiled/Model/Layers/Objects/TileObject.cs b/src/DotTiled/Layers/Objects/TileObject.cs similarity index 87% rename from src/DotTiled/Model/Layers/Objects/TileObject.cs rename to src/DotTiled/Layers/Objects/TileObject.cs index fe44c50..ab00628 100644 --- a/src/DotTiled/Model/Layers/Objects/TileObject.cs +++ b/src/DotTiled/Layers/Objects/TileObject.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// A tile object in a map. diff --git a/src/DotTiled/Model/Layers/TileLayer.cs b/src/DotTiled/Layers/TileLayer.cs similarity index 96% rename from src/DotTiled/Model/Layers/TileLayer.cs rename to src/DotTiled/Layers/TileLayer.cs index 600f7c0..8207f10 100644 --- a/src/DotTiled/Model/Layers/TileLayer.cs +++ b/src/DotTiled/Layers/TileLayer.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a tile layer in a map. diff --git a/src/DotTiled/Model/Map.cs b/src/DotTiled/Map.cs similarity index 99% rename from src/DotTiled/Model/Map.cs rename to src/DotTiled/Map.cs index 48ed975..0db1205 100644 --- a/src/DotTiled/Model/Map.cs +++ b/src/DotTiled/Map.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Globalization; -namespace DotTiled.Model; +namespace DotTiled; /// /// Map orientation enumeration. The map orientation determines the alignment of the tiles in the map. diff --git a/src/DotTiled/Model/Properties/BoolProperty.cs b/src/DotTiled/Properties/BoolProperty.cs similarity index 94% rename from src/DotTiled/Model/Properties/BoolProperty.cs rename to src/DotTiled/Properties/BoolProperty.cs index 315e820..e401d38 100644 --- a/src/DotTiled/Model/Properties/BoolProperty.cs +++ b/src/DotTiled/Properties/BoolProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a boolean property. diff --git a/src/DotTiled/Model/Properties/ClassProperty.cs b/src/DotTiled/Properties/ClassProperty.cs similarity index 95% rename from src/DotTiled/Model/Properties/ClassProperty.cs rename to src/DotTiled/Properties/ClassProperty.cs index 5c9d6a5..933660b 100644 --- a/src/DotTiled/Model/Properties/ClassProperty.cs +++ b/src/DotTiled/Properties/ClassProperty.cs @@ -3,7 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a class property. @@ -14,7 +14,7 @@ public class ClassProperty : IHasProperties, IProperty> public required string Name { get; set; } /// - public PropertyType Type => Model.PropertyType.Class; + public PropertyType Type => DotTiled.PropertyType.Class; /// /// The type of the class property. This will be the name of a custom defined diff --git a/src/DotTiled/Model/Properties/ColorProperty.cs b/src/DotTiled/Properties/ColorProperty.cs similarity index 94% rename from src/DotTiled/Model/Properties/ColorProperty.cs rename to src/DotTiled/Properties/ColorProperty.cs index 7c4a132..0fff029 100644 --- a/src/DotTiled/Model/Properties/ColorProperty.cs +++ b/src/DotTiled/Properties/ColorProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a color property. diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs b/src/DotTiled/Properties/CustomTypes/CustomClassDefinition.cs similarity index 98% rename from src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs rename to src/DotTiled/Properties/CustomTypes/CustomClassDefinition.cs index 313081f..457a17d 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomClassDefinition.cs +++ b/src/DotTiled/Properties/CustomTypes/CustomClassDefinition.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents the types of objects that can use a custom class. diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs b/src/DotTiled/Properties/CustomTypes/CustomEnumDefinition.cs similarity index 97% rename from src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs rename to src/DotTiled/Properties/CustomTypes/CustomEnumDefinition.cs index 60b7f5b..e155b38 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomEnumDefinition.cs +++ b/src/DotTiled/Properties/CustomTypes/CustomEnumDefinition.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents the storage type of a custom enum. diff --git a/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs b/src/DotTiled/Properties/CustomTypes/CustomTypeDefinition.cs similarity index 92% rename from src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs rename to src/DotTiled/Properties/CustomTypes/CustomTypeDefinition.cs index 1e595cc..583bc40 100644 --- a/src/DotTiled/Model/Properties/CustomTypes/CustomTypeDefinition.cs +++ b/src/DotTiled/Properties/CustomTypes/CustomTypeDefinition.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Base class for custom type definitions. diff --git a/src/DotTiled/Model/Properties/EnumProperty.cs b/src/DotTiled/Properties/EnumProperty.cs similarity index 95% rename from src/DotTiled/Model/Properties/EnumProperty.cs rename to src/DotTiled/Properties/EnumProperty.cs index 19e1b1f..a123f9a 100644 --- a/src/DotTiled/Model/Properties/EnumProperty.cs +++ b/src/DotTiled/Properties/EnumProperty.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents an enum property. @@ -12,7 +12,7 @@ public class EnumProperty : IProperty> public required string Name { get; set; } /// - public PropertyType Type => Model.PropertyType.Enum; + public PropertyType Type => DotTiled.PropertyType.Enum; /// /// The type of the class property. This will be the name of a custom defined diff --git a/src/DotTiled/Model/Properties/FileProperty.cs b/src/DotTiled/Properties/FileProperty.cs similarity index 94% rename from src/DotTiled/Model/Properties/FileProperty.cs rename to src/DotTiled/Properties/FileProperty.cs index 7c65121..01d4a08 100644 --- a/src/DotTiled/Model/Properties/FileProperty.cs +++ b/src/DotTiled/Properties/FileProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a file property. diff --git a/src/DotTiled/Model/Properties/FloatProperty.cs b/src/DotTiled/Properties/FloatProperty.cs similarity index 94% rename from src/DotTiled/Model/Properties/FloatProperty.cs rename to src/DotTiled/Properties/FloatProperty.cs index 57ba928..1652e20 100644 --- a/src/DotTiled/Model/Properties/FloatProperty.cs +++ b/src/DotTiled/Properties/FloatProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a float property. diff --git a/src/DotTiled/Model/Properties/IHasProperties.cs b/src/DotTiled/Properties/IHasProperties.cs similarity index 98% rename from src/DotTiled/Model/Properties/IHasProperties.cs rename to src/DotTiled/Properties/IHasProperties.cs index 1b124a9..21bf0bb 100644 --- a/src/DotTiled/Model/Properties/IHasProperties.cs +++ b/src/DotTiled/Properties/IHasProperties.cs @@ -3,7 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; -namespace DotTiled.Model; +namespace DotTiled; /// /// Interface for objects that have properties attached to them. diff --git a/src/DotTiled/Model/Properties/IProperty.cs b/src/DotTiled/Properties/IProperty.cs similarity index 97% rename from src/DotTiled/Model/Properties/IProperty.cs rename to src/DotTiled/Properties/IProperty.cs index d2d98e8..de9eebf 100644 --- a/src/DotTiled/Model/Properties/IProperty.cs +++ b/src/DotTiled/Properties/IProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Interface for properties that can be attached to objects, tiles, tilesets, maps etc. diff --git a/src/DotTiled/Model/Properties/IntProperty.cs b/src/DotTiled/Properties/IntProperty.cs similarity index 94% rename from src/DotTiled/Model/Properties/IntProperty.cs rename to src/DotTiled/Properties/IntProperty.cs index 27a7afc..2765038 100644 --- a/src/DotTiled/Model/Properties/IntProperty.cs +++ b/src/DotTiled/Properties/IntProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents an integer property. diff --git a/src/DotTiled/Model/Properties/ObjectProperty.cs b/src/DotTiled/Properties/ObjectProperty.cs similarity index 95% rename from src/DotTiled/Model/Properties/ObjectProperty.cs rename to src/DotTiled/Properties/ObjectProperty.cs index de8a1e0..a33e401 100644 --- a/src/DotTiled/Model/Properties/ObjectProperty.cs +++ b/src/DotTiled/Properties/ObjectProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents an object property. diff --git a/src/DotTiled/Model/Properties/PropertyType.cs b/src/DotTiled/Properties/PropertyType.cs similarity index 96% rename from src/DotTiled/Model/Properties/PropertyType.cs rename to src/DotTiled/Properties/PropertyType.cs index 451ca5e..a6a31db 100644 --- a/src/DotTiled/Model/Properties/PropertyType.cs +++ b/src/DotTiled/Properties/PropertyType.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents the type of a property. diff --git a/src/DotTiled/Model/Properties/StringProperty.cs b/src/DotTiled/Properties/StringProperty.cs similarity index 94% rename from src/DotTiled/Model/Properties/StringProperty.cs rename to src/DotTiled/Properties/StringProperty.cs index 0c20b29..c0c8722 100644 --- a/src/DotTiled/Model/Properties/StringProperty.cs +++ b/src/DotTiled/Properties/StringProperty.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a string property. diff --git a/src/DotTiled/Serialization/Helpers.cs b/src/DotTiled/Serialization/Helpers.cs index d47d627..bd839eb 100644 --- a/src/DotTiled/Serialization/Helpers.cs +++ b/src/DotTiled/Serialization/Helpers.cs @@ -3,7 +3,6 @@ using System.IO; using System.IO.Compression; using System.Linq; -using DotTiled.Model; namespace DotTiled.Serialization; diff --git a/src/DotTiled/Serialization/IMapReader.cs b/src/DotTiled/Serialization/IMapReader.cs index d96def5..ec70b91 100644 --- a/src/DotTiled/Serialization/IMapReader.cs +++ b/src/DotTiled/Serialization/IMapReader.cs @@ -1,5 +1,4 @@ using System; -using DotTiled.Model; namespace DotTiled.Serialization; diff --git a/src/DotTiled/Serialization/ITemplateReader.cs b/src/DotTiled/Serialization/ITemplateReader.cs index 9497e26..98901fc 100644 --- a/src/DotTiled/Serialization/ITemplateReader.cs +++ b/src/DotTiled/Serialization/ITemplateReader.cs @@ -1,5 +1,4 @@ using System; -using DotTiled.Model; namespace DotTiled.Serialization; diff --git a/src/DotTiled/Serialization/ITilesetReader.cs b/src/DotTiled/Serialization/ITilesetReader.cs index e798bcf..73fe815 100644 --- a/src/DotTiled/Serialization/ITilesetReader.cs +++ b/src/DotTiled/Serialization/ITilesetReader.cs @@ -1,5 +1,4 @@ using System; -using DotTiled.Model; namespace DotTiled.Serialization; diff --git a/src/DotTiled/Serialization/MapReader.cs b/src/DotTiled/Serialization/MapReader.cs index abd323e..35341f6 100644 --- a/src/DotTiled/Serialization/MapReader.cs +++ b/src/DotTiled/Serialization/MapReader.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Xml; -using DotTiled.Model; using DotTiled.Serialization.Tmj; using DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/TemplateReader.cs b/src/DotTiled/Serialization/TemplateReader.cs index f354c21..2fe92ec 100644 --- a/src/DotTiled/Serialization/TemplateReader.cs +++ b/src/DotTiled/Serialization/TemplateReader.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Xml; -using DotTiled.Model; using DotTiled.Serialization.Tmj; using DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/TilesetReader.cs b/src/DotTiled/Serialization/TilesetReader.cs index 55f0099..b8ba69b 100644 --- a/src/DotTiled/Serialization/TilesetReader.cs +++ b/src/DotTiled/Serialization/TilesetReader.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Xml; -using DotTiled.Model; using DotTiled.Serialization.Tmj; using DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs b/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs index 6a71eb7..792bb73 100644 --- a/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs +++ b/src/DotTiled/Serialization/Tmj/TjTemplateReader.cs @@ -1,5 +1,4 @@ using System; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs index 7ec12e1..8ceb211 100644 --- a/src/DotTiled/Serialization/Tmj/TmjMapReader.cs +++ b/src/DotTiled/Serialization/Tmj/TmjMapReader.cs @@ -1,5 +1,4 @@ using System; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Data.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Data.cs index 22a35e2..76945ca 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Data.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Data.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Text.Json; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs index e132d0c..ca08df8 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Globalization; using System.Text.Json; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs index 576fa52..f115a52 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs @@ -1,6 +1,5 @@ using System.Globalization; using System.Text.Json; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Layer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Layer.cs index 9e01d84..33c42fa 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Layer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Layer.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs index 47abc66..ec45b8d 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Globalization; using System.Text.Json; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs index cae4790..036e8ff 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs @@ -2,7 +2,6 @@ using System.Globalization; using System.Numerics; using System.Text.Json; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; @@ -34,7 +33,7 @@ internal ObjectLayer ReadObjectLayer(JsonElement element) _ => throw new JsonException($"Unknown draw order '{s}'.") }, DrawOrder.TopDown); - var objects = element.GetOptionalPropertyCustom>("objects", e => e.GetValueAsList(el => ReadObject(el)), []); + var objects = element.GetOptionalPropertyCustom>("objects", e => e.GetValueAsList(el => ReadObject(el)), []); return new ObjectLayer { @@ -59,7 +58,7 @@ internal ObjectLayer ReadObjectLayer(JsonElement element) }; } - internal Model.Object ReadObject(JsonElement element) + internal DotTiled.Object ReadObject(JsonElement element) { uint? idDefault = null; string nameDefault = ""; diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Properties.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Properties.cs index c5b6a7d..c8683b2 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Properties.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Properties.cs @@ -2,7 +2,6 @@ using System.Globalization; using System.Linq; using System.Text.Json; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs index 45031db..88bcf09 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; @@ -9,7 +8,7 @@ internal Template ReadTemplate(JsonElement element) { var type = element.GetRequiredProperty("type"); var tileset = element.GetOptionalPropertyCustom("tileset", ReadTileset, null); - var @object = element.GetRequiredPropertyCustom("object", ReadObject); + var @object = element.GetRequiredPropertyCustom("object", ReadObject); return new Template { diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs index ecc74d8..e3ccc9a 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs @@ -1,6 +1,5 @@ using System.Globalization; using System.Text.Json; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs index 5fef5f3..c19e3f6 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Globalization; using System.Text.Json; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.cs index 4ae338f..f36ca88 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.cs @@ -1,6 +1,5 @@ using System; using System.Text.Json; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs index 8c918b5..5816c8a 100644 --- a/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmj/TsjTilesetReader.cs @@ -1,5 +1,4 @@ using System; -using DotTiled.Model; namespace DotTiled.Serialization.Tmj; diff --git a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs index e90caa1..6029481 100644 --- a/src/DotTiled/Serialization/Tmx/TmxMapReader.cs +++ b/src/DotTiled/Serialization/Tmx/TmxMapReader.cs @@ -1,6 +1,5 @@ using System; using System.Xml; -using DotTiled.Model; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Chunk.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Chunk.cs index 73c8052..4ab5b11 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Chunk.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Chunk.cs @@ -1,5 +1,3 @@ -using DotTiled.Model; - namespace DotTiled.Serialization.Tmx; public abstract partial class TmxReaderBase diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Data.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Data.cs index 254c1d3..fb29250 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Data.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Data.cs @@ -4,7 +4,6 @@ using System.IO.Compression; using System.Linq; using System.Xml; -using DotTiled.Model; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs index 89f0c9b..11d6fc1 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Map.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using DotTiled.Model; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs index a680544..0233639 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs @@ -3,7 +3,6 @@ using System.Globalization; using System.Linq; using System.Numerics; -using DotTiled.Model; namespace DotTiled.Serialization.Tmx; @@ -36,7 +35,7 @@ internal ObjectLayer ReadObjectLayer() // Elements List? properties = null; - List objects = []; + List objects = []; _reader.ProcessChildren("objectgroup", (r, elementName) => elementName switch { @@ -68,11 +67,11 @@ internal ObjectLayer ReadObjectLayer() }; } - internal Model.Object ReadObject() + internal DotTiled.Object ReadObject() { // Attributes var template = _reader.GetOptionalAttribute("template"); - Model.Object? obj = null; + DotTiled.Object? obj = null; if (template is not null) obj = _externalTemplateResolver(template).Object; @@ -100,7 +99,7 @@ internal Model.Object ReadObject() var visible = _reader.GetOptionalAttributeParseable("visible") ?? visibleDefault; // Elements - Model.Object? foundObject = null; + DotTiled.Object? foundObject = null; int propertiesCounter = 0; List? properties = propertiesDefault; @@ -138,7 +137,7 @@ internal Model.Object ReadObject() return OverrideObject(obj, foundObject); } - internal static Model.Object OverrideObject(Model.Object? obj, Model.Object foundObject) + internal static DotTiled.Object OverrideObject(DotTiled.Object? obj, DotTiled.Object foundObject) { if (obj is null) return foundObject; @@ -305,7 +304,7 @@ internal Template ReadTemplate() Tileset? tileset = null; // Should contain exactly one of - Model.Object? obj = null; + DotTiled.Object? obj = null; _reader.ProcessChildren("template", (r, elementName) => elementName switch { diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs index 863e125..de12d57 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Linq; using System.Xml; -using DotTiled.Model; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs index f69a739..c345917 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.TileLayer.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Linq; -using DotTiled.Model; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs index 72e66e9..bffe0bd 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Tileset.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using DotTiled.Model; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.cs index 5851d76..e30af82 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.cs @@ -1,6 +1,5 @@ using System; using System.Xml; -using DotTiled.Model; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs index 176872b..3b442da 100644 --- a/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs +++ b/src/DotTiled/Serialization/Tmx/TsxTilesetReader.cs @@ -1,6 +1,5 @@ using System; using System.Xml; -using DotTiled.Model; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs index 1ff8445..72da9dc 100644 --- a/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs +++ b/src/DotTiled/Serialization/Tmx/TxTemplateReader.cs @@ -1,6 +1,5 @@ using System; using System.Xml; -using DotTiled.Model; namespace DotTiled.Serialization.Tmx; diff --git a/src/DotTiled/Model/Template.cs b/src/DotTiled/Template.cs similarity index 80% rename from src/DotTiled/Model/Template.cs rename to src/DotTiled/Template.cs index d8cee95..56052de 100644 --- a/src/DotTiled/Model/Template.cs +++ b/src/DotTiled/Template.cs @@ -1,7 +1,7 @@ -namespace DotTiled.Model; +namespace DotTiled; /// -/// Represents a Tiled template. A template is a reusable object that can be placed in an inside the Tiled editor. +/// Represents a Tiled template. A template is a reusable object that can be placed in an inside the Tiled editor. /// public class Template { diff --git a/src/DotTiled/Model/Tilesets/Frame.cs b/src/DotTiled/Tilesets/Frame.cs similarity index 93% rename from src/DotTiled/Model/Tilesets/Frame.cs rename to src/DotTiled/Tilesets/Frame.cs index 7e48aa0..ff37133 100644 --- a/src/DotTiled/Model/Tilesets/Frame.cs +++ b/src/DotTiled/Tilesets/Frame.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// A single frame of an animated tile. diff --git a/src/DotTiled/Model/Tilesets/Grid.cs b/src/DotTiled/Tilesets/Grid.cs similarity index 96% rename from src/DotTiled/Model/Tilesets/Grid.cs rename to src/DotTiled/Tilesets/Grid.cs index e8acfac..c063dd1 100644 --- a/src/DotTiled/Model/Tilesets/Grid.cs +++ b/src/DotTiled/Tilesets/Grid.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Orientation of the grid for the tiles in this tileset. diff --git a/src/DotTiled/Model/Tilesets/Image.cs b/src/DotTiled/Tilesets/Image.cs similarity index 97% rename from src/DotTiled/Model/Tilesets/Image.cs rename to src/DotTiled/Tilesets/Image.cs index 418d5f4..cee67ff 100644 --- a/src/DotTiled/Model/Tilesets/Image.cs +++ b/src/DotTiled/Tilesets/Image.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// The format of an image. diff --git a/src/DotTiled/Model/Tilesets/Tile.cs b/src/DotTiled/Tilesets/Tile.cs similarity index 98% rename from src/DotTiled/Model/Tilesets/Tile.cs rename to src/DotTiled/Tilesets/Tile.cs index 9919cfd..835ecac 100644 --- a/src/DotTiled/Model/Tilesets/Tile.cs +++ b/src/DotTiled/Tilesets/Tile.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a single tile in a tileset, when using a collection of images to represent the tileset. diff --git a/src/DotTiled/Model/Tilesets/TileOffset.cs b/src/DotTiled/Tilesets/TileOffset.cs similarity index 93% rename from src/DotTiled/Model/Tilesets/TileOffset.cs rename to src/DotTiled/Tilesets/TileOffset.cs index 6030f39..b446036 100644 --- a/src/DotTiled/Model/Tilesets/TileOffset.cs +++ b/src/DotTiled/Tilesets/TileOffset.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Is used to specify an offset in pixels in tilesets, to be applied when drawing a tile from the related tileset. diff --git a/src/DotTiled/Model/Tilesets/Tileset.cs b/src/DotTiled/Tilesets/Tileset.cs similarity index 99% rename from src/DotTiled/Model/Tilesets/Tileset.cs rename to src/DotTiled/Tilesets/Tileset.cs index 47f2021..0c2863f 100644 --- a/src/DotTiled/Model/Tilesets/Tileset.cs +++ b/src/DotTiled/Tilesets/Tileset.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotTiled.Model; +namespace DotTiled; /// /// The alignment of tile objects. diff --git a/src/DotTiled/Model/Tilesets/Transformations.cs b/src/DotTiled/Tilesets/Transformations.cs similarity index 96% rename from src/DotTiled/Model/Tilesets/Transformations.cs rename to src/DotTiled/Tilesets/Transformations.cs index b6cf6bf..8ed7c36 100644 --- a/src/DotTiled/Model/Tilesets/Transformations.cs +++ b/src/DotTiled/Tilesets/Transformations.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents which transformations can be applied to a tile in a tileset. diff --git a/src/DotTiled/Model/Tilesets/WangColor.cs b/src/DotTiled/Tilesets/WangColor.cs similarity index 97% rename from src/DotTiled/Model/Tilesets/WangColor.cs rename to src/DotTiled/Tilesets/WangColor.cs index f5d1186..b5ef482 100644 --- a/src/DotTiled/Model/Tilesets/WangColor.cs +++ b/src/DotTiled/Tilesets/WangColor.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a Wang color in a Wang set. diff --git a/src/DotTiled/Model/Tilesets/WangTile.cs b/src/DotTiled/Tilesets/WangTile.cs similarity index 92% rename from src/DotTiled/Model/Tilesets/WangTile.cs rename to src/DotTiled/Tilesets/WangTile.cs index 2347b91..0432cdd 100644 --- a/src/DotTiled/Model/Tilesets/WangTile.cs +++ b/src/DotTiled/Tilesets/WangTile.cs @@ -1,4 +1,4 @@ -namespace DotTiled.Model; +namespace DotTiled; /// /// Represents a Wang tile in a Wang set. diff --git a/src/DotTiled/Model/Tilesets/Wangset.cs b/src/DotTiled/Tilesets/Wangset.cs similarity index 97% rename from src/DotTiled/Model/Tilesets/Wangset.cs rename to src/DotTiled/Tilesets/Wangset.cs index 66952e8..16ceb56 100644 --- a/src/DotTiled/Model/Tilesets/Wangset.cs +++ b/src/DotTiled/Tilesets/Wangset.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotTiled.Model; +namespace DotTiled; /// /// Defines a list of colors and any number of Wang tiles using these colors. From ac073d689df819f9c90f81981750bb03fd21625c Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Fri, 30 Aug 2024 20:25:24 +0200 Subject: [PATCH 23/23] Set version to 0.1.0 for initial release of functionality --- src/DotTiled/DotTiled.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DotTiled/DotTiled.csproj b/src/DotTiled/DotTiled.csproj index d00569d..f5114f5 100644 --- a/src/DotTiled/DotTiled.csproj +++ b/src/DotTiled/DotTiled.csproj @@ -19,7 +19,7 @@ true Copyright © 2024 dcronqvist LICENSE - 1.0.0 + 0.1.0