diff --git a/README.md b/README.md index 66e4d04..63980ee 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Benchmark details The following benchmark results were gathered using the `DotTiled.Benchmark` project which uses [BenchmarkDotNet](https://benchmarkdotnet.org/) to compare the performance of DotTiled with other similar libraries. The benchmark results are grouped by category and show the mean execution time, memory consumption metrics, and ratio to DotTiled. ``` -BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.5131/22H2/2022Update) +BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.5737/22H2/2022Update) 12th Gen Intel Core i7-12700K, 1 CPU, 20 logical and 12 physical cores .NET SDK 8.0.202 [Host] : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX2 @@ -44,12 +44,12 @@ BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.5131/22H2/2022Update) ``` | Method | Categories | Mean | Ratio | Gen0 | Gen1 | Allocated | Alloc Ratio | |------------ |------------------------- |---------:|------:|-------:|-------:|----------:|------------:| -| DotTiled | MapFromInMemoryTmjString | 4.602 μs | 1.00 | 0.5417 | - | 7 KB | 1.00 | -| TiledLib | MapFromInMemoryTmjString | 6.385 μs | 1.39 | 0.7019 | 0.0153 | 9.01 KB | 1.29 | +| DotTiled | MapFromInMemoryTmjString | 4.410 μs | 1.00 | 0.4501 | - | 5.81 KB | 1.00 | +| TiledLib | MapFromInMemoryTmjString | 6.170 μs | 1.40 | 0.7019 | 0.0305 | 9.01 KB | 1.55 | | | | | | | | | | -| DotTiled | MapFromInMemoryTmxString | 3.216 μs | 1.00 | 1.3733 | 0.0610 | 17.68 KB | 1.00 | -| TiledLib | MapFromInMemoryTmxString | 5.721 μs | 1.78 | 1.8005 | 0.0916 | 23.32 KB | 1.32 | -| TiledCSPlus | MapFromInMemoryTmxString | 6.696 μs | 2.11 | 2.5940 | 0.1831 | 33.23 KB | 1.88 | +| DotTiled | MapFromInMemoryTmxString | 3.092 μs | 1.00 | 1.2970 | 0.0610 | 16.73 KB | 1.00 | +| TiledLib | MapFromInMemoryTmxString | 5.392 μs | 1.75 | 1.8158 | 0.1068 | 23.32 KB | 1.39 | +| TiledCSPlus | MapFromInMemoryTmxString | 6.479 μs | 2.10 | 2.5940 | 0.1831 | 33.16 KB | 1.98 | It is important to note that the above benchmark results come from loading a very small map with a single tile layer as I had to find a common denominator between the libraries so that they all could load the same map. The results aim to be indicative of the performance of the libraries, but should be taken with a grain of salt. Only the actively maintained libraries are included in the benchmark results. TiledCSPlus does not support the `.tmj` format, so it was not included for that benchmark category. diff --git a/docs/docs/essentials/custom-properties.md b/docs/docs/essentials/custom-properties.md index 3fd1bcc..805c914 100644 --- a/docs/docs/essentials/custom-properties.md +++ b/docs/docs/essentials/custom-properties.md @@ -178,7 +178,7 @@ For enum definitions, the can be used to indicate t > Tiled supports enums which can store their values as either strings or integers, and depending on the storage type you have specified in Tiled, you must make sure to have the same storage type in your . This can be done by setting the `StorageType` property to either `CustomEnumStorageType.String` or `CustomEnumStorageType.Int` when creating the definition, or by passing the storage type as an argument to the method. To be consistent with Tiled, will default to `CustomEnumStorageType.String` for the storage type parameter. > [!WARNING] -> If you have a custom enum type in Tiled, but do not define it in DotTiled, you must be aware that the type of the parsed property will be either or . It is not possible to determine the correct way to parse the enum property without the custom enum definition, which is why you will instead be given a property of type `string` or `int` when accessing the property in DotTiled. This can lead to inconsistencies between the map in Tiled and the loaded map with DotTiled. It is therefore recommended to define your custom enum types in DotTiled if you want to access the properties as instances. +> If you have a custom enum type in Tiled, but do not define it in DotTiled, you must be aware that the type of the parsed property will be either or . It is not possible to determine the correct way to parse the enum property without the custom enum definition, which is why you will instead be given a property of type `string` or `int` when accessing the property in DotTiled. This can lead to inconsistencies between the map in Tiled and the loaded map with DotTiled. It is therefore recommended to define your custom enum types in DotTiled if you want to access the properties as instances. ## Mapping properties to C# classes or enums diff --git a/src/DotTiled.Examples/DotTiled.Example.Console/Program.cs b/src/DotTiled.Examples/DotTiled.Example.Console/Program.cs index baf36ea..6220f2e 100644 --- a/src/DotTiled.Examples/DotTiled.Example.Console/Program.cs +++ b/src/DotTiled.Examples/DotTiled.Example.Console/Program.cs @@ -79,6 +79,6 @@ public class Program [ new CustomClassDefinition() { Name = "a" }, ]; - return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional(ctd) : Optional.Empty; + return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional(ctd) : Optional.Empty; } } diff --git a/src/DotTiled.Examples/DotTiled.Example.Godot/MapParser.cs b/src/DotTiled.Examples/DotTiled.Example.Godot/MapParser.cs index 8319d00..9e92276 100644 --- a/src/DotTiled.Examples/DotTiled.Example.Godot/MapParser.cs +++ b/src/DotTiled.Examples/DotTiled.Example.Godot/MapParser.cs @@ -42,10 +42,10 @@ public partial class MapParser : Node2D private Tileset ResolveTileset(string source) { - string tilesetString = FileAccess.Open($"res://{source}", FileAccess.ModeFlags.Read).GetAsText(); - using TilesetReader tilesetReader = - new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType); - return tilesetReader.ReadTileset(); + string tilesetString = FileAccess.Open($"res://{source}", FileAccess.ModeFlags.Read).GetAsText(); + using TilesetReader tilesetReader = + new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType); + return tilesetReader.ReadTileset(); } private Template ResolveTemplate(string source) @@ -62,6 +62,6 @@ public partial class MapParser : Node2D [ new CustomClassDefinition() { Name = "a" }, ]; - return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional(ctd) : Optional.Empty; + return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional(ctd) : Optional.Empty; } } diff --git a/src/DotTiled.Tests/Assert/AssertLayer.cs b/src/DotTiled.Tests/Assert/AssertLayer.cs index 7dc8011..85a96af 100644 --- a/src/DotTiled.Tests/Assert/AssertLayer.cs +++ b/src/DotTiled.Tests/Assert/AssertLayer.cs @@ -35,8 +35,7 @@ public static partial class DotTiledAssert AssertEqual(expected.X, actual.X, nameof(TileLayer.X)); AssertEqual(expected.Y, actual.Y, nameof(TileLayer.Y)); - Assert.NotNull(actual.Data); - AssertData(expected.Data, actual.Data); + AssertOptionalsEqual(expected.Data, actual.Data, nameof(TileLayer.Data), AssertData); } private static void AssertLayer(ObjectLayer expected, ObjectLayer actual) @@ -60,8 +59,7 @@ public static partial class DotTiledAssert AssertEqual(expected.X, actual.X, nameof(ImageLayer.X)); AssertEqual(expected.Y, actual.Y, nameof(ImageLayer.Y)); - Assert.NotNull(actual.Image); - AssertImage(expected.Image, actual.Image); + AssertOptionalsEqual(expected.Image, actual.Image, nameof(ImageLayer.Image), AssertImage); } private static void AssertLayer(Group expected, Group actual) diff --git a/src/DotTiled.Tests/Assert/AssertMap.cs b/src/DotTiled.Tests/Assert/AssertMap.cs index bc87002..55c1896 100644 --- a/src/DotTiled.Tests/Assert/AssertMap.cs +++ b/src/DotTiled.Tests/Assert/AssertMap.cs @@ -33,12 +33,6 @@ public static partial class DotTiledAssert string nameof, Action assertEqual) { - if (expected is null) - { - Assert.Null(actual); - return; - } - if (expected.HasValue) { Assert.True(actual.HasValue, $"Expected {nameof} to have a value"); @@ -51,12 +45,6 @@ public static partial class DotTiledAssert internal static void AssertEqual(Optional expected, Optional actual, string nameof) { - if (expected is null) - { - Assert.Null(actual); - return; - } - if (expected.HasValue) { Assert.True(actual.HasValue, $"Expected {nameof} to have a value"); diff --git a/src/DotTiled.Tests/TestData/Maps/map-with-common-props/map-with-common-props.cs b/src/DotTiled.Tests/TestData/Maps/map-with-common-props/map-with-common-props.cs index ff184ff..a455bdd 100644 --- a/src/DotTiled.Tests/TestData/Maps/map-with-common-props/map-with-common-props.cs +++ b/src/DotTiled.Tests/TestData/Maps/map-with-common-props/map-with-common-props.cs @@ -58,7 +58,7 @@ public partial class TestData new IntProperty { Name = "intprop", Value = 8 }, new ObjectProperty { Name = "objectprop", Value = 5 }, new StringProperty { Name = "stringprop", Value = "This is a string, hello world!" }, - new ColorProperty { Name = "unsetcolorprop", Value = Optional.Empty } + new ColorProperty { Name = "unsetcolorprop", Value = Optional.Empty } ] }; } diff --git a/src/DotTiled.Tests/UnitTests/OptionalTests.cs b/src/DotTiled.Tests/UnitTests/OptionalTests.cs index 5390a64..fec5971 100644 --- a/src/DotTiled.Tests/UnitTests/OptionalTests.cs +++ b/src/DotTiled.Tests/UnitTests/OptionalTests.cs @@ -59,30 +59,6 @@ public class OptionalTests Assert.Equal(expectedValue, optional.Value); } - [Fact] - public void ImplicitConversion_FromOptionalToValue_ShouldReturnValue_WhenHasValueIsTrue() - { - // Arrange - int expectedValue = 10; - var optional = new Optional(expectedValue); - - // Act - int value = optional; - - // Assert - Assert.Equal(expectedValue, value); - } - - [Fact] - public void ImplicitConversion_FromOptionalToValue_ShouldThrowException_WhenHasValueIsFalse() - { - // Arrange - var optional = new Optional(); - - // Act & Assert - _ = Assert.Throws(() => { int value = optional; }); - } - // ToString Method Tests [Fact] @@ -237,18 +213,6 @@ public class OptionalTests _ = Assert.Throws(() => optional.Value); } - [Fact] - public void ImplicitConversion_WhenHasValueIsFalse_ShouldThrowInvalidOperationException() - { - // Arrange - var optional = new Optional(); - - // Act & Assert - _ = Assert.Throws(() => { int value = optional; }); - } - - // Edge Cases - [Fact] public void EmptyOptionalEquality_ShouldReturnTrue() { diff --git a/src/DotTiled.Tests/UnitTests/Serialization/LoaderTests.cs b/src/DotTiled.Tests/UnitTests/Serialization/LoaderTests.cs index 7edff12..b25b157 100644 --- a/src/DotTiled.Tests/UnitTests/Serialization/LoaderTests.cs +++ b/src/DotTiled.Tests/UnitTests/Serialization/LoaderTests.cs @@ -71,8 +71,8 @@ public class LoaderTests """); var resourceCache = Substitute.For(); - resourceCache.GetTileset(Arg.Any()).Returns(Optional.Empty); - resourceCache.GetTemplate(Arg.Any()).Returns(Optional