Merge pull request #3 from dcronqvist/more-tests

Add more tests that parse both XML and JSON maps
This commit is contained in:
dcronqvist 2024-08-14 20:36:29 +02:00 committed by GitHub
commit 7f81feaf6b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
95 changed files with 2182 additions and 1413 deletions

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;

View file

@ -12,17 +12,17 @@ public static partial class DotTiledAssert
// Attributes // Attributes
Assert.NotNull(actual); Assert.NotNull(actual);
Assert.Equal(expected.Encoding, actual.Encoding); AssertEqual(expected.Encoding, actual.Encoding, nameof(Data.Encoding));
Assert.Equal(expected.Compression, actual.Compression); AssertEqual(expected.Compression, actual.Compression, nameof(Data.Compression));
// Data // Data
Assert.Equal(expected.GlobalTileIDs, actual.GlobalTileIDs); AssertEqual(expected.GlobalTileIDs, actual.GlobalTileIDs, nameof(Data.GlobalTileIDs));
Assert.Equal(expected.FlippingFlags, actual.FlippingFlags); AssertEqual(expected.FlippingFlags, actual.FlippingFlags, nameof(Data.FlippingFlags));
if (expected.Chunks is not null) if (expected.Chunks is not null)
{ {
Assert.NotNull(actual.Chunks); Assert.NotNull(actual.Chunks);
Assert.Equal(expected.Chunks.Length, actual.Chunks.Length); AssertEqual(expected.Chunks.Length, actual.Chunks.Length, "Chunks.Length");
for (var i = 0; i < expected.Chunks.Length; i++) for (var i = 0; i < expected.Chunks.Length; i++)
AssertChunk(expected.Chunks[i], actual.Chunks[i]); AssertChunk(expected.Chunks[i], actual.Chunks[i]);
} }
@ -31,13 +31,13 @@ public static partial class DotTiledAssert
private static void AssertChunk(Chunk expected, Chunk actual) private static void AssertChunk(Chunk expected, Chunk actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.X, actual.X); AssertEqual(expected.X, actual.X, nameof(Chunk.X));
Assert.Equal(expected.Y, actual.Y); AssertEqual(expected.Y, actual.Y, nameof(Chunk.Y));
Assert.Equal(expected.Width, actual.Width); AssertEqual(expected.Width, actual.Width, nameof(Chunk.Width));
Assert.Equal(expected.Height, actual.Height); AssertEqual(expected.Height, actual.Height, nameof(Chunk.Height));
// Data // Data
Assert.Equal(expected.GlobalTileIDs, actual.GlobalTileIDs); AssertEqual(expected.GlobalTileIDs, actual.GlobalTileIDs, nameof(Chunk.GlobalTileIDs));
Assert.Equal(expected.FlippingFlags, actual.FlippingFlags); AssertEqual(expected.FlippingFlags, actual.FlippingFlags, nameof(Chunk.FlippingFlags));
} }
} }

View file

@ -12,10 +12,10 @@ public static partial class DotTiledAssert
// Attributes // Attributes
Assert.NotNull(actual); Assert.NotNull(actual);
Assert.Equal(expected.Format, actual.Format); AssertEqual(expected.Format, actual.Format, nameof(Image.Format));
Assert.Equal(expected.Source, actual.Source); AssertEqual(expected.Source, actual.Source, nameof(Image.Source));
Assert.Equal(expected.TransparentColor, actual.TransparentColor); AssertEqual(expected.TransparentColor, actual.TransparentColor, nameof(Image.TransparentColor));
Assert.Equal(expected.Width, actual.Width); AssertEqual(expected.Width, actual.Width, nameof(Image.Width));
Assert.Equal(expected.Height, actual.Height); AssertEqual(expected.Height, actual.Height, nameof(Image.Height));
} }
} }

View file

@ -12,16 +12,16 @@ public static partial class DotTiledAssert
// Attributes // Attributes
Assert.NotNull(actual); Assert.NotNull(actual);
Assert.Equal(expected.ID, actual.ID); AssertEqual(expected.ID, actual.ID, nameof(BaseLayer.ID));
Assert.Equal(expected.Name, actual.Name); AssertEqual(expected.Name, actual.Name, nameof(BaseLayer.Name));
Assert.Equal(expected.Class, actual.Class); AssertEqual(expected.Class, actual.Class, nameof(BaseLayer.Class));
Assert.Equal(expected.Opacity, actual.Opacity); AssertEqual(expected.Opacity, actual.Opacity, nameof(BaseLayer.Opacity));
Assert.Equal(expected.Visible, actual.Visible); AssertEqual(expected.Visible, actual.Visible, nameof(BaseLayer.Visible));
Assert.Equal(expected.TintColor, actual.TintColor); AssertEqual(expected.TintColor, actual.TintColor, nameof(BaseLayer.TintColor));
Assert.Equal(expected.OffsetX, actual.OffsetX); AssertEqual(expected.OffsetX, actual.OffsetX, nameof(BaseLayer.OffsetX));
Assert.Equal(expected.OffsetY, actual.OffsetY); AssertEqual(expected.OffsetY, actual.OffsetY, nameof(BaseLayer.OffsetY));
Assert.Equal(expected.ParallaxX, actual.ParallaxX); AssertEqual(expected.ParallaxX, actual.ParallaxX, nameof(BaseLayer.ParallaxX));
Assert.Equal(expected.ParallaxY, actual.ParallaxY); AssertEqual(expected.ParallaxY, actual.ParallaxY, nameof(BaseLayer.ParallaxY));
AssertProperties(expected.Properties, actual.Properties); AssertProperties(expected.Properties, actual.Properties);
AssertLayer((dynamic)expected, (dynamic)actual); AssertLayer((dynamic)expected, (dynamic)actual);
@ -30,10 +30,10 @@ public static partial class DotTiledAssert
private static void AssertLayer(TileLayer expected, TileLayer actual) private static void AssertLayer(TileLayer expected, TileLayer actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.Width, actual.Width); AssertEqual(expected.Width, actual.Width, nameof(TileLayer.Width));
Assert.Equal(expected.Height, actual.Height); AssertEqual(expected.Height, actual.Height, nameof(TileLayer.Height));
Assert.Equal(expected.X, actual.X); AssertEqual(expected.X, actual.X, nameof(TileLayer.X));
Assert.Equal(expected.Y, actual.Y); AssertEqual(expected.Y, actual.Y, nameof(TileLayer.Y));
Assert.NotNull(actual.Data); Assert.NotNull(actual.Data);
AssertData(expected.Data, actual.Data); AssertData(expected.Data, actual.Data);
@ -42,12 +42,12 @@ public static partial class DotTiledAssert
private static void AssertLayer(ObjectLayer expected, ObjectLayer actual) private static void AssertLayer(ObjectLayer expected, ObjectLayer actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.DrawOrder, actual.DrawOrder); AssertEqual(expected.DrawOrder, actual.DrawOrder, nameof(ObjectLayer.DrawOrder));
Assert.Equal(expected.X, actual.X); AssertEqual(expected.X, actual.X, nameof(ObjectLayer.X));
Assert.Equal(expected.Y, actual.Y); AssertEqual(expected.Y, actual.Y, nameof(ObjectLayer.Y));
Assert.NotNull(actual.Objects); Assert.NotNull(actual.Objects);
Assert.Equal(expected.Objects.Count, actual.Objects.Count); AssertEqual(expected.Objects.Count, actual.Objects.Count, "Objects.Count");
for (var i = 0; i < expected.Objects.Count; i++) for (var i = 0; i < expected.Objects.Count; i++)
AssertObject(expected.Objects[i], actual.Objects[i]); AssertObject(expected.Objects[i], actual.Objects[i]);
} }
@ -55,10 +55,10 @@ public static partial class DotTiledAssert
private static void AssertLayer(ImageLayer expected, ImageLayer actual) private static void AssertLayer(ImageLayer expected, ImageLayer actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.RepeatX, actual.RepeatX); AssertEqual(expected.RepeatX, actual.RepeatX, nameof(ImageLayer.RepeatX));
Assert.Equal(expected.RepeatY, actual.RepeatY); AssertEqual(expected.RepeatY, actual.RepeatY, nameof(ImageLayer.RepeatY));
Assert.Equal(expected.X, actual.X); AssertEqual(expected.X, actual.X, nameof(ImageLayer.X));
Assert.Equal(expected.Y, actual.Y); AssertEqual(expected.Y, actual.Y, nameof(ImageLayer.Y));
Assert.NotNull(actual.Image); Assert.NotNull(actual.Image);
AssertImage(expected.Image, actual.Image); AssertImage(expected.Image, actual.Image);
@ -68,7 +68,7 @@ public static partial class DotTiledAssert
{ {
// Attributes // Attributes
Assert.NotNull(actual.Layers); Assert.NotNull(actual.Layers);
Assert.Equal(expected.Layers.Count, actual.Layers.Count); AssertEqual(expected.Layers.Count, actual.Layers.Count, "Layers.Count");
for (var i = 0; i < expected.Layers.Count; i++) for (var i = 0; i < expected.Layers.Count; i++)
AssertLayer(expected.Layers[i], actual.Layers[i]); AssertLayer(expected.Layers[i], actual.Layers[i]);
} }

View file

@ -1,39 +1,104 @@
using System.Collections;
using System.Numerics;
namespace DotTiled.Tests; namespace DotTiled.Tests;
public static partial class DotTiledAssert public static partial class DotTiledAssert
{ {
private static void AssertEqual<T>(T expected, T actual, string nameof)
{
if (expected == null)
{
Assert.Null(actual);
return;
}
if (typeof(T) == typeof(float))
{
var expectedFloat = (float)(object)expected;
var actualFloat = (float)(object)actual!;
var expecRounded = MathF.Round(expectedFloat, 3);
var actRounded = MathF.Round(actualFloat, 3);
Assert.True(expecRounded == actRounded, $"Expected {nameof} '{expecRounded}' but got '{actRounded}'");
return;
}
if (expected is Vector2)
{
var expectedVector = (Vector2)(object)expected;
var actualVector = (Vector2)(object)actual!;
AssertEqual(expectedVector.X, actualVector.X, $"{nameof}.X");
AssertEqual(expectedVector.Y, actualVector.Y, $"{nameof}.Y");
return;
}
if (typeof(T).IsArray)
{
var expectedArray = (Array)(object)expected;
var actualArray = (Array)(object)actual!;
Assert.NotNull(actualArray);
AssertEqual(expectedArray.Length, actualArray.Length, $"{nameof}.Length");
for (var i = 0; i < expectedArray.Length; i++)
AssertEqual(expectedArray.GetValue(i), actualArray.GetValue(i), $"{nameof}[{i}]");
return;
}
if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(List<>))
{
var expectedList = (IList)(object)expected;
var actualList = (IList)(object)actual!;
Assert.NotNull(actualList);
AssertEqual(expectedList.Count, actualList.Count, $"{nameof}.Count");
for (var i = 0; i < expectedList.Count; i++)
AssertEqual(expectedList[i], actualList[i], $"{nameof}[{i}]");
return;
}
Assert.True(expected.Equals(actual), $"Expected {nameof} '{expected}' but got '{actual}'");
}
internal static void AssertMap(Map expected, Map actual) internal static void AssertMap(Map expected, Map actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.Version, actual.Version); AssertEqual(expected.Version, actual.Version, nameof(Map.Version));
Assert.Equal(expected.TiledVersion, actual.TiledVersion); AssertEqual(expected.TiledVersion, actual.TiledVersion, nameof(Map.TiledVersion));
Assert.Equal(expected.Class, actual.Class); AssertEqual(expected.Class, actual.Class, nameof(Map.Class));
Assert.Equal(expected.Orientation, actual.Orientation); AssertEqual(expected.Orientation, actual.Orientation, nameof(Map.Orientation));
Assert.Equal(expected.RenderOrder, actual.RenderOrder); AssertEqual(expected.RenderOrder, actual.RenderOrder, nameof(Map.RenderOrder));
Assert.Equal(expected.CompressionLevel, actual.CompressionLevel); AssertEqual(expected.CompressionLevel, actual.CompressionLevel, nameof(Map.CompressionLevel));
Assert.Equal(expected.Width, actual.Width); AssertEqual(expected.Width, actual.Width, nameof(Map.Width));
Assert.Equal(expected.Height, actual.Height); AssertEqual(expected.Height, actual.Height, nameof(Map.Height));
Assert.Equal(expected.TileWidth, actual.TileWidth); AssertEqual(expected.TileWidth, actual.TileWidth, nameof(Map.TileWidth));
Assert.Equal(expected.TileHeight, actual.TileHeight); AssertEqual(expected.TileHeight, actual.TileHeight, nameof(Map.TileHeight));
Assert.Equal(expected.HexSideLength, actual.HexSideLength); AssertEqual(expected.HexSideLength, actual.HexSideLength, nameof(Map.HexSideLength));
Assert.Equal(expected.StaggerAxis, actual.StaggerAxis); AssertEqual(expected.StaggerAxis, actual.StaggerAxis, nameof(Map.StaggerAxis));
Assert.Equal(expected.StaggerIndex, actual.StaggerIndex); AssertEqual(expected.StaggerIndex, actual.StaggerIndex, nameof(Map.StaggerIndex));
Assert.Equal(expected.ParallaxOriginX, actual.ParallaxOriginX); AssertEqual(expected.ParallaxOriginX, actual.ParallaxOriginX, nameof(Map.ParallaxOriginX));
Assert.Equal(expected.ParallaxOriginY, actual.ParallaxOriginY); AssertEqual(expected.ParallaxOriginY, actual.ParallaxOriginY, nameof(Map.ParallaxOriginY));
Assert.Equal(expected.BackgroundColor, actual.BackgroundColor); AssertEqual(expected.BackgroundColor, actual.BackgroundColor, nameof(Map.BackgroundColor));
Assert.Equal(expected.NextLayerID, actual.NextLayerID); AssertEqual(expected.NextLayerID, actual.NextLayerID, nameof(Map.NextLayerID));
Assert.Equal(expected.NextObjectID, actual.NextObjectID); AssertEqual(expected.NextObjectID, actual.NextObjectID, nameof(Map.NextObjectID));
Assert.Equal(expected.Infinite, actual.Infinite); AssertEqual(expected.Infinite, actual.Infinite, nameof(Map.Infinite));
AssertProperties(actual.Properties, expected.Properties); AssertProperties(actual.Properties, expected.Properties);
Assert.NotNull(actual.Tilesets); Assert.NotNull(actual.Tilesets);
Assert.Equal(expected.Tilesets.Count, actual.Tilesets.Count); AssertEqual(expected.Tilesets.Count, actual.Tilesets.Count, "Tilesets.Count");
for (var i = 0; i < expected.Tilesets.Count; i++) for (var i = 0; i < expected.Tilesets.Count; i++)
AssertTileset(expected.Tilesets[i], actual.Tilesets[i]); AssertTileset(expected.Tilesets[i], actual.Tilesets[i]);
Assert.NotNull(actual.Layers); Assert.NotNull(actual.Layers);
Assert.Equal(expected.Layers.Count, actual.Layers.Count); AssertEqual(expected.Layers.Count, actual.Layers.Count, "Layers.Count");
for (var i = 0; i < expected.Layers.Count; i++) for (var i = 0; i < expected.Layers.Count; i++)
AssertLayer(expected.Layers[i], actual.Layers[i]); AssertLayer(expected.Layers[i], actual.Layers[i]);
} }

View file

@ -5,19 +5,20 @@ public static partial class DotTiledAssert
internal static void AssertObject(Object expected, Object actual) internal static void AssertObject(Object expected, Object actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.ID, actual.ID); AssertEqual(expected.ID, actual.ID, nameof(Object.ID));
Assert.Equal(expected.Name, actual.Name); AssertEqual(expected.Name, actual.Name, nameof(Object.Name));
Assert.Equal(expected.Type, actual.Type); AssertEqual(expected.Type, actual.Type, nameof(Object.Type));
Assert.Equal(expected.X, actual.X); AssertEqual(expected.X, actual.X, nameof(Object.X));
Assert.Equal(expected.Y, actual.Y); AssertEqual(expected.Y, actual.Y, nameof(Object.Y));
Assert.Equal(expected.Width, actual.Width); AssertEqual(expected.Width, actual.Width, nameof(Object.Width));
Assert.Equal(expected.Height, actual.Height); AssertEqual(expected.Height, actual.Height, nameof(Object.Height));
Assert.Equal(expected.Rotation, actual.Rotation); AssertEqual(expected.Rotation, actual.Rotation, nameof(Object.Rotation));
Assert.Equal(expected.GID, actual.GID); AssertEqual(expected.Visible, actual.Visible, nameof(Object.Visible));
Assert.Equal(expected.Visible, actual.Visible); AssertEqual(expected.Template, actual.Template, nameof(Object.Template));
Assert.Equal(expected.Template, actual.Template);
AssertProperties(expected.Properties, actual.Properties); AssertProperties(expected.Properties, actual.Properties);
Assert.True(expected.GetType() == actual.GetType(), $"Expected object type {expected.GetType()} but got {actual.GetType()}");
AssertObject((dynamic)expected, (dynamic)actual); AssertObject((dynamic)expected, (dynamic)actual);
} }
@ -38,29 +39,35 @@ public static partial class DotTiledAssert
private static void AssertObject(PolygonObject expected, PolygonObject actual) private static void AssertObject(PolygonObject expected, PolygonObject actual)
{ {
Assert.Equal(expected.Points, actual.Points); AssertEqual(expected.Points, actual.Points, nameof(PolygonObject.Points));
} }
private static void AssertObject(PolylineObject expected, PolylineObject actual) private static void AssertObject(PolylineObject expected, PolylineObject actual)
{ {
Assert.Equal(expected.Points, actual.Points); AssertEqual(expected.Points, actual.Points, nameof(PolylineObject.Points));
} }
private static void AssertObject(TextObject expected, TextObject actual) private static void AssertObject(TextObject expected, TextObject actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.FontFamily, actual.FontFamily); AssertEqual(expected.FontFamily, actual.FontFamily, nameof(TextObject.FontFamily));
Assert.Equal(expected.PixelSize, actual.PixelSize); AssertEqual(expected.PixelSize, actual.PixelSize, nameof(TextObject.PixelSize));
Assert.Equal(expected.Wrap, actual.Wrap); AssertEqual(expected.Wrap, actual.Wrap, nameof(TextObject.Wrap));
Assert.Equal(expected.Color, actual.Color); AssertEqual(expected.Color, actual.Color, nameof(TextObject.Color));
Assert.Equal(expected.Bold, actual.Bold); AssertEqual(expected.Bold, actual.Bold, nameof(TextObject.Bold));
Assert.Equal(expected.Italic, actual.Italic); AssertEqual(expected.Italic, actual.Italic, nameof(TextObject.Italic));
Assert.Equal(expected.Underline, actual.Underline); AssertEqual(expected.Underline, actual.Underline, nameof(TextObject.Underline));
Assert.Equal(expected.Strikeout, actual.Strikeout); AssertEqual(expected.Strikeout, actual.Strikeout, nameof(TextObject.Strikeout));
Assert.Equal(expected.Kerning, actual.Kerning); AssertEqual(expected.Kerning, actual.Kerning, nameof(TextObject.Kerning));
Assert.Equal(expected.HorizontalAlignment, actual.HorizontalAlignment); AssertEqual(expected.HorizontalAlignment, actual.HorizontalAlignment, nameof(TextObject.HorizontalAlignment));
Assert.Equal(expected.VerticalAlignment, actual.VerticalAlignment); AssertEqual(expected.VerticalAlignment, actual.VerticalAlignment, nameof(TextObject.VerticalAlignment));
Assert.Equal(expected.Text, actual.Text); 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));
} }
} }

View file

@ -11,7 +11,7 @@ public static partial class DotTiledAssert
} }
Assert.NotNull(actual); Assert.NotNull(actual);
Assert.Equal(expected.Count, actual.Count); AssertEqual(expected.Count, actual.Count, "Properties.Count");
foreach (var kvp in expected) foreach (var kvp in expected)
{ {
Assert.Contains(kvp.Key, actual.Keys); Assert.Contains(kvp.Key, actual.Keys);
@ -21,49 +21,49 @@ public static partial class DotTiledAssert
private static void AssertProperty(IProperty expected, IProperty actual) private static void AssertProperty(IProperty expected, IProperty actual)
{ {
Assert.Equal(expected.Type, actual.Type); AssertEqual(expected.Type, actual.Type, "Property.Type");
Assert.Equal(expected.Name, actual.Name); AssertEqual(expected.Name, actual.Name, "Property.Name");
AssertProperties((dynamic)actual, (dynamic)expected); AssertProperties((dynamic)actual, (dynamic)expected);
} }
private static void AssertProperty(StringProperty expected, StringProperty actual) private static void AssertProperty(StringProperty expected, StringProperty actual)
{ {
Assert.Equal(expected.Value, actual.Value); AssertEqual(expected.Value, actual.Value, "StringProperty.Value");
} }
private static void AssertProperty(IntProperty expected, IntProperty actual) private static void AssertProperty(IntProperty expected, IntProperty actual)
{ {
Assert.Equal(expected.Value, actual.Value); AssertEqual(expected.Value, actual.Value, "IntProperty.Value");
} }
private static void AssertProperty(FloatProperty expected, FloatProperty actual) private static void AssertProperty(FloatProperty expected, FloatProperty actual)
{ {
Assert.Equal(expected.Value, actual.Value); AssertEqual(expected.Value, actual.Value, "FloatProperty.Value");
} }
private static void AssertProperty(BoolProperty expected, BoolProperty actual) private static void AssertProperty(BoolProperty expected, BoolProperty actual)
{ {
Assert.Equal(expected.Value, actual.Value); AssertEqual(expected.Value, actual.Value, "BoolProperty.Value");
} }
private static void AssertProperty(ColorProperty expected, ColorProperty actual) private static void AssertProperty(ColorProperty expected, ColorProperty actual)
{ {
Assert.Equal(expected.Value, actual.Value); AssertEqual(expected.Value, actual.Value, "ColorProperty.Value");
} }
private static void AssertProperty(FileProperty expected, FileProperty actual) private static void AssertProperty(FileProperty expected, FileProperty actual)
{ {
Assert.Equal(expected.Value, actual.Value); AssertEqual(expected.Value, actual.Value, "FileProperty.Value");
} }
private static void AssertProperty(ObjectProperty expected, ObjectProperty actual) private static void AssertProperty(ObjectProperty expected, ObjectProperty actual)
{ {
Assert.Equal(expected.Value, actual.Value); AssertEqual(expected.Value, actual.Value, "ObjectProperty.Value");
} }
private static void AssertProperty(ClassProperty expected, ClassProperty actual) private static void AssertProperty(ClassProperty expected, ClassProperty actual)
{ {
Assert.Equal(expected.PropertyType, actual.PropertyType); AssertEqual(expected.PropertyType, actual.PropertyType, "ClassProperty.PropertyType");
AssertProperties(expected.Properties, actual.Properties); AssertProperties(expected.Properties, actual.Properties);
} }
} }

View file

@ -5,21 +5,21 @@ public static partial class DotTiledAssert
internal static void AssertTileset(Tileset expected, Tileset actual) internal static void AssertTileset(Tileset expected, Tileset actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.Version, actual.Version); AssertEqual(expected.Version, actual.Version, nameof(Tileset.Version));
Assert.Equal(expected.TiledVersion, actual.TiledVersion); AssertEqual(expected.TiledVersion, actual.TiledVersion, nameof(Tileset.TiledVersion));
Assert.Equal(expected.FirstGID, actual.FirstGID); AssertEqual(expected.FirstGID, actual.FirstGID, nameof(Tileset.FirstGID));
Assert.Equal(expected.Source, actual.Source); AssertEqual(expected.Source, actual.Source, nameof(Tileset.Source));
Assert.Equal(expected.Name, actual.Name); AssertEqual(expected.Name, actual.Name, nameof(Tileset.Name));
Assert.Equal(expected.Class, actual.Class); AssertEqual(expected.Class, actual.Class, nameof(Tileset.Class));
Assert.Equal(expected.TileWidth, actual.TileWidth); AssertEqual(expected.TileWidth, actual.TileWidth, nameof(Tileset.TileWidth));
Assert.Equal(expected.TileHeight, actual.TileHeight); AssertEqual(expected.TileHeight, actual.TileHeight, nameof(Tileset.TileHeight));
Assert.Equal(expected.Spacing, actual.Spacing); AssertEqual(expected.Spacing, actual.Spacing, nameof(Tileset.Spacing));
Assert.Equal(expected.Margin, actual.Margin); AssertEqual(expected.Margin, actual.Margin, nameof(Tileset.Margin));
Assert.Equal(expected.TileCount, actual.TileCount); AssertEqual(expected.TileCount, actual.TileCount, nameof(Tileset.TileCount));
Assert.Equal(expected.Columns, actual.Columns); AssertEqual(expected.Columns, actual.Columns, nameof(Tileset.Columns));
Assert.Equal(expected.ObjectAlignment, actual.ObjectAlignment); AssertEqual(expected.ObjectAlignment, actual.ObjectAlignment, nameof(Tileset.ObjectAlignment));
Assert.Equal(expected.RenderSize, actual.RenderSize); AssertEqual(expected.RenderSize, actual.RenderSize, nameof(Tileset.RenderSize));
Assert.Equal(expected.FillMode, actual.FillMode); AssertEqual(expected.FillMode, actual.FillMode, nameof(Tileset.FillMode));
// At most one of // At most one of
AssertImage(expected.Image, actual.Image); AssertImage(expected.Image, actual.Image);
@ -30,7 +30,7 @@ public static partial class DotTiledAssert
if (expected.Wangsets is not null) if (expected.Wangsets is not null)
{ {
Assert.NotNull(actual.Wangsets); Assert.NotNull(actual.Wangsets);
Assert.Equal(expected.Wangsets.Count, actual.Wangsets.Count); AssertEqual(expected.Wangsets.Count, actual.Wangsets.Count, "Wangsets.Count");
for (var i = 0; i < expected.Wangsets.Count; i++) for (var i = 0; i < expected.Wangsets.Count; i++)
AssertWangset(expected.Wangsets[i], actual.Wangsets[i]); AssertWangset(expected.Wangsets[i], actual.Wangsets[i]);
} }
@ -38,7 +38,7 @@ public static partial class DotTiledAssert
// Any number of // Any number of
Assert.NotNull(actual.Tiles); Assert.NotNull(actual.Tiles);
Assert.Equal(expected.Tiles.Count, actual.Tiles.Count); AssertEqual(expected.Tiles.Count, actual.Tiles.Count, "Tiles.Count");
for (var i = 0; i < expected.Tiles.Count; i++) for (var i = 0; i < expected.Tiles.Count; i++)
AssertTile(expected.Tiles[i], actual.Tiles[i]); AssertTile(expected.Tiles[i], actual.Tiles[i]);
} }
@ -53,8 +53,8 @@ public static partial class DotTiledAssert
// Attributes // Attributes
Assert.NotNull(actual); Assert.NotNull(actual);
Assert.Equal(expected.X, actual.X); AssertEqual(expected.X, actual.X, nameof(TileOffset.X));
Assert.Equal(expected.Y, actual.Y); AssertEqual(expected.Y, actual.Y, nameof(TileOffset.Y));
} }
private static void AssertGrid(Grid? expected, Grid? actual) private static void AssertGrid(Grid? expected, Grid? actual)
@ -67,24 +67,24 @@ public static partial class DotTiledAssert
// Attributes // Attributes
Assert.NotNull(actual); Assert.NotNull(actual);
Assert.Equal(expected.Orientation, actual.Orientation); AssertEqual(expected.Orientation, actual.Orientation, nameof(Grid.Orientation));
Assert.Equal(expected.Width, actual.Width); AssertEqual(expected.Width, actual.Width, nameof(Grid.Width));
Assert.Equal(expected.Height, actual.Height); AssertEqual(expected.Height, actual.Height, nameof(Grid.Height));
} }
private static void AssertWangset(Wangset expected, Wangset actual) private static void AssertWangset(Wangset expected, Wangset actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.Name, actual.Name); AssertEqual(expected.Name, actual.Name, nameof(Wangset.Name));
Assert.Equal(expected.Class, actual.Class); AssertEqual(expected.Class, actual.Class, nameof(Wangset.Class));
Assert.Equal(expected.Tile, actual.Tile); AssertEqual(expected.Tile, actual.Tile, nameof(Wangset.Tile));
// At most one of // At most one of
AssertProperties(expected.Properties, actual.Properties); AssertProperties(expected.Properties, actual.Properties);
if (expected.WangColors is not null) if (expected.WangColors is not null)
{ {
Assert.NotNull(actual.WangColors); Assert.NotNull(actual.WangColors);
Assert.Equal(expected.WangColors.Count, actual.WangColors.Count); AssertEqual(expected.WangColors.Count, actual.WangColors.Count, "WangColors.Count");
for (var i = 0; i < expected.WangColors.Count; i++) for (var i = 0; i < expected.WangColors.Count; i++)
AssertWangColor(expected.WangColors[i], actual.WangColors[i]); AssertWangColor(expected.WangColors[i], actual.WangColors[i]);
} }
@ -95,11 +95,11 @@ public static partial class DotTiledAssert
private static void AssertWangColor(WangColor expected, WangColor actual) private static void AssertWangColor(WangColor expected, WangColor actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.Name, actual.Name); AssertEqual(expected.Name, actual.Name, nameof(WangColor.Name));
Assert.Equal(expected.Class, actual.Class); AssertEqual(expected.Class, actual.Class, nameof(WangColor.Class));
Assert.Equal(expected.Color, actual.Color); AssertEqual(expected.Color, actual.Color, nameof(WangColor.Color));
Assert.Equal(expected.Tile, actual.Tile); AssertEqual(expected.Tile, actual.Tile, nameof(WangColor.Tile));
Assert.Equal(expected.Probability, actual.Probability); AssertEqual(expected.Probability, actual.Probability, nameof(WangColor.Probability));
AssertProperties(expected.Properties, actual.Properties); AssertProperties(expected.Properties, actual.Properties);
} }
@ -107,8 +107,8 @@ public static partial class DotTiledAssert
private static void AssertWangTile(WangTile expected, WangTile actual) private static void AssertWangTile(WangTile expected, WangTile actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.TileID, actual.TileID); AssertEqual(expected.TileID, actual.TileID, nameof(WangTile.TileID));
Assert.Equal(expected.WangID, actual.WangID); AssertEqual(expected.WangID, actual.WangID, nameof(WangTile.WangID));
} }
private static void AssertTransformations(Transformations? expected, Transformations? actual) private static void AssertTransformations(Transformations? expected, Transformations? actual)
@ -121,22 +121,22 @@ public static partial class DotTiledAssert
// Attributes // Attributes
Assert.NotNull(actual); Assert.NotNull(actual);
Assert.Equal(expected.HFlip, actual.HFlip); AssertEqual(expected.HFlip, actual.HFlip, nameof(Transformations.HFlip));
Assert.Equal(expected.VFlip, actual.VFlip); AssertEqual(expected.VFlip, actual.VFlip, nameof(Transformations.VFlip));
Assert.Equal(expected.Rotate, actual.Rotate); AssertEqual(expected.Rotate, actual.Rotate, nameof(Transformations.Rotate));
Assert.Equal(expected.PreferUntransformed, actual.PreferUntransformed); AssertEqual(expected.PreferUntransformed, actual.PreferUntransformed, nameof(Transformations.PreferUntransformed));
} }
private static void AssertTile(Tile expected, Tile actual) private static void AssertTile(Tile expected, Tile actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.ID, actual.ID); AssertEqual(expected.ID, actual.ID, nameof(Tile.ID));
Assert.Equal(expected.Type, actual.Type); AssertEqual(expected.Type, actual.Type, nameof(Tile.Type));
Assert.Equal(expected.Probability, actual.Probability); AssertEqual(expected.Probability, actual.Probability, nameof(Tile.Probability));
Assert.Equal(expected.X, actual.X); AssertEqual(expected.X, actual.X, nameof(Tile.X));
Assert.Equal(expected.Y, actual.Y); AssertEqual(expected.Y, actual.Y, nameof(Tile.Y));
Assert.Equal(expected.Width, actual.Width); AssertEqual(expected.Width, actual.Width, nameof(Tile.Width));
Assert.Equal(expected.Height, actual.Height); AssertEqual(expected.Height, actual.Height, nameof(Tile.Height));
// Elements // Elements
AssertProperties(actual.Properties, expected.Properties); AssertProperties(actual.Properties, expected.Properties);
@ -145,7 +145,7 @@ public static partial class DotTiledAssert
if (expected.Animation is not null) if (expected.Animation is not null)
{ {
Assert.NotNull(actual.Animation); Assert.NotNull(actual.Animation);
Assert.Equal(expected.Animation.Count, actual.Animation.Count); AssertEqual(expected.Animation.Count, actual.Animation.Count, "Animation.Count");
for (var i = 0; i < expected.Animation.Count; i++) for (var i = 0; i < expected.Animation.Count; i++)
AssertFrame(expected.Animation[i], actual.Animation[i]); AssertFrame(expected.Animation[i], actual.Animation[i]);
} }
@ -154,7 +154,7 @@ public static partial class DotTiledAssert
private static void AssertFrame(Frame expected, Frame actual) private static void AssertFrame(Frame expected, Frame actual)
{ {
// Attributes // Attributes
Assert.Equal(expected.TileID, actual.TileID); AssertEqual(expected.TileID, actual.TileID, nameof(Frame.TileID));
Assert.Equal(expected.Duration, actual.Duration); AssertEqual(expected.Duration, actual.Duration, nameof(Frame.Duration));
} }
} }

View file

@ -6,7 +6,7 @@ public static partial class TestData
{ {
public static XmlReader GetXmlReaderFor(string testDataFile) public static XmlReader GetXmlReaderFor(string testDataFile)
{ {
var fullyQualifiedTestDataFile = $"DotTiled.Tests.{testDataFile}"; var fullyQualifiedTestDataFile = $"DotTiled.Tests.{ConvertPathToAssemblyResourcePath(testDataFile)}";
using var stream = typeof(TestData).Assembly.GetManifestResourceStream(fullyQualifiedTestDataFile) using var stream = typeof(TestData).Assembly.GetManifestResourceStream(fullyQualifiedTestDataFile)
?? throw new ArgumentException($"Test data file '{fullyQualifiedTestDataFile}' not found"); ?? throw new ArgumentException($"Test data file '{fullyQualifiedTestDataFile}' not found");
@ -18,11 +18,62 @@ public static partial class TestData
public static string GetRawStringFor(string testDataFile) public static string GetRawStringFor(string testDataFile)
{ {
var fullyQualifiedTestDataFile = $"DotTiled.Tests.{testDataFile}"; var fullyQualifiedTestDataFile = $"DotTiled.Tests.{ConvertPathToAssemblyResourcePath(testDataFile)}";
using var stream = typeof(TestData).Assembly.GetManifestResourceStream(fullyQualifiedTestDataFile) using var stream = typeof(TestData).Assembly.GetManifestResourceStream(fullyQualifiedTestDataFile)
?? throw new ArgumentException($"Test data file '{fullyQualifiedTestDataFile}' not found"); ?? throw new ArgumentException($"Test data file '{fullyQualifiedTestDataFile}' not found");
using var stringReader = new StreamReader(stream); using var stringReader = new StreamReader(stream);
return stringReader.ReadToEnd(); return stringReader.ReadToEnd();
} }
private static string ConvertPathToAssemblyResourcePath(string path) =>
path.Replace("/", ".").Replace("\\", ".").Replace(" ", "_");
public static IEnumerable<object[]> MapTests =>
[
["Serialization/TestData/Map/default_map/default-map", (string f) => TestData.DefaultMap(), Array.Empty<CustomTypeDefinition>()],
["Serialization/TestData/Map/map_with_common_props/map-with-common-props", (string f) => TestData.MapWithCommonProps(), Array.Empty<CustomTypeDefinition>()],
["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<CustomTypeDefinition>()],
["Serialization/TestData/Map/map_with_external_tileset/map-with-external-tileset", (string f) => TestData.MapWithExternalTileset(f), Array.Empty<CustomTypeDefinition>()],
["Serialization/TestData/Map/map_with_flippingflags/map-with-flippingflags", (string f) => TestData.MapWithFlippingFlags(f), Array.Empty<CustomTypeDefinition>()],
["Serialization/TestData/Map/map_external_tileset_multi/map-external-tileset-multi", (string f) => TestData.MapExternalTilesetMulti(f), Array.Empty<CustomTypeDefinition>()],
["Serialization/TestData/Map/map_external_tileset_wangset/map-external-tileset-wangset", (string f) => TestData.MapExternalTilesetWangset(f), Array.Empty<CustomTypeDefinition>()],
["Serialization/TestData/Map/map_with_many_layers/map-with-many-layers", (string f) => TestData.MapWithManyLayers(f), Array.Empty<CustomTypeDefinition>()],
];
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 = []
}
]
}
];
} }

View file

@ -1,103 +0,0 @@
[
{
"id": 4,
"name": "Enum0String",
"storageType": "string",
"type": "enum",
"values": [
"Enum0_1",
"Enum0_2",
"Enum0_3"
],
"valuesAsFlags": false
},
{
"id": 5,
"name": "Enum1Num",
"storageType": "int",
"type": "enum",
"values": [
"Enum1Num_1",
"Enum1Num_2",
"Enum1Num_3",
"Enum1Num_4"
],
"valuesAsFlags": false
},
{
"id": 6,
"name": "Enum2StringFlags",
"storageType": "string",
"type": "enum",
"values": [
"Enum2StringFlags_1",
"Enum2StringFlags_2",
"Enum2StringFlags_3",
"Enum2StringFlags_4"
],
"valuesAsFlags": true
},
{
"id": 7,
"name": "Enum3NumFlags",
"storageType": "int",
"type": "enum",
"values": [
"Enum3NumFlags_1",
"Enum3NumFlags_2",
"Enum3NumFlags_3",
"Enum3NumFlags_4",
"Enum3NumFlags_5"
],
"valuesAsFlags": true
},
{
"color": "#ffa0a0a4",
"drawFill": true,
"id": 2,
"members": [
{
"name": "Yep",
"propertyType": "TestClass",
"type": "class",
"value": {
}
}
],
"name": "Test",
"type": "class",
"useAs": [
"property",
"map",
"layer",
"object",
"tile",
"tileset",
"wangcolor",
"wangset",
"project"
]
},
{
"color": "#ffa0a0a4",
"drawFill": true,
"id": 1,
"members": [
{
"name": "Amount",
"type": "float",
"value": 0
},
{
"name": "Name",
"type": "string",
"value": ""
}
],
"name": "TestClass",
"type": "class",
"useAs": [
"property"
]
}
]

View file

@ -1,24 +0,0 @@
[
{
"color": "#ffa0a0a4",
"drawFill": true,
"id": 1,
"members": [
{
"name": "Amount",
"type": "float",
"value": 0
},
{
"name": "Name",
"type": "string",
"value": ""
}
],
"name": "TestClass",
"type": "class",
"useAs": [
"property"
]
}
]

View file

@ -2,17 +2,25 @@ namespace DotTiled.Tests;
public partial class TestData public partial class TestData
{ {
public static Map EmptyMapWithEncodingAndCompression(DataEncoding dataEncoding, DataCompression? compression) => new Map public static Map DefaultMap() => new Map
{ {
Version = "1.10", Class = "",
TiledVersion = "1.11.0",
Orientation = MapOrientation.Orthogonal, Orientation = MapOrientation.Orthogonal,
RenderOrder = RenderOrder.RightDown,
Width = 5, Width = 5,
Height = 5, Height = 5,
TileWidth = 32, TileWidth = 32,
TileHeight = 32, TileHeight = 32,
Infinite = false, Infinite = false,
HexSideLength = null,
StaggerAxis = null,
StaggerIndex = null,
ParallaxOriginX = 0,
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2, NextLayerID = 2,
NextObjectID = 1, NextObjectID = 1,
Layers = [ Layers = [
@ -24,14 +32,15 @@ public partial class TestData
Height = 5, Height = 5,
Data = new Data Data = new Data
{ {
Encoding = dataEncoding, Encoding = DataEncoding.Csv,
Compression = compression, Chunks = null,
Compression = null,
GlobalTileIDs = [ 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, 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 = [
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,

View file

@ -0,0 +1,121 @@
using System.Globalization;
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapExternalTilesetMulti(string fileExt) => 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,
Tilesets = [
new Tileset
{
TileOffset = new TileOffset
{
X = 1,
Y = 5
},
Version = "1.10",
TiledVersion = "1.11.0",
FirstGID = 1,
Name = "multi-tileset",
TileWidth = 256,
TileHeight = 96,
TileCount = 2,
Columns = 0,
Source = $"multi-tileset.{(fileExt == "tmx" ? "tsx" : "tsj")}",
Grid = new Grid
{
Orientation = GridOrientation.Orthogonal,
Width = 1,
Height = 1
},
Properties = new Dictionary<string, IProperty>
{
["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!" }
},
Tiles = [
new Tile
{
ID = 0,
Width = 256,
Height = 96,
Image = new Image
{
Format = ImageFormat.Png,
Source = "tileset.png",
Width = 256,
Height = 96
}
},
new Tile
{
ID = 1,
Width = 256,
Height = 96,
Image = new Image
{
Format = ImageFormat.Png,
Source = "tileset.png",
Width = 256,
Height = 96
}
}
]
}
],
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,
1, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 2, 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
]
}
}
]
};
}

View file

@ -3,9 +3,11 @@
"infinite":false, "infinite":false,
"layers":[ "layers":[
{ {
"compression":"", "data":[0, 0, 0, 0, 0,
"data":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", 0, 0, 0, 0, 0,
"encoding":"base64", 1, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 2, 0, 0, 0],
"height":5, "height":5,
"id":1, "id":1,
"name":"Tile Layer 1", "name":"Tile Layer 1",
@ -22,7 +24,11 @@
"renderorder":"right-down", "renderorder":"right-down",
"tiledversion":"1.11.0", "tiledversion":"1.11.0",
"tileheight":32, "tileheight":32,
"tilesets":[], "tilesets":[
{
"firstgid":1,
"source":"multi-tileset.tsj"
}],
"tilewidth":32, "tilewidth":32,
"type":"map", "type":"map",
"version":"1.10", "version":"1.10",

View file

@ -1,8 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1"> <map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" source="multi-tileset.tsx"/>
<layer id="1" name="Tile Layer 1" width="5" height="5"> <layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="base64" compression="gzip"> <data encoding="csv">
H4sIAAAAAAAACmNgoD0AAMrGiJlkAAAA 0,0,0,0,0,
</data> 0,0,0,0,0,
1,0,0,0,0,
0,0,0,0,0,
0,2,0,0,0
</data>
</layer> </layer>
</map> </map>

View file

@ -0,0 +1,71 @@
{ "columns":0,
"grid":
{
"height":1,
"orientation":"orthogonal",
"width":1
},
"margin":0,
"name":"multi-tileset",
"properties":[
{
"name":"tilesetbool",
"type":"bool",
"value":true
},
{
"name":"tilesetcolor",
"type":"color",
"value":"#ffff0000"
},
{
"name":"tilesetfile",
"type":"file",
"value":""
},
{
"name":"tilesetfloat",
"type":"float",
"value":5.2
},
{
"name":"tilesetint",
"type":"int",
"value":9
},
{
"name":"tilesetobject",
"type":"object",
"value":0
},
{
"name":"tilesetstring",
"type":"string",
"value":"hello world!"
}],
"spacing":0,
"tilecount":2,
"tiledversion":"1.11.0",
"tileheight":96,
"tileoffset":
{
"x":1,
"y":5
},
"tiles":[
{
"id":0,
"image":"tileset.png",
"imageheight":96,
"imagewidth":256
},
{
"id":1,
"image":"tileset.png",
"imageheight":96,
"imagewidth":256
}],
"tilewidth":256,
"type":"tileset",
"version":"1.10"
}

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.0" name="multi-tileset" tilewidth="256" tileheight="96" tilecount="2" columns="0">
<tileoffset x="1" y="5"/>
<grid orientation="orthogonal" width="1" height="1"/>
<properties>
<property name="tilesetbool" type="bool" value="true"/>
<property name="tilesetcolor" type="color" value="#ffff0000"/>
<property name="tilesetfile" type="file" value=""/>
<property name="tilesetfloat" type="float" value="5.2"/>
<property name="tilesetint" type="int" value="9"/>
<property name="tilesetobject" type="object" value="0"/>
<property name="tilesetstring" value="hello world!"/>
</properties>
<tile id="0">
<image source="tileset.png" width="256" height="96"/>
</tile>
<tile id="1">
<image source="tileset.png" width="256" height="96"/>
</tile>
</tileset>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,92 @@
using System.Globalization;
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapExternalTilesetWangset(string fileExt) => new Map
{
Class = "",
Orientation = MapOrientation.Orthogonal,
Width = 5,
Height = 5,
TileWidth = 24,
TileHeight = 24,
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,
Tilesets = [
new Tileset
{
Version = "1.10",
TiledVersion = "1.11.0",
FirstGID = 1,
Name = "tileset",
TileWidth = 24,
TileHeight = 24,
TileCount = 48,
Columns = 10,
Source = $"wangset-tileset.{(fileExt == "tmx" ? "tsx" : "tsj")}",
Transformations = new Transformations
{
HFlip = true,
VFlip = true,
Rotate = false,
PreferUntransformed = false
},
Grid = new Grid
{
Orientation = GridOrientation.Orthogonal,
Width = 32,
Height = 32
},
Image = new Image
{
Format = ImageFormat.Png,
Source = "tileset.png",
Width = 256,
Height = 96,
}
}
],
Layers = [
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
Chunks = null,
Compression = null,
GlobalTileIDs = [
2, 2, 12, 11, 0,
1, 12, 1, 11, 0,
2, 1, 0, 1, 0,
12, 11, 12, 2, 0,
0, 0, 0, 0, 0
],
FlippingFlags = [
FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.None,
FlippingFlags.FlippedVertically, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically | FlippingFlags.FlippedHorizontally, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically | FlippingFlags.FlippedHorizontally, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedHorizontally, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
]
}
}
]
};
}

View file

@ -0,0 +1,36 @@
{ "compressionlevel":-1,
"height":5,
"infinite":false,
"layers":[
{
"data":[2147483650, 2, 2147483660, 2147483659, 0,
1073741825, 12, 1, 3221225483, 0,
2, 1, 0, 3221225473, 0,
12, 11, 12, 2147483650, 0,
0, 0, 0, 0, 0],
"height":5,
"id":1,
"name":"Tile Layer 1",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":5,
"x":0,
"y":0
}],
"nextlayerid":2,
"nextobjectid":1,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.11.0",
"tileheight":24,
"tilesets":[
{
"firstgid":1,
"source":"wangset-tileset.tsj"
}],
"tilewidth":24,
"type":"map",
"version":"1.10",
"width":5
}

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="24" tileheight="24" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" source="wangset-tileset.tsx"/>
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
2147483650,2,2147483660,2147483659,0,
1073741825,12,1,3221225483,0,
2,1,0,3221225473,0,
12,11,12,2147483650,0,
0,0,0,0,0
</data>
</layer>
</map>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,69 @@
{ "columns":10,
"grid":
{
"height":32,
"orientation":"orthogonal",
"width":32
},
"image":"tileset.png",
"imageheight":96,
"imagewidth":256,
"margin":0,
"name":"tileset",
"spacing":0,
"tilecount":48,
"tiledversion":"1.11.0",
"tileheight":24,
"tilewidth":24,
"transformations":
{
"hflip":true,
"preferuntransformed":false,
"rotate":false,
"vflip":true
},
"type":"tileset",
"version":"1.10",
"wangsets":[
{
"colors":[
{
"color":"#ff0000",
"name":"Water",
"probability":1,
"tile":0
},
{
"color":"#00ff00",
"name":"Grass",
"probability":1,
"tile":-1
},
{
"color":"#0000ff",
"name":"Stone",
"probability":1,
"tile":29
}],
"name":"test-terrain",
"tile":-1,
"type":"mixed",
"wangtiles":[
{
"tileid":0,
"wangid":[1, 1, 0, 0, 0, 1, 1, 1]
},
{
"tileid":1,
"wangid":[1, 1, 1, 1, 0, 0, 0, 1]
},
{
"tileid":10,
"wangid":[0, 0, 0, 1, 1, 1, 1, 1]
},
{
"tileid":11,
"wangid":[0, 1, 1, 1, 1, 1, 0, 0]
}]
}]
}

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.0" name="tileset" tilewidth="24" tileheight="24" tilecount="48" columns="10">
<grid orientation="orthogonal" width="32" height="32"/>
<transformations hflip="1" vflip="1" rotate="0" preferuntransformed="0"/>
<image source="tileset.png" width="256" height="96"/>
<wangsets>
<wangset name="test-terrain" type="mixed" tile="-1">
<wangcolor name="Water" color="#ff0000" tile="0" probability="1"/>
<wangcolor name="Grass" color="#00ff00" tile="-1" probability="1"/>
<wangcolor name="Stone" color="#0000ff" tile="29" probability="1"/>
<wangtile tileid="0" wangid="1,1,0,0,0,1,1,1"/>
<wangtile tileid="1" wangid="1,1,1,1,0,0,0,1"/>
<wangtile tileid="10" wangid="0,0,0,1,1,1,1,1"/>
<wangtile tileid="11" wangid="0,1,1,1,1,1,0,0"/>
</wangset>
</wangsets>
</tileset>

View file

@ -0,0 +1,68 @@
using System.Globalization;
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapWithCommonProps() => new Map
{
Class = "",
Orientation = MapOrientation.Isometric,
Width = 5,
Height = 5,
TileWidth = 32,
TileHeight = 16,
Infinite = false,
HexSideLength = null,
StaggerAxis = null,
StaggerIndex = null,
ParallaxOriginX = 0,
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00ff00", 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 Dictionary<string, IProperty>
{
["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!" }
}
};
}

View file

@ -1,4 +1,5 @@
{ "compressionlevel":-1, { "backgroundcolor":"#00ff00",
"compressionlevel":-1,
"height":5, "height":5,
"infinite":false, "infinite":false,
"layers":[ "layers":[
@ -20,47 +21,47 @@
}], }],
"nextlayerid":2, "nextlayerid":2,
"nextobjectid":1, "nextobjectid":1,
"orientation":"orthogonal", "orientation":"isometric",
"properties":[ "properties":[
{ {
"name":"MapBool", "name":"boolprop",
"type":"bool", "type":"bool",
"value":true "value":true
}, },
{ {
"name":"MapColor", "name":"colorprop",
"type":"color", "type":"color",
"value":"#ffff0000" "value":"#ff55ffff"
}, },
{ {
"name":"MapFile", "name":"fileprop",
"type":"file", "type":"file",
"value":"file.png" "value":"file.txt"
}, },
{ {
"name":"MapFloat", "name":"floatprop",
"type":"float", "type":"float",
"value":5.2 "value":4.2
}, },
{ {
"name":"MapInt", "name":"intprop",
"type":"int", "type":"int",
"value":42 "value":8
}, },
{ {
"name":"MapObject", "name":"objectprop",
"type":"object", "type":"object",
"value":5 "value":5
}, },
{ {
"name":"MapString", "name":"stringprop",
"type":"string", "type":"string",
"value":"string in map" "value":"This is a string, hello world!"
}], }],
"renderorder":"right-down", "renderorder":"right-down",
"tiledversion":"1.11.0", "tiledversion":"1.11.0",
"tileheight":32, "tileheight":16,
"tilesets":[], "tilesets":[],
"tilewidth":32, "tilewidth":32,
"type":"map", "type":"map",

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="isometric" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="16" infinite="0" backgroundcolor="#00ff00" nextlayerid="2" nextobjectid="1">
<properties>
<property name="boolprop" type="bool" value="true"/>
<property name="colorprop" type="color" value="#ff55ffff"/>
<property name="fileprop" type="file" value="file.txt"/>
<property name="floatprop" type="float" value="4.2"/>
<property name="intprop" type="int" value="8"/>
<property name="objectprop" type="object" value="5"/>
<property name="stringprop" value="This is a string, hello world!"/>
</properties>
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
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
</data>
</layer>
</map>

View file

@ -0,0 +1,122 @@
using System.Globalization;
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapWithCustomTypeProps() => 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 Dictionary<string, IProperty>
{
["customclassprop"] = new ClassProperty
{
Name = "customclassprop",
PropertyType = "CustomClass",
Properties = new Dictionary<string, IProperty>
{
["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" }
}
}
}
};
// This comes from map-with-custom-type-props/propertytypes.json
public static IReadOnlyCollection<CustomTypeDefinition> MapWithCustomTypePropsCustomTypeDefinitions() => [
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 = ""
}
]
}
];
}

View file

@ -0,0 +1,44 @@
{ "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":"customclassprop",
"propertytype":"CustomClass",
"type":"class",
"value":
{
"boolinclass":true,
"floatinclass":13.37,
"stringinclass":"This is a set string"
}
}],
"renderorder":"right-down",
"tiledversion":"1.11.0",
"tileheight":32,
"tilesets":[],
"tilewidth":32,
"type":"map",
"version":"1.10",
"width":5
}

View file

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1"> <map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<properties> <properties>
<property name="MapBool" type="bool" value="true"/> <property name="customclassprop" type="class" propertytype="CustomClass">
<property name="MapColor" type="color" value="#ffff0000"/> <properties>
<property name="MapFile" type="file" value="file.png"/> <property name="boolinclass" type="bool" value="true"/>
<property name="MapFloat" type="float" value="5.2"/> <property name="floatinclass" type="float" value="13.37"/>
<property name="MapInt" type="int" value="42"/> <property name="stringinclass" value="This is a set string"/>
<property name="MapObject" type="object" value="5"/> </properties>
<property name="MapString" value="string in map"/> </property>
</properties> </properties>
<layer id="1" name="Tile Layer 1" width="5" height="5"> <layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv"> <data encoding="csv">

View file

@ -0,0 +1,49 @@
[
{
"color": "#ffa0a0a4",
"drawFill": true,
"id": 8,
"members": [
{
"name": "boolinclass",
"type": "bool",
"value": false
},
{
"name": "colorinclass",
"type": "color",
"value": ""
},
{
"name": "fileinclass",
"type": "file",
"value": ""
},
{
"name": "floatinclass",
"type": "float",
"value": 0
},
{
"name": "intinclass",
"type": "int",
"value": 0
},
{
"name": "objectinclass",
"type": "object",
"value": 0
},
{
"name": "stringinclass",
"type": "string",
"value": ""
}
],
"name": "CustomClass",
"type": "class",
"useAs": [
"property"
]
}
]

View file

@ -1,35 +1,45 @@
using System.Globalization;
namespace DotTiled.Tests; namespace DotTiled.Tests;
public partial class TestData public partial class TestData
{ {
public static Map SimpleMapWithEmbeddedTileset() => new Map public static Map MapWithEmbeddedTileset() => new Map
{ {
Version = "1.10", Class = "",
TiledVersion = "1.11.0",
Orientation = MapOrientation.Orthogonal, Orientation = MapOrientation.Orthogonal,
RenderOrder = RenderOrder.RightDown,
Width = 5, Width = 5,
Height = 5, Height = 5,
TileWidth = 32, TileWidth = 32,
TileHeight = 32, TileHeight = 32,
Infinite = false, 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, NextLayerID = 2,
NextObjectID = 1, NextObjectID = 1,
Tilesets = [ Tilesets = [
new Tileset new Tileset
{ {
FirstGID = 1, FirstGID = 1,
Name = "Tileset 1", Name = "tileset",
TileWidth = 32, TileWidth = 32,
TileHeight = 32, TileHeight = 32,
TileCount = 8, TileCount = 24,
Columns = 4, Columns = 8,
Image = new Image Image = new Image
{ {
Format = ImageFormat.Png, Format = ImageFormat.Png,
Source = "tiles.png", Source = "tileset.png",
Width = 128, Width = 256,
Height = 64 Height = 96,
} }
} }
], ],
@ -43,13 +53,14 @@ public partial class TestData
Data = new Data Data = new Data
{ {
Encoding = DataEncoding.Csv, Encoding = DataEncoding.Csv,
Chunks = null,
Compression = null, Compression = null,
GlobalTileIDs = [ GlobalTileIDs = [
1,1,1,1,1, 1, 1, 0, 0, 7,
1,1,1,1,1, 1, 1, 0, 0, 7,
1,1,1,1,1, 0, 0, 0, 0, 7,
2,2,2,2,2, 9, 10, 0, 0, 7,
2,2,2,2,2 17, 18, 0, 0, 0
], ],
FlippingFlags = [ FlippingFlags = [
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
@ -58,7 +69,7 @@ public partial class TestData
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
] ]
}, }
} }
] ]
}; };

View file

@ -3,11 +3,11 @@
"infinite":false, "infinite":false,
"layers":[ "layers":[
{ {
"data":[1, 1, 1, 1, 1, "data":[1, 1, 0, 0, 7,
1, 1, 1, 1, 1, 1, 1, 0, 0, 7,
1, 1, 1, 1, 1, 0, 0, 0, 0, 7,
2, 2, 2, 2, 2, 9, 10, 0, 0, 7,
2, 2, 2, 2, 2], 17, 18, 0, 0, 0],
"height":5, "height":5,
"id":1, "id":1,
"name":"Tile Layer 1", "name":"Tile Layer 1",
@ -26,15 +26,15 @@
"tileheight":32, "tileheight":32,
"tilesets":[ "tilesets":[
{ {
"columns":4, "columns":8,
"firstgid":1, "firstgid":1,
"image":"tiles.png", "image":"tileset.png",
"imageheight":64, "imageheight":96,
"imagewidth":128, "imagewidth":256,
"margin":0, "margin":0,
"name":"Tileset 1", "name":"tileset",
"spacing":0, "spacing":0,
"tilecount":8, "tilecount":24,
"tileheight":32, "tileheight":32,
"tilewidth":32 "tilewidth":32
}], }],

View file

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1"> <map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" name="Tileset 1" tilewidth="32" tileheight="32" tilecount="8" columns="4"> <tileset firstgid="1" name="tileset" tilewidth="32" tileheight="32" tilecount="24" columns="8">
<image source="tiles.png" width="128" height="64"/> <image source="tileset.png" width="256" height="96"/>
</tileset> </tileset>
<layer id="1" name="Tile Layer 1" width="5" height="5"> <layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv"> <data encoding="csv">
1,1,1,1,1, 1,1,0,0,7,
1,1,1,1,1, 1,1,0,0,7,
1,1,1,1,1, 0,0,0,0,7,
2,2,2,2,2, 9,10,0,0,7,
2,2,2,2,2 17,18,0,0,0
</data> </data>
</layer> </layer>
</map> </map>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -1,20 +1,51 @@
using System.Globalization;
namespace DotTiled.Tests; namespace DotTiled.Tests;
public partial class TestData public partial class TestData
{ {
public static Map EmptyMapWithProperties() => new Map public static Map MapWithExternalTileset(string fileExt) => new Map
{ {
Version = "1.10", Class = "",
TiledVersion = "1.11.0",
Orientation = MapOrientation.Orthogonal, Orientation = MapOrientation.Orthogonal,
RenderOrder = RenderOrder.RightDown,
Width = 5, Width = 5,
Height = 5, Height = 5,
TileWidth = 32, TileWidth = 32,
TileHeight = 32, TileHeight = 32,
Infinite = false, 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, NextLayerID = 2,
NextObjectID = 1, NextObjectID = 1,
Tilesets = [
new Tileset
{
Version = "1.10",
TiledVersion = "1.11.0",
FirstGID = 1,
Name = "tileset",
TileWidth = 32,
TileHeight = 32,
TileCount = 24,
Columns = 8,
Source = $"tileset.{(fileExt == "tmx" ? "tsx" : "tsj")}",
Image = new Image
{
Format = ImageFormat.Png,
Source = "tileset.png",
Width = 256,
Height = 96,
}
}
],
Layers = [ Layers = [
new TileLayer new TileLayer
{ {
@ -25,12 +56,14 @@ public partial class TestData
Data = new Data Data = new Data
{ {
Encoding = DataEncoding.Csv, Encoding = DataEncoding.Csv,
Chunks = null,
Compression = null,
GlobalTileIDs = [ GlobalTileIDs = [
0,0,0,0,0, 1, 1, 0, 0, 7,
0,0,0,0,0, 1, 1, 0, 0, 7,
0,0,0,0,0, 0, 0, 1, 0, 7,
0,0,0,0,0, 0, 0, 0, 1, 7,
0,0,0,0,0 21, 21, 21, 21, 1
], ],
FlippingFlags = [ FlippingFlags = [
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
@ -41,16 +74,6 @@ public partial class TestData
] ]
} }
} }
], ]
Properties = new Dictionary<string, IProperty>
{
["MapBool"] = new BoolProperty { Name = "MapBool", Value = true },
["MapColor"] = new ColorProperty { Name = "MapColor", Value = new Color { R = 255, G = 0, B = 0, A = 255 } },
["MapFile"] = new FileProperty { Name = "MapFile", Value = "file.png" },
["MapFloat"] = new FloatProperty { Name = "MapFloat", Value = 5.2f },
["MapInt"] = new IntProperty { Name = "MapInt", Value = 42 },
["MapObject"] = new ObjectProperty { Name = "MapObject", Value = 5 },
["MapString"] = new StringProperty { Name = "MapString", Value = "string in map" }
}
}; };
} }

View file

@ -3,9 +3,11 @@
"infinite":false, "infinite":false,
"layers":[ "layers":[
{ {
"compression":"zlib", "data":[1, 1, 0, 0, 7,
"data":"eJxjYKA9AAAAZAAB", 1, 1, 0, 0, 7,
"encoding":"base64", 0, 0, 1, 0, 7,
0, 0, 0, 1, 7,
21, 21, 21, 21, 1],
"height":5, "height":5,
"id":1, "id":1,
"name":"Tile Layer 1", "name":"Tile Layer 1",
@ -22,7 +24,11 @@
"renderorder":"right-down", "renderorder":"right-down",
"tiledversion":"1.11.0", "tiledversion":"1.11.0",
"tileheight":32, "tileheight":32,
"tilesets":[], "tilesets":[
{
"firstgid":1,
"source":"tileset.tsj"
}],
"tilewidth":32, "tilewidth":32,
"type":"map", "type":"map",
"version":"1.10", "version":"1.10",

View file

@ -1,8 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1"> <map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" source="tileset.tsx"/>
<layer id="1" name="Tile Layer 1" width="5" height="5"> <layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="base64" compression="zlib"> <data encoding="csv">
eJxjYKA9AAAAZAAB 1,1,0,0,7,
</data> 1,1,0,0,7,
0,0,1,0,7,
0,0,0,1,7,
21,21,21,21,1
</data>
</layer> </layer>
</map> </map>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,14 @@
{ "columns":8,
"image":"tileset.png",
"imageheight":96,
"imagewidth":256,
"margin":0,
"name":"tileset",
"spacing":0,
"tilecount":24,
"tiledversion":"1.11.0",
"tileheight":32,
"tilewidth":32,
"type":"tileset",
"version":"1.10"
}

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.0" name="tileset" tilewidth="32" tileheight="32" tilecount="24" columns="8">
<image source="tileset.png" width="256" height="96"/>
</tileset>

View file

@ -0,0 +1,79 @@
using System.Globalization;
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapWithFlippingFlags(string fileExt) => 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,
Tilesets = [
new Tileset
{
Version = "1.10",
TiledVersion = "1.11.0",
FirstGID = 1,
Name = "tileset",
TileWidth = 32,
TileHeight = 32,
TileCount = 24,
Columns = 8,
Source = $"tileset.{(fileExt == "tmx" ? "tsx" : "tsj")}",
Image = new Image
{
Format = ImageFormat.Png,
Source = "tileset.png",
Width = 256,
Height = 96,
}
}
],
Layers = [
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
Chunks = null,
Compression = null,
GlobalTileIDs = [
1, 1, 0, 0, 7,
1, 1, 0, 0, 7,
0, 0, 1, 0, 7,
0, 0, 0, 1, 7,
21, 21, 21, 21, 1
],
FlippingFlags = [
FlippingFlags.None, FlippingFlags.FlippedDiagonally | FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically,
FlippingFlags.FlippedDiagonally | FlippingFlags.FlippedVertically, FlippingFlags.FlippedVertically | FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically,
FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.None
]
}
}
]
};
}

View file

@ -3,9 +3,11 @@
"infinite":false, "infinite":false,
"layers":[ "layers":[
{ {
"compression":"gzip", "data":[1, 2684354561, 0, 0, 1073741831,
"data":"H4sIAAAAAAAACmNgoD0AAMrGiJlkAAAA", 1610612737, 3221225473, 0, 0, 1073741831,
"encoding":"base64", 0, 0, 1, 0, 1073741831,
0, 0, 0, 1, 1073741831,
2147483669, 2147483669, 2147483669, 2147483669, 1],
"height":5, "height":5,
"id":1, "id":1,
"name":"Tile Layer 1", "name":"Tile Layer 1",
@ -22,7 +24,11 @@
"renderorder":"right-down", "renderorder":"right-down",
"tiledversion":"1.11.0", "tiledversion":"1.11.0",
"tileheight":32, "tileheight":32,
"tilesets":[], "tilesets":[
{
"firstgid":1,
"source":"tileset.tsj"
}],
"tilewidth":32, "tilewidth":32,
"type":"map", "type":"map",
"version":"1.10", "version":"1.10",

View file

@ -1,8 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1"> <map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" source="tileset.tsx"/>
<layer id="1" name="Tile Layer 1" width="5" height="5"> <layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="base64"> <data encoding="csv">
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== 1,2684354561,0,0,1073741831,
</data> 1610612737,3221225473,0,0,1073741831,
0,0,1,0,1073741831,
0,0,0,1,1073741831,
2147483669,2147483669,2147483669,2147483669,1
</data>
</layer> </layer>
</map> </map>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,14 @@
{ "columns":8,
"image":"tileset.png",
"imageheight":96,
"imagewidth":256,
"margin":0,
"name":"tileset",
"spacing":0,
"tilecount":24,
"tiledversion":"1.11.0",
"tileheight":32,
"tilewidth":32,
"type":"tileset",
"version":"1.10"
}

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.0" name="tileset" tilewidth="32" tileheight="32" tilecount="24" columns="8">
<image source="tileset.png" width="256" height="96"/>
</tileset>

View file

@ -1,94 +0,0 @@
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapWithGroup() => new Map
{
Version = "1.10",
TiledVersion = "1.11.0",
Orientation = MapOrientation.Orthogonal,
RenderOrder = RenderOrder.RightDown,
Width = 5,
Height = 5,
TileWidth = 32,
TileHeight = 32,
Infinite = false,
NextLayerID = 5,
NextObjectID = 2,
Layers = [
new TileLayer
{
ID = 4,
Name = "Tile Layer 2",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
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
]
}
},
new Group
{
ID = 3,
Name = "Group 1",
Layers = [
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
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
]
}
},
new ObjectLayer
{
ID = 2,
Name = "Object Layer 1",
Objects = [
new RectangleObject
{
ID = 1,
Name = "Name",
X = 35.5f,
Y = 26,
Width = 64.5f,
Height = 64.5f,
}
]
}
]
}
]
};
}

View file

@ -1,80 +0,0 @@
{ "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":4,
"name":"Tile Layer 2",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":5,
"x":0,
"y":0
},
{
"id":3,
"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
},
{
"draworder":"topdown",
"id":2,
"name":"Object Layer 1",
"objects":[
{
"height":64.5,
"id":1,
"name":"Name",
"rotation":0,
"type":"",
"visible":true,
"width":64.5,
"x":35.5,
"y":26
}],
"opacity":1,
"type":"objectgroup",
"visible":true,
"x":0,
"y":0
}],
"name":"Group 1",
"opacity":1,
"type":"group",
"visible":true,
"x":0,
"y":0
}],
"nextlayerid":5,
"nextobjectid":2,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.11.0",
"tileheight":32,
"tilesets":[],
"tilewidth":32,
"type":"map",
"version":"1.10",
"width":5
}

View file

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="5" nextobjectid="2">
<layer id="4" name="Tile Layer 2" width="5" height="5">
<data encoding="csv">
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
</data>
</layer>
<group id="3" name="Group 1">
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
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
</data>
</layer>
<objectgroup id="2" name="Object Layer 1">
<object id="1" name="Name" x="35.5" y="26" width="64.5" height="64.5"/>
</objectgroup>
</group>
</map>

View file

@ -0,0 +1,219 @@
using System.Numerics;
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapWithManyLayers(string fileExt) => 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 = new Color { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 8,
NextObjectID = 7,
Tilesets = [
new Tileset
{
Version = "1.10",
TiledVersion = "1.11.0",
FirstGID = 1,
Name = "tileset",
TileWidth = 32,
TileHeight = 32,
TileCount = 24,
Columns = 8,
Source = $"tileset.{(fileExt == "tmx" ? "tsx" : "tsj")}",
Image = new Image
{
Format = ImageFormat.Png,
Source = "tileset.png",
Width = 256,
Height = 96,
}
}
],
Layers = [
new Group
{
ID = 2,
Name = "Root",
Layers = [
new ObjectLayer
{
ID = 3,
Name = "Objects",
Objects = [
new RectangleObject
{
ID = 1,
Name = "Object 1",
X = 25.6667f,
Y = 28.6667f,
Width = 31.3333f,
Height = 31.3333f
},
new PointObject
{
ID = 3,
Name = "P1",
X = 117.667f,
Y = 48.6667f
},
new EllipseObject
{
ID = 4,
Name = "Circle1",
X = 77f,
Y = 72.3333f,
Width = 34.6667f,
Height = 34.6667f
},
new PolygonObject
{
ID = 5,
Name = "Poly",
X = 20.6667f,
Y = 114.667f,
Points = [
new Vector2(0, 0),
new Vector2(104,20),
new Vector2(35.6667f, 32.3333f)
],
Template = fileExt == "tmx" ? "poly.tx" : "poly.tj",
Properties = new Dictionary<string, IProperty>
{
["templateprop"] = new StringProperty { Name = "templateprop", Value = "helo there" }
}
},
new TileObject
{
ID = 6,
Name = "TileObj",
GID = 7,
X = -35,
Y = 110.333f,
Width = 64,
Height = 146
}
]
},
new Group
{
ID = 5,
Name = "Sub",
Layers = [
new TileLayer
{
ID = 7,
Name = "Tile 3",
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
]
}
},
new TileLayer
{
ID = 6,
Name = "Tile 2",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
Chunks = null,
Compression = null,
GlobalTileIDs = [
0, 15, 15, 0, 0,
0, 15, 15, 0, 0,
0, 15, 15, 15, 0,
15, 15, 15, 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
]
}
}
]
},
new ImageLayer
{
ID = 4,
Name = "ImageLayer",
Image = new Image
{
Format = ImageFormat.Png,
Source = "tileset.png",
Width = fileExt == "tmx" ? 256u : 0, // Currently, json format does not
Height = fileExt == "tmx" ? 96u : 0 // include image dimensions in image layer https://github.com/mapeditor/tiled/issues/4028
},
RepeatX = true
},
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
Chunks = null,
Compression = null,
GlobalTileIDs = [
1, 1, 1, 1, 1,
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
]
}
}
]
}
]
};
}

View file

@ -0,0 +1,163 @@
{ "compressionlevel":-1,
"height":5,
"infinite":false,
"layers":[
{
"id":2,
"layers":[
{
"draworder":"topdown",
"id":3,
"name":"Objects",
"objects":[
{
"height":31.3333,
"id":1,
"name":"Object 1",
"rotation":0,
"type":"",
"visible":true,
"width":31.3333,
"x":25.6667,
"y":28.6667
},
{
"height":0,
"id":3,
"name":"P1",
"point":true,
"rotation":0,
"type":"",
"visible":true,
"width":0,
"x":117.667,
"y":48.6667
},
{
"ellipse":true,
"height":34.6667,
"id":4,
"name":"Circle1",
"rotation":0,
"type":"",
"visible":true,
"width":34.6667,
"x":77,
"y":72.3333
},
{
"id":5,
"template":"poly.tj",
"x":20.6667,
"y":114.667
},
{
"gid":7,
"height":146,
"id":6,
"name":"TileObj",
"rotation":0,
"type":"",
"visible":true,
"width":64,
"x":-35,
"y":110.333
}],
"opacity":1,
"type":"objectgroup",
"visible":true,
"x":0,
"y":0
},
{
"id":5,
"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":7,
"name":"Tile 3",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":5,
"x":0,
"y":0
},
{
"data":[0, 15, 15, 0, 0,
0, 15, 15, 0, 0,
0, 15, 15, 15, 0,
15, 15, 15, 0, 0,
0, 0, 0, 0, 0],
"height":5,
"id":6,
"name":"Tile 2",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":5,
"x":0,
"y":0
}],
"name":"Sub",
"opacity":1,
"type":"group",
"visible":true,
"x":0,
"y":0
},
{
"id":4,
"image":"tileset.png",
"name":"ImageLayer",
"opacity":1,
"repeatx":true,
"type":"imagelayer",
"visible":true,
"x":0,
"y":0
},
{
"data":[1, 1, 1, 1, 1,
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
}],
"name":"Root",
"opacity":1,
"type":"group",
"visible":true,
"x":0,
"y":0
}],
"nextlayerid":8,
"nextobjectid":7,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.11.0",
"tileheight":32,
"tilesets":[
{
"firstgid":1,
"source":"tileset.tsj"
}],
"tilewidth":32,
"type":"map",
"version":"1.10",
"width":5
}

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="8" nextobjectid="7">
<tileset firstgid="1" source="tileset.tsx"/>
<group id="2" name="Root">
<objectgroup id="3" name="Objects">
<object id="1" name="Object 1" x="25.6667" y="28.6667" width="31.3333" height="31.3333"/>
<object id="3" name="P1" x="117.667" y="48.6667">
<point/>
</object>
<object id="4" name="Circle1" x="77" y="72.3333" width="34.6667" height="34.6667">
<ellipse/>
</object>
<object id="5" template="poly.tx" x="20.6667" y="114.667"/>
<object id="6" name="TileObj" gid="7" x="-35" y="110.333" width="64" height="146"/>
</objectgroup>
<group id="5" name="Sub">
<layer id="7" name="Tile 3" width="5" height="5">
<data encoding="csv">
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
</data>
</layer>
<layer id="6" name="Tile 2" width="5" height="5">
<data encoding="csv">
0,15,15,0,0,
0,15,15,0,0,
0,15,15,15,0,
15,15,15,0,0,
0,0,0,0,0
</data>
</layer>
</group>
<imagelayer id="4" name="ImageLayer" repeatx="1">
<image source="tileset.png" width="256" height="96"/>
</imagelayer>
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
1,1,1,1,1,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
</data>
</layer>
</group>
</map>

View file

@ -0,0 +1,31 @@
{ "object":
{
"height":0,
"id":5,
"name":"Poly",
"polygon":[
{
"x":0,
"y":0
},
{
"x":104,
"y":20
},
{
"x":35.6667,
"y":32.3333
}],
"properties":[
{
"name":"templateprop",
"type":"string",
"value":"helo there"
}],
"rotation":0,
"type":"",
"visible":true,
"width":0
},
"type":"template"
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<template>
<object name="Poly">
<properties>
<property name="templateprop" value="helo there"/>
</properties>
<polygon points="0,0 104,20 35.6667,32.3333"/>
</object>
</template>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,14 @@
{ "columns":8,
"image":"tileset.png",
"imageheight":96,
"imagewidth":256,
"margin":0,
"name":"tileset",
"spacing":0,
"tilecount":24,
"tiledversion":"1.11.0",
"tileheight":32,
"tilewidth":32,
"type":"tileset",
"version":"1.10"
}

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.0" name="tileset" tilewidth="32" tileheight="32" tilecount="24" columns="8">
<image source="tileset.png" width="256" height="96"/>
</tileset>

View file

@ -1,125 +0,0 @@
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapWithObjectTemplate(string templateExtension) => new Map
{
Version = "1.10",
TiledVersion = "1.11.0",
Orientation = MapOrientation.Orthogonal,
RenderOrder = RenderOrder.RightDown,
Width = 5,
Height = 5,
TileWidth = 32,
TileHeight = 32,
Infinite = false,
NextLayerID = 3,
NextObjectID = 3,
Layers = [
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
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
]
}
},
new ObjectLayer
{
ID = 2,
Name = "Object Layer 1",
Objects = [
new RectangleObject
{
ID = 1,
Template = $"map-with-object-template.{templateExtension}",
Name = "Thingy 2",
X = 94.5749f,
Y = 33.6842f,
Width = 37.0156f,
Height = 37.0156f,
Properties = new Dictionary<string, IProperty>
{
["Bool"] = new BoolProperty { Name = "Bool", Value = true },
["TestClassInTemplate"] = new ClassProperty
{
Name = "TestClassInTemplate",
PropertyType = "TestClass",
Properties = new Dictionary<string, IProperty>
{
["Amount"] = new FloatProperty { Name = "Amount", Value = 37 },
["Name"] = new StringProperty { Name = "Name", Value = "I am here" }
}
}
}
},
new RectangleObject
{
ID = 2,
Template = $"map-with-object-template.{templateExtension}",
Name = "Thingy",
X = 29.7976f,
Y = 33.8693f,
Width = 37.0156f,
Height = 37.0156f,
Properties = new Dictionary<string, IProperty>
{
["Bool"] = new BoolProperty { Name = "Bool", Value = true },
["TestClassInTemplate"] = new ClassProperty
{
Name = "TestClassInTemplate",
PropertyType = "TestClass",
Properties = new Dictionary<string, IProperty>
{
["Amount"] = new FloatProperty { Name = "Amount", Value = 4.2f },
["Name"] = new StringProperty { Name = "Name", Value = "Hello there" }
}
}
}
},
new RectangleObject
{
ID = 3,
Template = $"map-with-object-template.{templateExtension}",
Name = "Thingy 3",
X = 5,
Y = 5,
Width = 37.0156f,
Height = 37.0156f,
Properties = new Dictionary<string, IProperty>
{
["Bool"] = new BoolProperty { Name = "Bool", Value = true },
["TestClassInTemplate"] = new ClassProperty
{
Name = "TestClassInTemplate",
PropertyType = "TestClass",
Properties = new Dictionary<string, IProperty>
{
["Amount"] = new FloatProperty { Name = "Amount", Value = 0.0f },
["Name"] = new StringProperty { Name = "Name", Value = "I am here 3" }
}
}
}
}
]
}
]
};
}

View file

@ -1,104 +0,0 @@
{ "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
},
{
"draworder":"topdown",
"id":2,
"name":"Object Layer 1",
"objects":[
{
"height":37.0156,
"id":1,
"template":"map-with-object-template.tj",
"name":"Thingy 2",
"properties":[
{
"name":"Bool",
"type":"bool",
"value":true
},
{
"name":"TestClassInTemplate",
"propertytype":"TestClass",
"type":"class",
"value":
{
"Amount":37,
"Name":"I am here"
}
}],
"rotation":0,
"type":"",
"visible":true,
"width":37.0156,
"x":94.5749,
"y":33.6842
},
{
"id":2,
"template":"map-with-object-template.tj",
"x":29.7976,
"y":33.8693
},
{
"height":37.0156,
"id":3,
"template":"map-with-object-template.tj",
"name":"Thingy 3",
"properties":[
{
"name":"Bool",
"type":"bool",
"value":true
},
{
"name":"TestClassInTemplate",
"propertytype":"TestClass",
"type":"class",
"value":
{
"Name":"I am here 3"
}
}],
"rotation":0,
"type":"",
"visible":true,
"width":37.0156,
"x":5,
"y":5
}],
"opacity":1,
"type":"objectgroup",
"visible":true,
"x":0,
"y":0
}],
"nextlayerid":3,
"nextobjectid":3,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.11.0",
"tileheight":32,
"tilesets":[],
"tilewidth":32,
"type":"map",
"version":"1.10",
"width":5
}

View file

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="3" nextobjectid="3">
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
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
</data>
</layer>
<objectgroup id="2" name="Object Layer 1">
<object id="1" template="map-with-object-template.tx" name="Thingy 2" x="94.5749" y="33.6842">
<properties>
<property name="Bool" type="bool" value="true"/>
<property name="TestClassInTemplate" type="class" propertytype="TestClass">
<properties>
<property name="Amount" type="float" value="37"/>
<property name="Name" value="I am here"/>
</properties>
</property>
</properties>
</object>
<object id="2" template="map-with-object-template.tx" x="29.7976" y="33.8693"/>
<object id="3" template="map-with-object-template.tx" name="Thingy 3" x="5" y="5">
<properties>
<property name="TestClassInTemplate" type="class" propertytype="TestClass">
<properties>
<property name="Name" value="I am here 3"/>
</properties>
</property>
</properties>
</object>
</objectgroup>
</map>

View file

@ -1,28 +0,0 @@
{ "object":
{
"height":37.0156,
"id":2,
"name":"Thingy",
"properties":[
{
"name":"Bool",
"type":"bool",
"value":true
},
{
"name":"TestClassInTemplate",
"propertytype":"TestClass",
"type":"class",
"value":
{
"Amount":4.2,
"Name":"Hello there"
}
}],
"rotation":0,
"type":"",
"visible":true,
"width":37.0156
},
"type":"template"
}

View file

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<template>
<object name="Thingy" width="37.0156" height="37.0156">
<properties>
<property name="Bool" type="bool" value="true"/>
<property name="TestClassInTemplate" type="class" propertytype="TestClass">
<properties>
<property name="Amount" type="float" value="4.2"/>
<property name="Name" value="Hello there"/>
</properties>
</property>
</properties>
</object>
</template>

View file

@ -2,96 +2,27 @@ namespace DotTiled.Tests;
public partial class TmjMapReaderTests public partial class TmjMapReaderTests
{ {
public static IEnumerable<object[]> DeserializeMap_ValidTmjNoExternalTilesets_ReturnsMapWithoutThrowing_Data => public static IEnumerable<object[]> Maps => TestData.MapTests;
[
["Serialization.TestData.Map.empty-map-csv.tmj", TestData.EmptyMapWithEncodingAndCompression(DataEncoding.Csv, null)],
["Serialization.TestData.Map.empty-map-base64.tmj", TestData.EmptyMapWithEncodingAndCompression(DataEncoding.Base64, null)],
["Serialization.TestData.Map.empty-map-base64-gzip.tmj", TestData.EmptyMapWithEncodingAndCompression(DataEncoding.Base64, DataCompression.GZip)],
["Serialization.TestData.Map.empty-map-base64-zlib.tmj", TestData.EmptyMapWithEncodingAndCompression(DataEncoding.Base64, DataCompression.ZLib)],
["Serialization.TestData.Map.simple-tileset-embed.tmj", TestData.SimpleMapWithEmbeddedTileset()],
["Serialization.TestData.Map.empty-map-properties.tmj", TestData.EmptyMapWithProperties()],
];
[Theory] [Theory]
[MemberData(nameof(DeserializeMap_ValidTmjNoExternalTilesets_ReturnsMapWithoutThrowing_Data))] [MemberData(nameof(Maps))]
public void TmxMapReaderReadMap_ValidTmjNoExternalTilesets_ReturnsMapThatEqualsExpected(string testDataFile, Map expectedMap) public void TmxMapReaderReadMap_ValidTmjExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected(
string testDataFile,
Func<string, Map> expectedMap,
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
{ {
// Arrange // Arrange
var json = TestData.GetRawStringFor(testDataFile); testDataFile += ".tmj";
static Template ResolveTemplate(string source) var fileDir = Path.GetDirectoryName(testDataFile);
{
throw new NotSupportedException("External templates are not supported in this test.");
}
static Tileset ResolveTileset(string source)
{
throw new NotSupportedException("External tilesets are not supported in this test.");
}
using var mapReader = new TmjMapReader(json, ResolveTileset, ResolveTemplate, []);
// Act
var map = mapReader.ReadMap();
// Assert
Assert.NotNull(map);
DotTiledAssert.AssertMap(expectedMap, map);
}
public static IEnumerable<object[]> DeserializeMap_ValidTmjExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected_Data =>
[
["Serialization.TestData.Map.map-with-object-template.tmj", TestData.MapWithObjectTemplate("tj")],
["Serialization.TestData.Map.map-with-group.tmj", TestData.MapWithGroup()],
];
[Theory]
[MemberData(nameof(DeserializeMap_ValidTmjExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected_Data))]
public void TmxMapReaderReadMap_ValidTmjExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected(string testDataFile, Map expectedMap)
{
// Arrange
CustomTypeDefinition[] customTypeDefinitions = [
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 = []
}
]
}
];
var json = TestData.GetRawStringFor(testDataFile); var json = TestData.GetRawStringFor(testDataFile);
Template ResolveTemplate(string source) Template ResolveTemplate(string source)
{ {
var templateJson = TestData.GetRawStringFor($"Serialization.TestData.Template.{source}"); var templateJson = TestData.GetRawStringFor($"{fileDir}/{source}");
using var templateReader = new TjTemplateReader(templateJson, ResolveTileset, ResolveTemplate, customTypeDefinitions); using var templateReader = new TjTemplateReader(templateJson, ResolveTileset, ResolveTemplate, customTypeDefinitions);
return templateReader.ReadTemplate(); return templateReader.ReadTemplate();
} }
Tileset ResolveTileset(string source) Tileset ResolveTileset(string source)
{ {
var tilesetJson = TestData.GetRawStringFor($"Serialization.TestData.Tileset.{source}"); var tilesetJson = TestData.GetRawStringFor($"{fileDir}/{source}");
using var tilesetReader = new TsjTilesetReader(tilesetJson, ResolveTemplate, customTypeDefinitions); using var tilesetReader = new TsjTilesetReader(tilesetJson, ResolveTemplate, customTypeDefinitions);
return tilesetReader.ReadTileset(); return tilesetReader.ReadTileset();
} }
@ -102,6 +33,6 @@ public partial class TmjMapReaderTests
// Assert // Assert
Assert.NotNull(map); Assert.NotNull(map);
DotTiledAssert.AssertMap(expectedMap, map); DotTiledAssert.AssertMap(expectedMap("tmj"), map);
} }
} }

View file

@ -4,138 +4,27 @@ namespace DotTiled.Tests;
public partial class TmxMapReaderTests public partial class TmxMapReaderTests
{ {
[Fact] public static IEnumerable<object[]> Maps => TestData.MapTests;
public void TmxMapReaderConstructor_XmlReaderIsNull_ThrowsArgumentNullException()
{
// Arrange
XmlReader xmlReader = null!;
Func<string, Tileset> externalTilesetResolver = (_) => new Tileset();
Func<string, Template> externalTemplateResolver = (_) => new Template { Object = new RectangleObject { } };
// Act
Action act = () =>
{
using var _ = new TmxMapReader(xmlReader, externalTilesetResolver, externalTemplateResolver, []);
};
// Assert
Assert.Throws<ArgumentNullException>(act);
}
[Fact]
public void TmxMapReaderConstructor_ExternalTilesetResolverIsNull_ThrowsArgumentNullException()
{
// Arrange
using var stringReader = new StringReader("<map></map>");
using var xmlReader = XmlReader.Create(stringReader);
Func<string, Tileset> externalTilesetResolver = null!;
Func<string, Template> externalTemplateResolver = (_) => new Template { Object = new RectangleObject { } };
// Act
Action act = () =>
{
using var _ = new TmxMapReader(xmlReader, externalTilesetResolver, externalTemplateResolver, []);
};
// Assert
Assert.Throws<ArgumentNullException>(act);
}
[Fact]
public void TmxMapReaderConstructor_ExternalTemplateResolverIsNull_ThrowsArgumentNullException()
{
// Arrange
using var stringReader = new StringReader("<map></map>");
using var xmlReader = XmlReader.Create(stringReader);
Func<string, Tileset> externalTilesetResolver = (_) => new Tileset();
Func<string, Template> externalTemplateResolver = null!;
// Act
Action act = () =>
{
using var _ = new TmxMapReader(xmlReader, externalTilesetResolver, externalTemplateResolver, []);
};
// Assert
Assert.Throws<ArgumentNullException>(act);
}
[Fact]
public void TmxMapReaderConstructor_NoneNull_DoesNotThrow()
{
// Arrange
using var stringReader = new StringReader("<map></map>");
using var xmlReader = XmlReader.Create(stringReader);
Func<string, Tileset> externalTilesetResolver = (_) => new Tileset();
Func<string, Template> externalTemplateResolver = (_) => new Template { Object = new RectangleObject { } };
// Act
using var tmxMapReader = new TmxMapReader(xmlReader, externalTilesetResolver, externalTemplateResolver, []);
// Assert
Assert.NotNull(tmxMapReader);
}
public static IEnumerable<object[]> DeserializeMap_ValidXmlNoExternalTilesets_ReturnsMapWithoutThrowing_Data =>
[
["Serialization.TestData.Map.empty-map-csv.tmx", TestData.EmptyMapWithEncodingAndCompression(DataEncoding.Csv, null)],
["Serialization.TestData.Map.empty-map-base64.tmx", TestData.EmptyMapWithEncodingAndCompression(DataEncoding.Base64, null)],
["Serialization.TestData.Map.empty-map-base64-gzip.tmx", TestData.EmptyMapWithEncodingAndCompression(DataEncoding.Base64, DataCompression.GZip)],
["Serialization.TestData.Map.empty-map-base64-zlib.tmx", TestData.EmptyMapWithEncodingAndCompression(DataEncoding.Base64, DataCompression.ZLib)],
["Serialization.TestData.Map.simple-tileset-embed.tmx", TestData.SimpleMapWithEmbeddedTileset()],
["Serialization.TestData.Map.empty-map-properties.tmx", TestData.EmptyMapWithProperties()],
];
[Theory] [Theory]
[MemberData(nameof(DeserializeMap_ValidXmlNoExternalTilesets_ReturnsMapWithoutThrowing_Data))] [MemberData(nameof(Maps))]
public void TmxMapReaderReadMap_ValidXmlNoExternalTilesets_ReturnsMapThatEqualsExpected(string testDataFile, Map expectedMap) public void TmxMapReaderReadMap_ValidXmlExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected(
string testDataFile,
Func<string, Map> expectedMap,
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
{ {
// Arrange // Arrange
CustomTypeDefinition[] customTypeDefinitions = [ testDataFile += ".tmx";
new CustomClassDefinition var fileDir = Path.GetDirectoryName(testDataFile);
{
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 = []
}
]
}
];
using var reader = TestData.GetXmlReaderFor(testDataFile); using var reader = TestData.GetXmlReaderFor(testDataFile);
Template ResolveTemplate(string source) Template ResolveTemplate(string source)
{ {
using var xmlTemplateReader = TestData.GetXmlReaderFor($"Serialization.TestData.Template.{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, customTypeDefinitions);
return templateReader.ReadTemplate(); return templateReader.ReadTemplate();
} }
Tileset ResolveTileset(string source) Tileset ResolveTileset(string source)
{ {
using var xmlTilesetReader = TestData.GetXmlReaderFor($"Serialization.TestData.Tileset.{source}"); using var xmlTilesetReader = TestData.GetXmlReaderFor($"{fileDir}/{source}");
using var tilesetReader = new TsxTilesetReader(xmlTilesetReader, ResolveTemplate, customTypeDefinitions); using var tilesetReader = new TsxTilesetReader(xmlTilesetReader, ResolveTemplate, customTypeDefinitions);
return tilesetReader.ReadTileset(); return tilesetReader.ReadTileset();
} }
@ -146,74 +35,6 @@ public partial class TmxMapReaderTests
// Assert // Assert
Assert.NotNull(map); Assert.NotNull(map);
DotTiledAssert.AssertMap(expectedMap, map); DotTiledAssert.AssertMap(expectedMap("tmx"), map);
}
public static IEnumerable<object[]> DeserializeMap_ValidXmlExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected_Data =>
[
["Serialization.TestData.Map.map-with-object-template.tmx", TestData.MapWithObjectTemplate("tx")],
["Serialization.TestData.Map.map-with-group.tmx", TestData.MapWithGroup()],
];
[Theory]
[MemberData(nameof(DeserializeMap_ValidXmlExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected_Data))]
public void TmxMapReaderReadMap_ValidXmlExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected(string testDataFile, Map expectedMap)
{
// Arrange
CustomTypeDefinition[] customTypeDefinitions = [
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 = []
}
]
}
];
using var reader = TestData.GetXmlReaderFor(testDataFile);
Template ResolveTemplate(string source)
{
using var xmlTemplateReader = TestData.GetXmlReaderFor($"Serialization.TestData.Template.{source}");
using var templateReader = new TxTemplateReader(xmlTemplateReader, ResolveTileset, ResolveTemplate, customTypeDefinitions);
return templateReader.ReadTemplate();
}
Tileset ResolveTileset(string source)
{
using var xmlTilesetReader = TestData.GetXmlReaderFor($"Serialization.TestData.Tileset.{source}");
using var tilesetReader = new TsxTilesetReader(xmlTilesetReader, ResolveTemplate, customTypeDefinitions);
return tilesetReader.ReadTileset();
}
using var mapReader = new TmxMapReader(reader, ResolveTileset, ResolveTemplate, customTypeDefinitions);
// Act
var map = mapReader.ReadMap();
// Assert
Assert.NotNull(map);
DotTiledAssert.AssertMap(expectedMap, map);
} }
} }

View file

@ -66,4 +66,6 @@ public class Color : IParsable<Color>, IEquatable<Color>
public override bool Equals(object? obj) => obj is Color other && Equals(other); public override bool Equals(object? obj) => obj is Color other && Equals(other);
public override int GetHashCode() => HashCode.Combine(R, G, B, A); public override int GetHashCode() => HashCode.Combine(R, G, B, A);
public override string ToString() => $"#{A:x2}{R:x2}{G:x2}{B:x2}";
} }

View file

@ -1,173 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace DotTiled;
public enum PropertyType
{
String,
Int,
Float,
Bool,
Color,
File,
Object,
Class
}
public interface IProperty
{
public string Name { get; set; }
public PropertyType Type { get; }
IProperty Clone();
}
public class StringProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.String;
public required string Value { get; set; }
public IProperty Clone() => new StringProperty
{
Name = Name,
Value = Value
};
}
public class IntProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.Int;
public required int Value { get; set; }
public IProperty Clone() => new IntProperty
{
Name = Name,
Value = Value
};
}
public class FloatProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.Float;
public required float Value { get; set; }
public IProperty Clone() => new FloatProperty
{
Name = Name,
Value = Value
};
}
public class BoolProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.Bool;
public required bool Value { get; set; }
public IProperty Clone() => new BoolProperty
{
Name = Name,
Value = Value
};
}
public class ColorProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.Color;
public required Color Value { get; set; }
public IProperty Clone() => new ColorProperty
{
Name = Name,
Value = Value
};
}
public class FileProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.File;
public required string Value { get; set; }
public IProperty Clone() => new FileProperty
{
Name = Name,
Value = Value
};
}
public class ObjectProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.Object;
public required uint Value { get; set; }
public IProperty Clone() => new ObjectProperty
{
Name = Name,
Value = Value
};
}
public class ClassProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => DotTiled.PropertyType.Class;
public required string PropertyType { get; set; }
public required Dictionary<string, IProperty> Properties { get; set; }
public IProperty Clone() => new ClassProperty
{
Name = Name,
PropertyType = PropertyType,
Properties = Properties.ToDictionary(p => p.Key, p => p.Value.Clone())
};
}
public abstract class CustomTypeDefinition
{
public uint ID { get; set; }
public string Name { get; set; } = "";
}
[Flags]
public enum CustomClassUseAs
{
Property,
Map,
Layer,
Object,
Tile,
Tileset,
WangColor,
Wangset,
Project,
All = Property | Map | Layer | Object | Tile | Tileset | WangColor | Wangset | Project
}
public class CustomClassDefinition : CustomTypeDefinition
{
public Color Color { get; set; }
public bool DrawFill { get; set; }
public CustomClassUseAs UseAs { get; set; }
public List<IProperty> Members { get; set; }
}
public enum CustomEnumStorageType
{
Int,
String
}
public class CustomEnumDefinition : CustomTypeDefinition
{
public CustomEnumStorageType StorageType { get; set; }
public List<string> Values { get; set; } = [];
public bool ValueAsFlags { get; set; }
}

View file

@ -5,8 +5,8 @@ public class ImageLayer : BaseLayer
// Attributes // Attributes
public uint X { get; set; } = 0; public uint X { get; set; } = 0;
public uint Y { get; set; } = 0; public uint Y { get; set; } = 0;
public required bool RepeatX { get; set; } public bool RepeatX { get; set; } = false;
public required bool RepeatY { get; set; } public bool RepeatY { get; set; } = false;
// At most one of // At most one of
public Image? Image { get; set; } public Image? Image { get; set; }

View file

@ -13,7 +13,6 @@ public abstract class Object
public float Width { get; set; } = 0f; public float Width { get; set; } = 0f;
public float Height { get; set; } = 0f; public float Height { get; set; } = 0f;
public float Rotation { get; set; } = 0f; public float Rotation { get; set; } = 0f;
public uint? GID { get; set; }
public bool Visible { get; set; } = true; public bool Visible { get; set; } = true;
public string? Template { get; set; } public string? Template { get; set; }

View file

@ -0,0 +1,6 @@
namespace DotTiled;
public class TileObject : Object
{
public uint GID { get; set; }
}

View file

@ -60,5 +60,4 @@ public class Map
// Any number of // Any number of
public List<Tileset> Tilesets { get; set; } = []; public List<Tileset> Tilesets { get; set; } = [];
public List<BaseLayer> Layers { get; set; } = []; public List<BaseLayer> Layers { get; set; } = [];
public List<Group> Groups { get; set; } = [];
} }

View file

@ -0,0 +1,14 @@
namespace DotTiled;
public class BoolProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.Bool;
public required bool Value { get; set; }
public IProperty Clone() => new BoolProperty
{
Name = Name,
Value = Value
};
}

View file

@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.Linq;
namespace DotTiled;
public class ClassProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => DotTiled.PropertyType.Class;
public required string PropertyType { get; set; }
public required Dictionary<string, IProperty> Properties { get; set; }
public IProperty Clone() => new ClassProperty
{
Name = Name,
PropertyType = PropertyType,
Properties = Properties.ToDictionary(p => p.Key, p => p.Value.Clone())
};
}

View file

@ -0,0 +1,14 @@
namespace DotTiled;
public class ColorProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.Color;
public required Color Value { get; set; }
public IProperty Clone() => new ColorProperty
{
Name = Name,
Value = Value
};
}

View file

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
namespace DotTiled;
[Flags]
public enum CustomClassUseAs
{
Property,
Map,
Layer,
Object,
Tile,
Tileset,
WangColor,
Wangset,
Project,
All = Property | Map | Layer | Object | Tile | Tileset | WangColor | Wangset | Project
}
public class CustomClassDefinition : CustomTypeDefinition
{
public Color? Color { get; set; }
public bool DrawFill { get; set; }
public CustomClassUseAs UseAs { get; set; }
public List<IProperty> Members { get; set; } = [];
}

View file

@ -0,0 +1,16 @@
using System.Collections.Generic;
namespace DotTiled;
public enum CustomEnumStorageType
{
Int,
String
}
public class CustomEnumDefinition : CustomTypeDefinition
{
public CustomEnumStorageType StorageType { get; set; }
public List<string> Values { get; set; } = [];
public bool ValueAsFlags { get; set; }
}

View file

@ -0,0 +1,7 @@
namespace DotTiled;
public abstract class CustomTypeDefinition
{
public uint ID { get; set; }
public string Name { get; set; } = "";
}

View file

@ -0,0 +1,14 @@
namespace DotTiled;
public class FileProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.File;
public required string Value { get; set; }
public IProperty Clone() => new FileProperty
{
Name = Name,
Value = Value
};
}

View file

@ -0,0 +1,14 @@
namespace DotTiled;
public class FloatProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.Float;
public required float Value { get; set; }
public IProperty Clone() => new FloatProperty
{
Name = Name,
Value = Value
};
}

View file

@ -0,0 +1,9 @@
namespace DotTiled;
public interface IProperty
{
public string Name { get; set; }
public PropertyType Type { get; }
IProperty Clone();
}

View file

@ -0,0 +1,14 @@
namespace DotTiled;
public class IntProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.Int;
public required int Value { get; set; }
public IProperty Clone() => new IntProperty
{
Name = Name,
Value = Value
};
}

View file

@ -0,0 +1,14 @@
namespace DotTiled;
public class ObjectProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.Object;
public required uint Value { get; set; }
public IProperty Clone() => new ObjectProperty
{
Name = Name,
Value = Value
};
}

View file

@ -0,0 +1,13 @@
namespace DotTiled;
public enum PropertyType
{
String,
Int,
Float,
Bool,
Color,
File,
Object,
Class
}

View file

@ -0,0 +1,14 @@
namespace DotTiled;
public class StringProperty : IProperty
{
public required string Name { get; set; }
public PropertyType Type => PropertyType.String;
public required string Value { get; set; }
public IProperty Clone() => new StringProperty
{
Name = Name,
Value = Value
};
}

View file

@ -8,7 +8,7 @@ public class WangColor
public required string Name { get; set; } public required string Name { get; set; }
public string Class { get; set; } = ""; public string Class { get; set; } = "";
public required Color Color { get; set; } public required Color Color { get; set; }
public required uint Tile { get; set; } public required int Tile { get; set; }
public float Probability { get; set; } = 0f; public float Probability { get; set; } = 0f;
// Elements // Elements

View file

@ -7,7 +7,7 @@ public class Wangset
// Attributes // Attributes
public required string Name { get; set; } public required string Name { get; set; }
public string Class { get; set; } = ""; public string Class { get; set; } = "";
public required uint Tile { get; set; } public required int Tile { get; set; }
// Elements // Elements
// At most one of // At most one of

View file

@ -72,7 +72,7 @@ internal static partial class Helpers
}; };
} }
internal static Dictionary<string, IProperty> MergeProperties(Dictionary<string, IProperty>? baseProperties, Dictionary<string, IProperty> overrideProperties) internal static Dictionary<string, IProperty> MergeProperties(Dictionary<string, IProperty>? baseProperties, Dictionary<string, IProperty>? overrideProperties)
{ {
if (baseProperties is null) if (baseProperties is null)
return overrideProperties ?? new Dictionary<string, IProperty>(); return overrideProperties ?? new Dictionary<string, IProperty>();

View file

@ -25,8 +25,8 @@ internal partial class Tmj
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", e => ReadProperties(e, customTypeDefinitions), null); var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", e => ReadProperties(e, customTypeDefinitions), null);
var image = element.GetRequiredProperty<string>("image"); var image = element.GetRequiredProperty<string>("image");
var repeatX = element.GetRequiredProperty<bool>("repeatx"); var repeatX = element.GetOptionalProperty<bool>("repeatx", false);
var repeatY = element.GetRequiredProperty<bool>("repeaty"); var repeatY = element.GetOptionalProperty<bool>("repeaty", false);
var transparentColor = element.GetOptionalPropertyParseable<Color?>("transparentcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); var transparentColor = element.GetOptionalPropertyParseable<Color?>("transparentcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null);
var x = element.GetOptionalProperty<uint>("x", 0); var x = element.GetOptionalProperty<uint>("x", 0);
var y = element.GetOptionalProperty<uint>("y", 0); var y = element.GetOptionalProperty<uint>("y", 0);

View file

@ -97,7 +97,6 @@ internal partial class Tmj
widthDefault = templObj.Width; widthDefault = templObj.Width;
heightDefault = templObj.Height; heightDefault = templObj.Height;
rotationDefault = templObj.Rotation; rotationDefault = templObj.Rotation;
gidDefault = templObj.GID;
visibleDefault = templObj.Visible; visibleDefault = templObj.Visible;
propertiesDefault = templObj.Properties; propertiesDefault = templObj.Properties;
ellipseDefault = templObj is EllipseObject; ellipseDefault = templObj is EllipseObject;
@ -123,6 +122,25 @@ internal partial class Tmj
var x = element.GetOptionalProperty<float>("x", xDefault); var x = element.GetOptionalProperty<float>("x", xDefault);
var y = element.GetOptionalProperty<float>("y", yDefault); var y = element.GetOptionalProperty<float>("y", yDefault);
if (gid is not null)
{
return new TileObject
{
ID = id,
Name = name,
Type = type,
X = x,
Y = y,
Width = width,
Height = height,
Rotation = rotation,
Visible = visible,
Template = template,
Properties = properties,
GID = gid.Value
};
}
if (ellipse) if (ellipse)
{ {
return new EllipseObject return new EllipseObject
@ -135,7 +153,6 @@ internal partial class Tmj
Width = width, Width = width,
Height = height, Height = height,
Rotation = rotation, Rotation = rotation,
GID = gid,
Visible = visible, Visible = visible,
Template = template, Template = template,
Properties = properties Properties = properties
@ -154,7 +171,6 @@ internal partial class Tmj
Width = width, Width = width,
Height = height, Height = height,
Rotation = rotation, Rotation = rotation,
GID = gid,
Visible = visible, Visible = visible,
Template = template, Template = template,
Properties = properties Properties = properties
@ -173,7 +189,6 @@ internal partial class Tmj
Width = width, Width = width,
Height = height, Height = height,
Rotation = rotation, Rotation = rotation,
GID = gid,
Visible = visible, Visible = visible,
Template = template, Template = template,
Properties = properties, Properties = properties,
@ -193,7 +208,6 @@ internal partial class Tmj
Width = width, Width = width,
Height = height, Height = height,
Rotation = rotation, Rotation = rotation,
GID = gid,
Visible = visible, Visible = visible,
Template = template, Template = template,
Properties = properties, Properties = properties,
@ -211,7 +225,6 @@ internal partial class Tmj
text.Width = width; text.Width = width;
text.Height = height; text.Height = height;
text.Rotation = rotation; text.Rotation = rotation;
text.GID = gid;
text.Visible = visible; text.Visible = visible;
text.Template = template; text.Template = template;
text.Properties = properties; text.Properties = properties;
@ -228,7 +241,6 @@ internal partial class Tmj
Width = width, Width = width,
Height = height, Height = height,
Rotation = rotation, Rotation = rotation,
GID = gid,
Visible = visible, Visible = visible,
Template = template, Template = template,
Properties = properties Properties = properties

View file

@ -64,7 +64,8 @@ internal partial class Tmj
var transparentColor = element.GetOptionalPropertyParseable<Color?>("transparentcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null); var transparentColor = element.GetOptionalPropertyParseable<Color?>("transparentcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null);
var type = element.GetOptionalProperty<string?>("type", null); var type = element.GetOptionalProperty<string?>("type", null);
var version = element.GetOptionalProperty<string?>("version", null); var version = element.GetOptionalProperty<string?>("version", null);
//var wangsets = element.GetOptionalPropertyCustom<List<Wangset>?>("wangsets", ReadWangSets, null); var transformations = element.GetOptionalPropertyCustom<Transformations?>("transformations", ReadTransformations, null);
var wangsets = element.GetOptionalPropertyCustom<List<Wangset>?>("wangsets", el => el.GetValueAsList<Wangset>(e => ReadWangset(e, customTypeDefinitions)), null);
if (source is not null) if (source is not null)
{ {
@ -77,14 +78,14 @@ internal partial class Tmj
return resolvedTileset; return resolvedTileset;
} }
var imageModel = new Image var imageModel = image is not null ? new Image
{ {
Format = Helpers.ParseImageFormatFromSource(image!), Format = Helpers.ParseImageFormatFromSource(image),
Source = image, Source = image,
Height = imageHeight, Height = imageHeight,
Width = imageWidth, Width = imageWidth,
TransparentColor = transparentColor TransparentColor = transparentColor
}; } : null;
return new Tileset return new Tileset
{ {
@ -108,7 +109,24 @@ internal partial class Tmj
Tiles = tiles, Tiles = tiles,
TileWidth = tileWidth, TileWidth = tileWidth,
Version = version, Version = version,
//Wangsets = wangsets Wangsets = wangsets,
Transformations = transformations
};
}
internal static Transformations ReadTransformations(JsonElement element)
{
var hFlip = element.GetOptionalProperty<bool>("hflip", false);
var vFlip = element.GetOptionalProperty<bool>("vflip", false);
var rotate = element.GetOptionalProperty<bool>("rotate", false);
var preferUntransformed = element.GetOptionalProperty<bool>("preferuntransformed", false);
return new Transformations
{
HFlip = hFlip,
VFlip = vFlip,
Rotate = rotate,
PreferUntransformed = preferUntransformed
}; };
} }
@ -159,7 +177,7 @@ internal partial class Tmj
var width = e.GetOptionalProperty<uint>("width", imageWidth ?? 0); var width = e.GetOptionalProperty<uint>("width", imageWidth ?? 0);
var height = e.GetOptionalProperty<uint>("height", imageHeight ?? 0); var height = e.GetOptionalProperty<uint>("height", imageHeight ?? 0);
var objectGroup = e.GetOptionalPropertyCustom<ObjectLayer?>("objectgroup", e => ReadObjectLayer(e, externalTemplateResolver, customTypeDefinitions), null); var objectGroup = e.GetOptionalPropertyCustom<ObjectLayer?>("objectgroup", e => ReadObjectLayer(e, externalTemplateResolver, customTypeDefinitions), null);
var probability = e.GetOptionalProperty<float>("probability", 1.0f); var probability = e.GetOptionalProperty<float>("probability", 0.0f);
var properties = e.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", el => ReadProperties(el, customTypeDefinitions), null); var properties = e.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", el => ReadProperties(el, customTypeDefinitions), null);
// var terrain, replaced by wangsets // var terrain, replaced by wangsets
var type = e.GetOptionalProperty<string>("type", ""); var type = e.GetOptionalProperty<string>("type", "");
@ -208,7 +226,7 @@ internal partial class Tmj
var colors = element.GetOptionalPropertyCustom<List<WangColor>>("colors", e => e.GetValueAsList<WangColor>(el => ReadWangColor(el, customTypeDefinitions)), []); var colors = element.GetOptionalPropertyCustom<List<WangColor>>("colors", e => e.GetValueAsList<WangColor>(el => ReadWangColor(el, customTypeDefinitions)), []);
var name = element.GetRequiredProperty<string>("name"); var name = element.GetRequiredProperty<string>("name");
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", e => ReadProperties(e, customTypeDefinitions), null); var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", e => ReadProperties(e, customTypeDefinitions), null);
var tile = element.GetOptionalProperty<uint>("tile", 0); var tile = element.GetOptionalProperty<int>("tile", 0);
var type = element.GetOptionalProperty<string>("type", ""); var type = element.GetOptionalProperty<string>("type", "");
var wangTiles = element.GetOptionalPropertyCustom<List<WangTile>>("wangtiles", e => e.GetValueAsList<WangTile>(ReadWangTile), []); var wangTiles = element.GetOptionalPropertyCustom<List<WangTile>>("wangtiles", e => e.GetValueAsList<WangTile>(ReadWangTile), []);
@ -232,7 +250,7 @@ internal partial class Tmj
var name = element.GetRequiredProperty<string>("name"); var name = element.GetRequiredProperty<string>("name");
var probability = element.GetOptionalProperty<float>("probability", 1.0f); var probability = element.GetOptionalProperty<float>("probability", 1.0f);
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", e => ReadProperties(e, customTypeDefinitions), null); var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", e => ReadProperties(e, customTypeDefinitions), null);
var tile = element.GetOptionalProperty<uint>("tile", 0); var tile = element.GetOptionalProperty<int>("tile", 0);
return new WangColor return new WangColor
{ {

View file

@ -78,37 +78,21 @@ internal partial class Tmx
{ {
// Attributes // Attributes
var template = reader.GetOptionalAttribute("template"); var template = reader.GetOptionalAttribute("template");
Object? obj = null;
uint? idDefault = null;
string nameDefault = "";
string typeDefault = "";
float xDefault = 0f;
float yDefault = 0f;
float widthDefault = 0f;
float heightDefault = 0f;
float rotationDefault = 0f;
uint? gidDefault = null;
bool visibleDefault = true;
Dictionary<string, IProperty>? propertiesDefault = null;
// Perform template copy first
if (template is not null) if (template is not null)
{ obj = externalTemplateResolver(template).Object;
var resolvedTemplate = externalTemplateResolver(template);
var templObj = resolvedTemplate.Object;
idDefault = templObj.ID; uint? idDefault = obj?.ID ?? null;
nameDefault = templObj.Name; string nameDefault = obj?.Name ?? "";
typeDefault = templObj.Type; string typeDefault = obj?.Type ?? "";
xDefault = templObj.X; float xDefault = obj?.X ?? 0f;
yDefault = templObj.Y; float yDefault = obj?.Y ?? 0f;
widthDefault = templObj.Width; float widthDefault = obj?.Width ?? 0f;
heightDefault = templObj.Height; float heightDefault = obj?.Height ?? 0f;
rotationDefault = templObj.Rotation; float rotationDefault = obj?.Rotation ?? 0f;
gidDefault = templObj.GID; uint? gidDefault = obj is TileObject tileObj ? tileObj.GID : null;
visibleDefault = templObj.Visible; bool visibleDefault = obj?.Visible ?? true;
propertiesDefault = templObj.Properties; Dictionary<string, IProperty>? propertiesDefault = obj?.Properties ?? null;
}
var id = reader.GetOptionalAttributeParseable<uint>("id") ?? idDefault; var id = reader.GetOptionalAttributeParseable<uint>("id") ?? idDefault;
var name = reader.GetOptionalAttribute("name") ?? nameDefault; var name = reader.GetOptionalAttribute("name") ?? nameDefault;
@ -122,40 +106,66 @@ internal partial class Tmx
var visible = reader.GetOptionalAttributeParseable<bool>("visible") ?? visibleDefault; var visible = reader.GetOptionalAttributeParseable<bool>("visible") ?? visibleDefault;
// Elements // Elements
Object? obj = null; Object? foundObject = null;
int propertiesCounter = 0; int propertiesCounter = 0;
Dictionary<string, IProperty>? properties = propertiesDefault; Dictionary<string, IProperty>? 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)), "Properties", ref propertiesCounter), "properties" => () => Helpers.SetAtMostOnceUsingCounter(ref properties, Helpers.MergeProperties(properties, ReadProperties(r, customTypeDefinitions)), "Properties", ref propertiesCounter),
"ellipse" => () => Helpers.SetAtMostOnce(ref obj, ReadEllipseObject(r), "Object marker"), "ellipse" => () => Helpers.SetAtMostOnce(ref foundObject, ReadEllipseObject(r), "Object marker"),
"point" => () => Helpers.SetAtMostOnce(ref obj, ReadPointObject(r), "Object marker"), "point" => () => Helpers.SetAtMostOnce(ref foundObject, ReadPointObject(r), "Object marker"),
"polygon" => () => Helpers.SetAtMostOnce(ref obj, ReadPolygonObject(r), "Object marker"), "polygon" => () => Helpers.SetAtMostOnce(ref foundObject, ReadPolygonObject(r), "Object marker"),
"polyline" => () => Helpers.SetAtMostOnce(ref obj, ReadPolylineObject(r), "Object marker"), "polyline" => () => Helpers.SetAtMostOnce(ref foundObject, ReadPolylineObject(r), "Object marker"),
"text" => () => Helpers.SetAtMostOnce(ref obj, ReadTextObject(r), "Object marker"), "text" => () => Helpers.SetAtMostOnce(ref foundObject, ReadTextObject(r), "Object marker"),
_ => throw new Exception($"Unknown object marker '{elementName}'") _ => throw new Exception($"Unknown object marker '{elementName}'")
}); });
if (obj is null) if (foundObject is null)
{ {
obj = new RectangleObject { ID = id }; if (gid is not null)
reader.Skip(); foundObject = new TileObject { ID = id, GID = gid.Value };
else
foundObject = new RectangleObject { ID = id };
} }
obj.Name = name; foundObject.ID = id;
obj.Type = type; foundObject.Name = name;
obj.X = x; foundObject.Type = type;
obj.Y = y; foundObject.X = x;
obj.Width = width; foundObject.Y = y;
obj.Height = height; foundObject.Width = width;
obj.Rotation = rotation; foundObject.Height = height;
obj.GID = gid; foundObject.Rotation = rotation;
obj.Visible = visible; foundObject.Visible = visible;
obj.Template = template; foundObject.Properties = properties;
obj.Properties = properties; foundObject.Template = template;
return obj; return OverrideObject(obj, foundObject);
}
internal static Object OverrideObject(Object? obj, Object foundObject)
{
if (obj is null)
return foundObject;
if (obj.GetType() != foundObject.GetType())
{
obj.ID = foundObject.ID;
obj.Name = foundObject.Name;
obj.Type = foundObject.Type;
obj.X = foundObject.X;
obj.Y = foundObject.Y;
obj.Width = foundObject.Width;
obj.Height = foundObject.Height;
obj.Rotation = foundObject.Rotation;
obj.Visible = foundObject.Visible;
obj.Properties = Helpers.MergeProperties(obj.Properties, foundObject.Properties);
obj.Template = foundObject.Template;
return obj;
}
return OverrideObject((dynamic)obj, (dynamic)foundObject);
} }
internal static EllipseObject ReadEllipseObject(XmlReader reader) internal static EllipseObject ReadEllipseObject(XmlReader reader)
@ -164,12 +174,16 @@ internal partial class Tmx
return new EllipseObject { }; return new EllipseObject { };
} }
internal static EllipseObject OverrideObject(EllipseObject obj, EllipseObject foundObject) => obj;
internal static PointObject ReadPointObject(XmlReader reader) internal static PointObject ReadPointObject(XmlReader reader)
{ {
reader.Skip(); reader.Skip();
return new PointObject { }; return new PointObject { };
} }
internal static PointObject OverrideObject(PointObject obj, PointObject foundObject) => obj;
internal static PolygonObject ReadPolygonObject(XmlReader reader) internal static PolygonObject ReadPolygonObject(XmlReader reader)
{ {
// Attributes // Attributes
@ -188,6 +202,12 @@ internal partial class Tmx
return new PolygonObject { Points = points }; return new PolygonObject { Points = points };
} }
internal static PolygonObject OverrideObject(PolygonObject obj, PolygonObject foundObject)
{
obj.Points = foundObject.Points;
return obj;
}
internal static PolylineObject ReadPolylineObject(XmlReader reader) internal static PolylineObject ReadPolylineObject(XmlReader reader)
{ {
// Attributes // Attributes
@ -206,6 +226,12 @@ internal partial class Tmx
return new PolylineObject { Points = points }; return new PolylineObject { Points = points };
} }
internal static PolylineObject OverrideObject(PolylineObject obj, PolylineObject foundObject)
{
obj.Points = foundObject.Points;
return obj;
}
internal static TextObject ReadTextObject(XmlReader reader) internal static TextObject ReadTextObject(XmlReader reader)
{ {
// Attributes // Attributes
@ -254,6 +280,29 @@ internal partial class Tmx
}; };
} }
internal static TextObject OverrideObject(TextObject obj, TextObject foundObject)
{
obj.FontFamily = foundObject.FontFamily;
obj.PixelSize = foundObject.PixelSize;
obj.Wrap = foundObject.Wrap;
obj.Color = foundObject.Color;
obj.Bold = foundObject.Bold;
obj.Italic = foundObject.Italic;
obj.Underline = foundObject.Underline;
obj.Strikeout = foundObject.Strikeout;
obj.Kerning = foundObject.Kerning;
obj.HorizontalAlignment = foundObject.HorizontalAlignment;
obj.VerticalAlignment = foundObject.VerticalAlignment;
obj.Text = foundObject.Text;
return obj;
}
internal static TileObject OverrideObject(TileObject obj, TileObject foundObject)
{
obj.GID = foundObject.GID;
return obj;
}
internal static Template ReadTemplate( internal static Template ReadTemplate(
XmlReader reader, XmlReader reader,
Func<string, Tileset> externalTilesetResolver, Func<string, Tileset> externalTilesetResolver,

View file

@ -74,8 +74,8 @@ internal partial class Tmx
var offsetY = reader.GetOptionalAttributeParseable<float>("offsety") ?? 0.0f; var offsetY = reader.GetOptionalAttributeParseable<float>("offsety") ?? 0.0f;
var parallaxX = reader.GetOptionalAttributeParseable<float>("parallaxx") ?? 1.0f; var parallaxX = reader.GetOptionalAttributeParseable<float>("parallaxx") ?? 1.0f;
var parallaxY = reader.GetOptionalAttributeParseable<float>("parallaxy") ?? 1.0f; var parallaxY = reader.GetOptionalAttributeParseable<float>("parallaxy") ?? 1.0f;
var repeatX = reader.GetRequiredAttributeParseable<bool>("repeatx"); var repeatX = (reader.GetOptionalAttributeParseable<uint>("repeatx") ?? 0) == 1;
var repeatY = reader.GetRequiredAttributeParseable<bool>("repeaty"); var repeatY = (reader.GetOptionalAttributeParseable<uint>("repeaty") ?? 0) == 1;
Dictionary<string, IProperty>? properties = null; Dictionary<string, IProperty>? properties = null;
Image? image = null; Image? image = null;

View file

@ -83,7 +83,7 @@ internal partial class Tmx
var resolvedTileset = externalTilesetResolver(source); var resolvedTileset = externalTilesetResolver(source);
resolvedTileset.FirstGID = firstGID; resolvedTileset.FirstGID = firstGID;
resolvedTileset.Source = null; resolvedTileset.Source = source;
return resolvedTileset; return resolvedTileset;
} }
@ -193,10 +193,10 @@ internal partial class Tmx
internal static Transformations ReadTransformations(XmlReader reader) internal static Transformations ReadTransformations(XmlReader reader)
{ {
// Attributes // Attributes
var hFlip = reader.GetOptionalAttributeParseable<bool>("hflip") ?? false; var hFlip = (reader.GetOptionalAttributeParseable<uint>("hflip") ?? 0) == 1;
var vFlip = reader.GetOptionalAttributeParseable<bool>("vflip") ?? false; var vFlip = (reader.GetOptionalAttributeParseable<uint>("vflip") ?? 0) == 1;
var rotate = reader.GetOptionalAttributeParseable<bool>("rotate") ?? false; var rotate = (reader.GetOptionalAttributeParseable<uint>("rotate") ?? 0) == 1;
var preferUntransformed = reader.GetOptionalAttributeParseable<bool>("preferuntransformed") ?? false; var preferUntransformed = (reader.GetOptionalAttributeParseable<uint>("preferuntransformed") ?? 0) == 1;
reader.ReadStartElement("transformations"); reader.ReadStartElement("transformations");
return new Transformations { HFlip = hFlip, VFlip = vFlip, Rotate = rotate, PreferUntransformed = preferUntransformed }; return new Transformations { HFlip = hFlip, VFlip = vFlip, Rotate = rotate, PreferUntransformed = preferUntransformed };
@ -266,7 +266,7 @@ internal partial class Tmx
// Attributes // Attributes
var name = reader.GetRequiredAttribute("name"); var name = reader.GetRequiredAttribute("name");
var @class = reader.GetOptionalAttribute("class") ?? ""; var @class = reader.GetOptionalAttribute("class") ?? "";
var tile = reader.GetRequiredAttributeParseable<uint>("tile"); var tile = reader.GetRequiredAttributeParseable<int>("tile");
// Elements // Elements
Dictionary<string, IProperty>? properties = null; Dictionary<string, IProperty>? properties = null;
@ -303,7 +303,7 @@ internal partial class Tmx
var name = reader.GetRequiredAttribute("name"); var name = reader.GetRequiredAttribute("name");
var @class = reader.GetOptionalAttribute("class") ?? ""; var @class = reader.GetOptionalAttribute("class") ?? "";
var color = reader.GetRequiredAttributeParseable<Color>("color"); var color = reader.GetRequiredAttributeParseable<Color>("color");
var tile = reader.GetRequiredAttributeParseable<uint>("tile"); var tile = reader.GetRequiredAttributeParseable<int>("tile");
var probability = reader.GetOptionalAttributeParseable<float>("probability") ?? 0f; var probability = reader.GetOptionalAttributeParseable<float>("probability") ?? 0f;
// Elements // Elements
@ -339,6 +339,8 @@ internal partial class Tmx
return indices; return indices;
}); });
reader.ReadStartElement("wangtile");
return new WangTile return new WangTile
{ {
TileID = tileID, TileID = tileID,