diff --git a/src/DotTiled.Tests/Assert/AssertData.cs b/src/DotTiled.Tests/Assert/AssertData.cs index 3207a20..d840ae0 100644 --- a/src/DotTiled.Tests/Assert/AssertData.cs +++ b/src/DotTiled.Tests/Assert/AssertData.cs @@ -2,7 +2,7 @@ namespace DotTiled.Tests; public static partial class DotTiledAssert { - internal static void AssertData(Data? expected, Data? actual) + internal static void AssertData(Data expected, Data actual) { if (expected is null) { diff --git a/src/DotTiled.Tests/Assert/AssertImage.cs b/src/DotTiled.Tests/Assert/AssertImage.cs index a674faa..6bb5f4e 100644 --- a/src/DotTiled.Tests/Assert/AssertImage.cs +++ b/src/DotTiled.Tests/Assert/AssertImage.cs @@ -2,7 +2,7 @@ namespace DotTiled.Tests; public static partial class DotTiledAssert { - internal static void AssertImage(Image? expected, Image? actual) + internal static void AssertImage(Image expected, Image actual) { if (expected is null) { diff --git a/src/DotTiled.Tests/Assert/AssertLayer.cs b/src/DotTiled.Tests/Assert/AssertLayer.cs index 5432d62..7dc8011 100644 --- a/src/DotTiled.Tests/Assert/AssertLayer.cs +++ b/src/DotTiled.Tests/Assert/AssertLayer.cs @@ -2,7 +2,7 @@ namespace DotTiled.Tests; public static partial class DotTiledAssert { - internal static void AssertLayer(BaseLayer? expected, BaseLayer? actual) + internal static void AssertLayer(BaseLayer expected, BaseLayer actual) { if (expected is null) { diff --git a/src/DotTiled.Tests/Assert/AssertProperties.cs b/src/DotTiled.Tests/Assert/AssertProperties.cs index 843d8d0..9454486 100644 --- a/src/DotTiled.Tests/Assert/AssertProperties.cs +++ b/src/DotTiled.Tests/Assert/AssertProperties.cs @@ -2,7 +2,7 @@ namespace DotTiled.Tests; public static partial class DotTiledAssert { - internal static void AssertProperties(IList? expected, IList? actual) + internal static void AssertProperties(IList expected, IList actual) { if (expected is null) { diff --git a/src/DotTiled.Tests/Assert/AssertTileset.cs b/src/DotTiled.Tests/Assert/AssertTileset.cs index 0c10279..607b542 100644 --- a/src/DotTiled.Tests/Assert/AssertTileset.cs +++ b/src/DotTiled.Tests/Assert/AssertTileset.cs @@ -43,7 +43,7 @@ public static partial class DotTiledAssert AssertEqual(expected.Y, actual.Y, nameof(TileOffset.Y)); } - private static void AssertGrid(Grid? expected, Grid? actual) + private static void AssertGrid(Grid expected, Grid actual) { if (expected is null) { @@ -86,7 +86,7 @@ public static partial class DotTiledAssert AssertEqual(expected.WangID, actual.WangID, nameof(WangTile.WangID)); } - private static void AssertTransformations(Transformations? expected, Transformations? actual) + private static void AssertTransformations(Transformations expected, Transformations actual) { if (expected is null) { diff --git a/src/DotTiled.Tests/Serialization/MapReaderTests.cs b/src/DotTiled.Tests/Serialization/MapReaderTests.cs index 0f365ab..885f57e 100644 --- a/src/DotTiled.Tests/Serialization/MapReaderTests.cs +++ b/src/DotTiled.Tests/Serialization/MapReaderTests.cs @@ -5,7 +5,7 @@ namespace DotTiled.Tests; public partial class MapReaderTests { public static IEnumerable Maps => TestData.MapTests; - [Theory(Skip = "Skipped for now")] + [Theory] [MemberData(nameof(Maps))] public void MapReaderReadMap_ValidFilesExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected( string testDataFile, diff --git a/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs b/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs index 0e76d84..23951de 100644 --- a/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs +++ b/src/DotTiled/Serialization/Tmj/ExtensionsJsonElement.cs @@ -15,13 +15,13 @@ internal static class ExtensionsJsonElement return property.GetValueAs(); } - internal static T GetOptionalProperty(this JsonElement element, string propertyName, T defaultValue) + internal static Optional GetOptionalProperty(this JsonElement element, string propertyName) { if (!element.TryGetProperty(propertyName, out var property)) - return defaultValue; + return Optional.Empty; if (property.ValueKind == JsonValueKind.Null) - return defaultValue; + return Optional.Empty; return property.GetValueAs(); } @@ -64,18 +64,18 @@ internal static class ExtensionsJsonElement return parser(property.GetString()!); } - internal static T GetOptionalPropertyParseable(this JsonElement element, string propertyName, T defaultValue) where T : IParsable + internal static Optional GetOptionalPropertyParseable(this JsonElement element, string propertyName) where T : IParsable { if (!element.TryGetProperty(propertyName, out var property)) - return defaultValue; + return Optional.Empty; return T.Parse(property.GetString()!, CultureInfo.InvariantCulture); } - internal static T GetOptionalPropertyParseable(this JsonElement element, string propertyName, Func parser, T defaultValue) + internal static Optional GetOptionalPropertyParseable(this JsonElement element, string propertyName, Func parser) { if (!element.TryGetProperty(propertyName, out var property)) - return defaultValue; + return Optional.Empty; return parser(property.GetString()!); } @@ -88,10 +88,10 @@ internal static class ExtensionsJsonElement return parser(property); } - internal static T GetOptionalPropertyCustom(this JsonElement element, string propertyName, Func parser, T defaultValue) + internal static Optional GetOptionalPropertyCustom(this JsonElement element, string propertyName, Func parser) { if (!element.TryGetProperty(propertyName, out var property)) - return defaultValue; + return Optional.Empty; return parser(property); } diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Data.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Data.cs index 76945ca..f42ddd5 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Data.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Data.cs @@ -6,7 +6,7 @@ namespace DotTiled.Serialization.Tmj; public abstract partial class TmjReaderBase { - internal static Data ReadDataAsChunks(JsonElement element, DataCompression? compression, DataEncoding encoding) + internal static Data ReadDataAsChunks(JsonElement element, Optional compression, DataEncoding encoding) { var chunks = element.GetValueAsList(e => ReadChunk(e, compression, encoding)).ToArray(); return new Data @@ -19,7 +19,7 @@ public abstract partial class TmjReaderBase }; } - internal static Chunk ReadChunk(JsonElement element, DataCompression? compression, DataEncoding encoding) + internal static Chunk ReadChunk(JsonElement element, Optional compression, DataEncoding encoding) { var data = ReadDataWithoutChunks(element, compression, encoding); @@ -39,7 +39,7 @@ public abstract partial class TmjReaderBase }; } - internal static Data ReadDataWithoutChunks(JsonElement element, DataCompression? compression, DataEncoding encoding) + internal static Data ReadDataWithoutChunks(JsonElement element, Optional compression, DataEncoding encoding) { if (encoding == DataEncoding.Csv) { @@ -52,7 +52,7 @@ public abstract partial class TmjReaderBase { var base64Data = element.GetBytesFromBase64(); - if (compression == null) + if (!compression.HasValue) { var data = Helpers.ReadBytesAsInt32Array(base64Data); var (globalTileIDs, flippingFlags) = Helpers.ReadAndClearFlippingFlagsFromGIDs(data); @@ -60,7 +60,7 @@ public abstract partial class TmjReaderBase } using var stream = new MemoryStream(base64Data); - var decompressed = compression switch + var decompressed = compression.Value switch { DataCompression.GZip => Helpers.DecompressGZip(stream), DataCompression.ZLib => Helpers.DecompressZLib(stream), diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs index ca08df8..9548f1c 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Group.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Globalization; using System.Text.Json; namespace DotTiled.Serialization.Tmj; @@ -10,16 +9,16 @@ public abstract partial class TmjReaderBase { var id = element.GetRequiredProperty("id"); var name = element.GetRequiredProperty("name"); - var @class = element.GetOptionalProperty("class", ""); - var opacity = element.GetOptionalProperty("opacity", 1.0f); - var visible = element.GetOptionalProperty("visible", true); - var tintColor = element.GetOptionalPropertyParseable("tintcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); - var offsetX = element.GetOptionalProperty("offsetx", 0.0f); - 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", ReadProperties, []); - var layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(ReadLayer), []); + var @class = element.GetOptionalProperty("class").GetValueOr(""); + var opacity = element.GetOptionalProperty("opacity").GetValueOr(1.0f); + var visible = element.GetOptionalProperty("visible").GetValueOr(true); + var tintColor = element.GetOptionalPropertyParseable("tintcolor"); + var offsetX = element.GetOptionalProperty("offsetx").GetValueOr(0.0f); + var offsetY = element.GetOptionalProperty("offsety").GetValueOr(0.0f); + var parallaxX = element.GetOptionalProperty("parallaxx").GetValueOr(1.0f); + var parallaxY = element.GetOptionalProperty("parallaxy").GetValueOr(1.0f); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(ReadLayer)).GetValueOr([]); return new Group { diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs index f115a52..7034663 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ImageLayer.cs @@ -1,4 +1,3 @@ -using System.Globalization; using System.Text.Json; namespace DotTiled.Serialization.Tmj; @@ -9,22 +8,22 @@ public abstract partial class TmjReaderBase { var id = element.GetRequiredProperty("id"); var name = element.GetRequiredProperty("name"); - var @class = element.GetOptionalProperty("class", ""); - var opacity = element.GetOptionalProperty("opacity", 1.0f); - var visible = element.GetOptionalProperty("visible", true); - var tintColor = element.GetOptionalPropertyParseable("tintcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); - var offsetX = element.GetOptionalProperty("offsetx", 0.0f); - 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", ReadProperties, []); + var @class = element.GetOptionalProperty("class").GetValueOr(""); + var opacity = element.GetOptionalProperty("opacity").GetValueOr(1.0f); + var visible = element.GetOptionalProperty("visible").GetValueOr(true); + var tintColor = element.GetOptionalPropertyParseable("tintcolor"); + var offsetX = element.GetOptionalProperty("offsetx").GetValueOr(0.0f); + var offsetY = element.GetOptionalProperty("offsety").GetValueOr(0.0f); + var parallaxX = element.GetOptionalProperty("parallaxx").GetValueOr(1.0f); + var parallaxY = element.GetOptionalProperty("parallaxy").GetValueOr(1.0f); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); var image = element.GetRequiredProperty("image"); - var repeatX = element.GetOptionalProperty("repeatx", false); - var repeatY = element.GetOptionalProperty("repeaty", false); - var transparentColor = element.GetOptionalPropertyParseable("transparentcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); - var x = element.GetOptionalProperty("x", 0); - var y = element.GetOptionalProperty("y", 0); + var repeatX = element.GetOptionalProperty("repeatx").GetValueOr(false); + var repeatY = element.GetOptionalProperty("repeaty").GetValueOr(false); + var transparentColor = element.GetOptionalPropertyParseable("transparentcolor"); + var x = element.GetOptionalProperty("x").GetValueOr(0); + var y = element.GetOptionalProperty("y").GetValueOr(0); var imgModel = new Image { diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs index ec45b8d..eaa0a9e 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Map.cs @@ -10,7 +10,7 @@ public abstract partial class TmjReaderBase { var version = element.GetRequiredProperty("version"); var tiledVersion = element.GetRequiredProperty("tiledversion"); - string @class = element.GetOptionalProperty("class", ""); + var @class = element.GetOptionalProperty("class").GetValueOr(""); var orientation = element.GetRequiredPropertyParseable("orientation", s => s switch { "orthogonal" => MapOrientation.Orthogonal, @@ -26,36 +26,36 @@ public abstract partial class TmjReaderBase "left-down" => RenderOrder.LeftDown, "left-up" => RenderOrder.LeftUp, _ => throw new JsonException($"Unknown render order '{s}'") - }, RenderOrder.RightDown); - var compressionLevel = element.GetOptionalProperty("compressionlevel", -1); + }).GetValueOr(RenderOrder.RightDown); + var compressionLevel = element.GetOptionalProperty("compressionlevel").GetValueOr(-1); var width = element.GetRequiredProperty("width"); var height = element.GetRequiredProperty("height"); var tileWidth = element.GetRequiredProperty("tilewidth"); var tileHeight = element.GetRequiredProperty("tileheight"); - var hexSideLength = element.GetOptionalProperty("hexsidelength", null); - var staggerAxis = element.GetOptionalPropertyParseable("staggeraxis", s => s switch + var hexSideLength = element.GetOptionalProperty("hexsidelength"); + var staggerAxis = element.GetOptionalPropertyParseable("staggeraxis", s => s switch { "x" => StaggerAxis.X, "y" => StaggerAxis.Y, _ => throw new JsonException($"Unknown stagger axis '{s}'") - }, null); - var staggerIndex = element.GetOptionalPropertyParseable("staggerindex", s => s switch + }); + var staggerIndex = element.GetOptionalPropertyParseable("staggerindex", s => s switch { "odd" => StaggerIndex.Odd, "even" => StaggerIndex.Even, _ => throw new JsonException($"Unknown stagger index '{s}'") - }, null); - var parallaxOriginX = element.GetOptionalProperty("parallaxoriginx", 0.0f); - var parallaxOriginY = element.GetOptionalProperty("parallaxoriginy", 0.0f); - var backgroundColor = element.GetOptionalPropertyParseable("backgroundcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), Color.Parse("#00000000", CultureInfo.InvariantCulture)); + }); + var parallaxOriginX = element.GetOptionalProperty("parallaxoriginx").GetValueOr(0f); + var parallaxOriginY = element.GetOptionalProperty("parallaxoriginy").GetValueOr(0f); + var backgroundColor = element.GetOptionalPropertyParseable("backgroundcolor").GetValueOr(Color.Parse("#00000000", CultureInfo.InvariantCulture)); var nextLayerID = element.GetRequiredProperty("nextlayerid"); var nextObjectID = element.GetRequiredProperty("nextobjectid"); - var infinite = element.GetOptionalProperty("infinite", false); + var infinite = element.GetOptionalProperty("infinite").GetValueOr(false); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); - List layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(el => ReadLayer(el)), []); - List tilesets = element.GetOptionalPropertyCustom>("tilesets", e => e.GetValueAsList(el => ReadTileset(el)), []); + List layers = element.GetOptionalPropertyCustom>("layers", e => e.GetValueAsList(el => ReadLayer(el))).GetValueOr([]); + List tilesets = element.GetOptionalPropertyCustom>("tilesets", e => e.GetValueAsList(el => ReadTileset(el, version, tiledVersion))).GetValueOr([]); return new Map { diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs index 1b8ef23..0456157 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.ObjectLayer.cs @@ -11,29 +11,29 @@ public abstract partial class TmjReaderBase { var id = element.GetRequiredProperty("id"); var name = element.GetRequiredProperty("name"); - var @class = element.GetOptionalProperty("class", ""); - var opacity = element.GetOptionalProperty("opacity", 1.0f); - var visible = element.GetOptionalProperty("visible", true); - var tintColor = element.GetOptionalPropertyParseable("tintcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); - var offsetX = element.GetOptionalProperty("offsetx", 0.0f); - 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", ReadProperties, []); + var @class = element.GetOptionalProperty("class").GetValueOr(""); + var opacity = element.GetOptionalProperty("opacity").GetValueOr(1.0f); + var visible = element.GetOptionalProperty("visible").GetValueOr(true); + var tintColor = element.GetOptionalPropertyParseable("tintcolor"); + var offsetX = element.GetOptionalProperty("offsetx").GetValueOr(0.0f); + var offsetY = element.GetOptionalProperty("offsety").GetValueOr(0.0f); + var parallaxX = element.GetOptionalProperty("parallaxx").GetValueOr(1.0f); + var parallaxY = element.GetOptionalProperty("parallaxy").GetValueOr(1.0f); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); - var x = element.GetOptionalProperty("x", 0); - var y = element.GetOptionalProperty("y", 0); - var width = element.GetOptionalProperty("width", null); - var height = element.GetOptionalProperty("height", null); - var color = element.GetOptionalPropertyParseable("color", s => Color.Parse(s, CultureInfo.InvariantCulture), null); + var x = element.GetOptionalProperty("x").GetValueOr(0); + var y = element.GetOptionalProperty("y").GetValueOr(0); + var width = element.GetOptionalProperty("width").GetValueOr(0); + var height = element.GetOptionalProperty("height").GetValueOr(0); + var color = element.GetOptionalPropertyParseable("color"); var drawOrder = element.GetOptionalPropertyParseable("draworder", s => s switch { "topdown" => DrawOrder.TopDown, "index" => DrawOrder.Index, _ => throw new JsonException($"Unknown draw order '{s}'.") - }, DrawOrder.TopDown); + }).GetValueOr(DrawOrder.TopDown); - var objects = element.GetOptionalPropertyCustom>("objects", e => e.GetValueAsList(el => ReadObject(el)), []); + var objects = element.GetOptionalPropertyCustom>("objects", e => e.GetValueAsList(el => ReadObject(el))).GetValueOr([]); return new ObjectLayer { @@ -50,8 +50,8 @@ public abstract partial class TmjReaderBase Properties = properties, X = x, Y = y, - Width = width ?? 0, - Height = height ?? 0, + Width = width, + Height = height, Color = color, DrawOrder = drawOrder, Objects = objects @@ -60,7 +60,7 @@ public abstract partial class TmjReaderBase internal DotTiled.Object ReadObject(JsonElement element) { - uint? idDefault = null; + Optional idDefault = Optional.Empty; string nameDefault = ""; string typeDefault = ""; float xDefault = 0f; @@ -68,16 +68,16 @@ public abstract partial class TmjReaderBase float widthDefault = 0f; float heightDefault = 0f; float rotationDefault = 0f; - uint? gidDefault = null; bool visibleDefault = true; bool ellipseDefault = false; bool pointDefault = false; - List? polygonDefault = null; - List? polylineDefault = null; + + List polygonDefault = null; + List polylineDefault = null; List propertiesDefault = []; - var template = element.GetOptionalProperty("template", null); - if (template is not null) + var template = element.GetOptionalProperty("template"); + if (template.HasValue) { var resolvedTemplate = _externalTemplateResolver(template); var templObj = resolvedTemplate.Object; @@ -98,24 +98,24 @@ public abstract partial class TmjReaderBase polylineDefault = (templObj is PolylineObject polylineObj) ? polylineObj.Points : null; } - var ellipse = element.GetOptionalProperty("ellipse", ellipseDefault); - var gid = element.GetOptionalProperty("gid", gidDefault); - var height = element.GetOptionalProperty("height", heightDefault); - var id = element.GetOptionalProperty("id", idDefault); - var name = element.GetOptionalProperty("name", nameDefault); - 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", ReadProperties, propertiesDefault); - var rotation = element.GetOptionalProperty("rotation", rotationDefault); - var text = element.GetOptionalPropertyCustom("text", ReadText, null); - var type = element.GetOptionalProperty("type", typeDefault); - var visible = element.GetOptionalProperty("visible", visibleDefault); - var width = element.GetOptionalProperty("width", widthDefault); - var x = element.GetOptionalProperty("x", xDefault); - var y = element.GetOptionalProperty("y", yDefault); + var ellipse = element.GetOptionalProperty("ellipse").GetValueOr(ellipseDefault); + var gid = element.GetOptionalProperty("gid"); + var height = element.GetOptionalProperty("height").GetValueOr(heightDefault); + var id = element.GetOptionalProperty("id").GetValueOrOptional(idDefault); + var name = element.GetOptionalProperty("name").GetValueOr(nameDefault); + var point = element.GetOptionalProperty("point").GetValueOr(pointDefault); + var polygon = element.GetOptionalPropertyCustom>("polygon", ReadPoints).GetValueOr(polygonDefault); + var polyline = element.GetOptionalPropertyCustom>("polyline", ReadPoints).GetValueOr(polylineDefault); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr(propertiesDefault); + var rotation = element.GetOptionalProperty("rotation").GetValueOr(rotationDefault); + var text = element.GetOptionalPropertyCustom("text", ReadText); + var type = element.GetOptionalProperty("type").GetValueOr(typeDefault); + var visible = element.GetOptionalProperty("visible").GetValueOr(visibleDefault); + var width = element.GetOptionalProperty("width").GetValueOr(widthDefault); + var x = element.GetOptionalProperty("x").GetValueOr(xDefault); + var y = element.GetOptionalProperty("y").GetValueOr(yDefault); - if (gid is not null) + if (gid.HasValue) { return new TileObject { @@ -208,19 +208,19 @@ public abstract partial class TmjReaderBase }; } - if (text is not null) + if (text.HasValue) { - text.ID = id; - text.Name = name; - text.Type = type; - text.X = x; - text.Y = y; - text.Width = width; - text.Height = height; - text.Rotation = rotation; - text.Visible = visible; - text.Template = template; - text.Properties = properties; + text.Value.ID = id; + text.Value.Name = name; + text.Value.Type = type; + text.Value.X = x; + text.Value.Y = y; + text.Value.Width = width; + text.Value.Height = height; + text.Value.Rotation = rotation; + text.Value.Visible = visible; + text.Value.Template = template; + text.Value.Properties = properties; return text; } @@ -250,30 +250,30 @@ public abstract partial class TmjReaderBase internal static TextObject ReadText(JsonElement element) { - var bold = element.GetOptionalProperty("bold", false); - var color = element.GetOptionalPropertyParseable("color", s => Color.Parse(s, CultureInfo.InvariantCulture), Color.Parse("#00000000", CultureInfo.InvariantCulture)); - var fontfamily = element.GetOptionalProperty("fontfamily", "sans-serif"); + var bold = element.GetOptionalProperty("bold").GetValueOr(false); + var color = element.GetOptionalPropertyParseable("color").GetValueOr(Color.Parse("#00000000", CultureInfo.InvariantCulture)); + var fontfamily = element.GetOptionalProperty("fontfamily").GetValueOr("sans-serif"); var halign = element.GetOptionalPropertyParseable("halign", s => s switch { "left" => TextHorizontalAlignment.Left, "center" => TextHorizontalAlignment.Center, "right" => TextHorizontalAlignment.Right, _ => throw new JsonException($"Unknown horizontal alignment '{s}'.") - }, TextHorizontalAlignment.Left); - var italic = element.GetOptionalProperty("italic", false); - var kerning = element.GetOptionalProperty("kerning", true); - var pixelsize = element.GetOptionalProperty("pixelsize", 16); - var strikeout = element.GetOptionalProperty("strikeout", false); + }).GetValueOr(TextHorizontalAlignment.Left); + var italic = element.GetOptionalProperty("italic").GetValueOr(false); + var kerning = element.GetOptionalProperty("kerning").GetValueOr(true); + var pixelsize = element.GetOptionalProperty("pixelsize").GetValueOr(16); + var strikeout = element.GetOptionalProperty("strikeout").GetValueOr(false); var text = element.GetRequiredProperty("text"); - var underline = element.GetOptionalProperty("underline", false); + var underline = element.GetOptionalProperty("underline").GetValueOr(false); var valign = element.GetOptionalPropertyParseable("valign", s => s switch { "top" => TextVerticalAlignment.Top, "center" => TextVerticalAlignment.Center, "bottom" => TextVerticalAlignment.Bottom, _ => throw new JsonException($"Unknown vertical alignment '{s}'.") - }, TextVerticalAlignment.Top); - var wrap = element.GetOptionalProperty("wrap", false); + }).GetValueOr(TextVerticalAlignment.Top); + var wrap = element.GetOptionalProperty("wrap").GetValueOr(false); return new TextObject { diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Properties.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Properties.cs index c8683b2..b877382 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Properties.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Properties.cs @@ -22,9 +22,9 @@ public abstract partial class TmjReaderBase "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) + }).GetValueOr(PropertyType.String); + var propertyType = e.GetOptionalProperty("propertytype"); + if (propertyType.HasValue) { return ReadPropertyWithCustomType(e); } @@ -48,7 +48,7 @@ public abstract partial class TmjReaderBase internal IProperty ReadPropertyWithCustomType(JsonElement element) { - var isClass = element.GetOptionalProperty("type", null) == "class"; + var isClass = element.GetOptionalProperty("type") == "class"; if (isClass) { return ReadClassProperty(element); @@ -66,7 +66,7 @@ public abstract partial class TmjReaderBase if (customTypeDef is CustomClassDefinition ccd) { var propsInType = Helpers.CreateInstanceOfCustomClass(ccd, _customTypeResolver); - var props = element.GetOptionalPropertyCustom>("value", e => ReadPropertiesInsideClass(e, ccd), []); + var props = element.GetOptionalPropertyCustom>("value", e => ReadPropertiesInsideClass(e, ccd)).GetValueOr([]); var mergedProps = Helpers.MergeProperties(propsInType, props); return new ClassProperty @@ -120,7 +120,7 @@ public abstract partial class TmjReaderBase "string" => PropertyType.String, "int" => PropertyType.Int, _ => throw new JsonException("Invalid property type") - }, PropertyType.String); + }).GetValueOr(PropertyType.String); var customTypeDef = _customTypeResolver(propertyType); if (customTypeDef is not CustomEnumDefinition ced) diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs index 88bcf09..1bda13a 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Template.cs @@ -7,7 +7,7 @@ public abstract partial class TmjReaderBase internal Template ReadTemplate(JsonElement element) { var type = element.GetRequiredProperty("type"); - var tileset = element.GetOptionalPropertyCustom("tileset", ReadTileset, null); + var tileset = element.GetOptionalPropertyCustom("tileset", e => ReadTileset(e)); 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 e3ccc9a..7c8791a 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.TileLayer.cs @@ -1,4 +1,3 @@ -using System.Globalization; using System.Text.Json; namespace DotTiled.Serialization.Tmj; @@ -7,43 +6,43 @@ public abstract partial class TmjReaderBase { internal TileLayer ReadTileLayer(JsonElement element) { - var compression = element.GetOptionalPropertyParseable("compression", s => s switch - { - "zlib" => DataCompression.ZLib, - "gzip" => DataCompression.GZip, - "" => null, - _ => throw new JsonException($"Unsupported compression '{s}'.") - }, null); var encoding = element.GetOptionalPropertyParseable("encoding", s => s switch { "csv" => DataEncoding.Csv, "base64" => DataEncoding.Base64, _ => throw new JsonException($"Unsupported encoding '{s}'.") - }, DataEncoding.Csv); - var chunks = element.GetOptionalPropertyCustom("chunks", e => ReadDataAsChunks(e, compression, encoding), null); - var @class = element.GetOptionalProperty("class", ""); - var data = element.GetOptionalPropertyCustom("data", e => ReadDataWithoutChunks(e, compression, encoding), null); + }).GetValueOr(DataEncoding.Csv); + var compression = element.GetOptionalPropertyParseable("compression", s => s switch + { + "zlib" => DataCompression.ZLib, + "gzip" => DataCompression.GZip, + "" => Optional.Empty, + _ => throw new JsonException($"Unsupported compression '{s}'.") + }); + var chunks = element.GetOptionalPropertyCustom("chunks", e => ReadDataAsChunks(e, compression, encoding)); + var @class = element.GetOptionalProperty("class").GetValueOr(""); + var data = element.GetOptionalPropertyCustom("data", e => ReadDataWithoutChunks(e, compression, encoding)); var height = element.GetRequiredProperty("height"); var id = element.GetRequiredProperty("id"); var name = element.GetRequiredProperty("name"); - var offsetX = element.GetOptionalProperty("offsetx", 0.0f); - var offsetY = element.GetOptionalProperty("offsety", 0.0f); - 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", ReadProperties, []); - var repeatX = element.GetOptionalProperty("repeatx", false); - var repeatY = element.GetOptionalProperty("repeaty", false); - var startX = element.GetOptionalProperty("startx", 0); - var startY = element.GetOptionalProperty("starty", 0); - var tintColor = element.GetOptionalPropertyParseable("tintcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); - var transparentColor = element.GetOptionalPropertyParseable("transparentcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); - var visible = element.GetOptionalProperty("visible", true); + var offsetX = element.GetOptionalProperty("offsetx").GetValueOr(0.0f); + var offsetY = element.GetOptionalProperty("offsety").GetValueOr(0.0f); + var opacity = element.GetOptionalProperty("opacity").GetValueOr(1.0f); + var parallaxx = element.GetOptionalProperty("parallaxx").GetValueOr(1.0f); + var parallaxy = element.GetOptionalProperty("parallaxy").GetValueOr(1.0f); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var repeatX = element.GetOptionalProperty("repeatx").GetValueOr(false); + var repeatY = element.GetOptionalProperty("repeaty").GetValueOr(false); + var startX = element.GetOptionalProperty("startx").GetValueOr(0); + var startY = element.GetOptionalProperty("starty").GetValueOr(0); + var tintColor = element.GetOptionalPropertyParseable("tintcolor"); + var transparentColor = element.GetOptionalPropertyParseable("transparentcolor"); + var visible = element.GetOptionalProperty("visible").GetValueOr(true); var width = element.GetRequiredProperty("width"); var x = element.GetRequiredProperty("x"); var y = element.GetRequiredProperty("y"); - if ((data ?? chunks) is null) + if (!data.HasValue && !chunks.HasValue) throw new JsonException("Tile layer does not contain data."); return new TileLayer diff --git a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs index 8a41117..ea91acf 100644 --- a/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs +++ b/src/DotTiled/Serialization/Tmj/TmjReaderBase.Tileset.cs @@ -1,29 +1,31 @@ using System.Collections.Generic; -using System.Globalization; using System.Text.Json; namespace DotTiled.Serialization.Tmj; public abstract partial class TmjReaderBase { - internal Tileset ReadTileset(JsonElement element) + internal Tileset ReadTileset( + JsonElement element, + Optional parentVersion = null, + Optional parentTiledVersion = null) { - var backgroundColor = element.GetOptionalPropertyParseable("backgroundcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); - var @class = element.GetOptionalProperty("class", ""); - var columns = element.GetOptionalProperty("columns", null); + var backgroundColor = element.GetOptionalPropertyParseable("backgroundcolor"); + var @class = element.GetOptionalProperty("class").GetValueOr(""); + var columns = element.GetOptionalProperty("columns"); var fillMode = element.GetOptionalPropertyParseable("fillmode", s => s switch { "stretch" => FillMode.Stretch, "preserve-aspect-fit" => FillMode.PreserveAspectFit, _ => throw new JsonException($"Unknown fill mode '{s}'") - }, FillMode.Stretch); - var firstGID = element.GetOptionalProperty("firstgid", null); - var grid = element.GetOptionalPropertyCustom("grid", ReadGrid, null); - var image = element.GetOptionalProperty("image", null); - var imageHeight = element.GetOptionalProperty("imageheight", null); - var imageWidth = element.GetOptionalProperty("imagewidth", null); - var margin = element.GetOptionalProperty("margin", null); - var name = element.GetOptionalProperty("name", null); + }).GetValueOr(FillMode.Stretch); + var firstGID = element.GetOptionalProperty("firstgid"); + var grid = element.GetOptionalPropertyCustom("grid", ReadGrid); + var image = element.GetOptionalProperty("image"); + var imageHeight = element.GetOptionalProperty("imageheight"); + var imageWidth = element.GetOptionalProperty("imagewidth"); + var margin = element.GetOptionalProperty("margin"); + var name = element.GetOptionalProperty("name"); var objectAlignment = element.GetOptionalPropertyParseable("objectalignment", s => s switch { "unspecified" => ObjectAlignment.Unspecified, @@ -37,29 +39,29 @@ public abstract partial class TmjReaderBase "bottom" => ObjectAlignment.Bottom, "bottomright" => ObjectAlignment.BottomRight, _ => throw new JsonException($"Unknown object alignment '{s}'") - }, ObjectAlignment.Unspecified); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); - var source = element.GetOptionalProperty("source", null); - var spacing = element.GetOptionalProperty("spacing", null); - var tileCount = element.GetOptionalProperty("tilecount", null); - var tiledVersion = element.GetOptionalProperty("tiledversion", null); - var tileHeight = element.GetOptionalProperty("tileheight", null); - var tileOffset = element.GetOptionalPropertyCustom("tileoffset", ReadTileOffset, null); + }).GetValueOr(ObjectAlignment.Unspecified); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var source = element.GetOptionalProperty("source"); + var spacing = element.GetOptionalProperty("spacing"); + var tileCount = element.GetOptionalProperty("tilecount"); + var tiledVersion = element.GetOptionalProperty("tiledversion").GetValueOrOptional(parentTiledVersion); + var tileHeight = element.GetOptionalProperty("tileheight"); + var tileOffset = element.GetOptionalPropertyCustom("tileoffset", ReadTileOffset); var tileRenderSize = element.GetOptionalPropertyParseable("tilerendersize", s => s switch { "tile" => TileRenderSize.Tile, "grid" => TileRenderSize.Grid, _ => throw new JsonException($"Unknown tile render size '{s}'") - }, TileRenderSize.Tile); - 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)), null); + }).GetValueOr(TileRenderSize.Tile); + var tiles = element.GetOptionalPropertyCustom>("tiles", ReadTiles).GetValueOr([]); + var tileWidth = element.GetOptionalProperty("tilewidth"); + var transparentColor = element.GetOptionalPropertyParseable("transparentcolor"); + var type = element.GetOptionalProperty("type"); + var version = element.GetOptionalProperty("version").GetValueOrOptional(parentVersion); + var transformations = element.GetOptionalPropertyCustom("transformations", ReadTransformations); + var wangsets = element.GetOptionalPropertyCustom>("wangsets", el => el.GetValueAsList(e => ReadWangset(e))).GetValueOr([]); - if (source is not null) + if (source.HasValue) { var resolvedTileset = _externalTilesetResolver(source); resolvedTileset.FirstGID = firstGID; @@ -67,49 +69,48 @@ public abstract partial class TmjReaderBase return resolvedTileset; } - var imageModel = image is not null ? new Image + Optional imageModel = image.HasValue ? new Image { Format = Helpers.ParseImageFormatFromSource(image), Source = image, Height = imageHeight, Width = imageWidth, TransparentColor = transparentColor - } : null; + } : Optional.Empty; - return null; - // return new Tileset - // { - // Class = @class, - // Columns = columns, - // FillMode = fillMode, - // FirstGID = firstGID, - // Grid = grid, - // Image = imageModel, - // Margin = margin, - // Name = name, - // ObjectAlignment = objectAlignment, - // Properties = properties, - // Source = source, - // Spacing = spacing, - // TileCount = tileCount, - // TiledVersion = tiledVersion, - // TileHeight = tileHeight, - // TileOffset = tileOffset, - // RenderSize = tileRenderSize, - // Tiles = tiles, - // TileWidth = tileWidth, - // Version = version, - // Wangsets = wangsets, - // Transformations = transformations - // }; + return new Tileset + { + Class = @class, + Columns = columns, + FillMode = fillMode, + FirstGID = firstGID, + Grid = grid, + Image = imageModel, + Margin = margin, + Name = name, + ObjectAlignment = objectAlignment, + Properties = properties, + Source = source, + Spacing = spacing, + TileCount = tileCount, + TiledVersion = tiledVersion, + TileHeight = tileHeight, + TileOffset = tileOffset, + RenderSize = tileRenderSize, + Tiles = tiles, + TileWidth = tileWidth, + Version = version, + Wangsets = wangsets, + Transformations = transformations + }; } internal static Transformations ReadTransformations(JsonElement element) { - var hFlip = element.GetOptionalProperty("hflip", false); - var vFlip = element.GetOptionalProperty("vflip", false); - var rotate = element.GetOptionalProperty("rotate", false); - var preferUntransformed = element.GetOptionalProperty("preferuntransformed", false); + var hFlip = element.GetOptionalProperty("hflip").GetValueOr(false); + var vFlip = element.GetOptionalProperty("vflip").GetValueOr(false); + var rotate = element.GetOptionalProperty("rotate").GetValueOr(false); + var preferUntransformed = element.GetOptionalProperty("preferuntransformed").GetValueOr(false); return new Transformations { @@ -127,7 +128,7 @@ public abstract partial class TmjReaderBase "orthogonal" => GridOrientation.Orthogonal, "isometric" => GridOrientation.Isometric, _ => throw new JsonException($"Unknown grid orientation '{s}'") - }, GridOrientation.Orthogonal); + }).GetValueOr(GridOrientation.Orthogonal); var height = element.GetRequiredProperty("height"); var width = element.GetRequiredProperty("width"); @@ -154,28 +155,27 @@ public abstract partial class TmjReaderBase internal List ReadTiles(JsonElement element) => element.GetValueAsList(e => { - var animation = e.GetOptionalPropertyCustom?>("animation", e => e.GetValueAsList(ReadFrame), null); + var animation = e.GetOptionalPropertyCustom>("animation", e => e.GetValueAsList(ReadFrame)).GetValueOr([]); var id = e.GetRequiredProperty("id"); - var image = e.GetOptionalProperty("image", null); - var imageHeight = e.GetOptionalProperty("imageheight", null); - var imageWidth = e.GetOptionalProperty("imagewidth", null); - var x = e.GetOptionalProperty("x", 0); - 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), null); - var probability = e.GetOptionalProperty("probability", 0.0f); - var properties = e.GetOptionalPropertyCustom("properties", ReadProperties, []); - // var terrain, replaced by wangsets - var type = e.GetOptionalProperty("type", ""); + var image = e.GetOptionalProperty("image"); + var imageHeight = e.GetOptionalProperty("imageheight"); + var imageWidth = e.GetOptionalProperty("imagewidth"); + var x = e.GetOptionalProperty("x").GetValueOr(0); + var y = e.GetOptionalProperty("y").GetValueOr(0); + var width = e.GetOptionalProperty("width").GetValueOr(imageWidth.GetValueOr(0)); + var height = e.GetOptionalProperty("height").GetValueOr(imageHeight.GetValueOr(0)); + var objectGroup = e.GetOptionalPropertyCustom("objectgroup", e => ReadObjectLayer(e)); + var probability = e.GetOptionalProperty("probability").GetValueOr(0.0f); + var properties = e.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var type = e.GetOptionalProperty("type").GetValueOr(""); - var imageModel = image != null ? new Image + Optional imageModel = image.HasValue ? new Image { Format = Helpers.ParseImageFormatFromSource(image), Source = image, Height = imageHeight ?? 0, Width = imageWidth ?? 0 - } : null; + } : Optional.Empty; return new Tile { @@ -207,13 +207,13 @@ public abstract partial class TmjReaderBase internal Wangset ReadWangset(JsonElement element) { - var @clalss = element.GetOptionalProperty("class", ""); - var colors = element.GetOptionalPropertyCustom>("colors", e => e.GetValueAsList(el => ReadWangColor(el)), []); + var @clalss = element.GetOptionalProperty("class").GetValueOr(""); + var colors = element.GetOptionalPropertyCustom>("colors", e => e.GetValueAsList(el => ReadWangColor(el))).GetValueOr([]); var name = element.GetRequiredProperty("name"); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); - var tile = element.GetOptionalProperty("tile", 0); - var type = element.GetOptionalProperty("type", ""); - var wangTiles = element.GetOptionalPropertyCustom>("wangtiles", e => e.GetValueAsList(ReadWangTile), []); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var tile = element.GetOptionalProperty("tile").GetValueOr(0); + var type = element.GetOptionalProperty("type").GetValueOr(""); + var wangTiles = element.GetOptionalPropertyCustom>("wangtiles", e => e.GetValueAsList(ReadWangTile)).GetValueOr([]); return new Wangset { @@ -228,12 +228,12 @@ public abstract partial class TmjReaderBase internal WangColor ReadWangColor(JsonElement element) { - var @class = element.GetOptionalProperty("class", ""); - var color = element.GetRequiredPropertyParseable("color", s => Color.Parse(s, CultureInfo.InvariantCulture)); + var @class = element.GetOptionalProperty("class").GetValueOr(""); + var color = element.GetRequiredPropertyParseable("color"); var name = element.GetRequiredProperty("name"); - var probability = element.GetOptionalProperty("probability", 1.0f); - var properties = element.GetOptionalPropertyCustom("properties", ReadProperties, []); - var tile = element.GetOptionalProperty("tile", 0); + var probability = element.GetOptionalProperty("probability").GetValueOr(1.0f); + var properties = element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]); + var tile = element.GetOptionalProperty("tile").GetValueOr(0); return new WangColor { @@ -249,7 +249,7 @@ public abstract partial class TmjReaderBase internal static WangTile ReadWangTile(JsonElement element) { var tileID = element.GetRequiredProperty("tileid"); - var wangID = element.GetOptionalPropertyCustom>("wangid", e => e.GetValueAsList(el => (byte)el.GetUInt32()), []); + var wangID = element.GetOptionalPropertyCustom>("wangid", e => e.GetValueAsList(el => (byte)el.GetUInt32())).GetValueOr([]); return new WangTile { diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs index af2e759..67cd69a 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.ObjectLayer.cs @@ -301,10 +301,10 @@ public abstract partial class TmxReaderBase // No attributes // At most one of - Tileset? tileset = null; + Tileset tileset = null; // Should contain exactly one of - DotTiled.Object? obj = null; + DotTiled.Object obj = null; _reader.ProcessChildren("template", (r, elementName) => elementName switch { diff --git a/src/DotTiled/Template.cs b/src/DotTiled/Template.cs index 56052de..24b237e 100644 --- a/src/DotTiled/Template.cs +++ b/src/DotTiled/Template.cs @@ -8,7 +8,7 @@ public class Template /// /// If the template represents a tile object, this property will contain the tileset that the tile belongs to. /// - public Tileset? Tileset { get; set; } + public Optional Tileset { get; set; } = Optional.Empty; /// /// The object that this template represents.