mirror of
https://github.com/dcronqvist/DotTiled.git
synced 2025-02-05 08:52:50 +02:00
Big properties work
This commit is contained in:
parent
1168917c23
commit
5e93716d2c
15 changed files with 820 additions and 55 deletions
|
@ -17,7 +17,7 @@ public static partial class DotTiledAssert
|
|||
Assert.Equal(expected.Visible, actual.Visible);
|
||||
Assert.Equal(expected.Template, actual.Template);
|
||||
|
||||
AssertProperties(actual.Properties, expected.Properties);
|
||||
AssertProperties(expected.Properties, actual.Properties);
|
||||
AssertObject((dynamic)expected, (dynamic)actual);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,51 +19,51 @@ public static partial class DotTiledAssert
|
|||
}
|
||||
}
|
||||
|
||||
private static void AssertProperty(IProperty actual, IProperty expected)
|
||||
private static void AssertProperty(IProperty expected, IProperty actual)
|
||||
{
|
||||
Assert.Equal(expected.Type, actual.Type);
|
||||
Assert.Equal(expected.Name, actual.Name);
|
||||
AssertProperties((dynamic)actual, (dynamic)expected);
|
||||
}
|
||||
|
||||
private static void AssertProperty(StringProperty actual, StringProperty expected)
|
||||
private static void AssertProperty(StringProperty expected, StringProperty actual)
|
||||
{
|
||||
Assert.Equal(expected.Value, actual.Value);
|
||||
}
|
||||
|
||||
private static void AssertProperty(IntProperty actual, IntProperty expected)
|
||||
private static void AssertProperty(IntProperty expected, IntProperty actual)
|
||||
{
|
||||
Assert.Equal(expected.Value, actual.Value);
|
||||
}
|
||||
|
||||
private static void AssertProperty(FloatProperty actual, FloatProperty expected)
|
||||
private static void AssertProperty(FloatProperty expected, FloatProperty actual)
|
||||
{
|
||||
Assert.Equal(expected.Value, actual.Value);
|
||||
}
|
||||
|
||||
private static void AssertProperty(BoolProperty actual, BoolProperty expected)
|
||||
private static void AssertProperty(BoolProperty expected, BoolProperty actual)
|
||||
{
|
||||
Assert.Equal(expected.Value, actual.Value);
|
||||
}
|
||||
|
||||
private static void AssertProperty(ColorProperty actual, ColorProperty expected)
|
||||
private static void AssertProperty(ColorProperty expected, ColorProperty actual)
|
||||
{
|
||||
Assert.Equal(expected.Value, actual.Value);
|
||||
}
|
||||
|
||||
private static void AssertProperty(FileProperty actual, FileProperty expected)
|
||||
private static void AssertProperty(FileProperty expected, FileProperty actual)
|
||||
{
|
||||
Assert.Equal(expected.Value, actual.Value);
|
||||
}
|
||||
|
||||
private static void AssertProperty(ObjectProperty actual, ObjectProperty expected)
|
||||
private static void AssertProperty(ObjectProperty expected, ObjectProperty actual)
|
||||
{
|
||||
Assert.Equal(expected.Value, actual.Value);
|
||||
}
|
||||
|
||||
private static void AssertProperty(ClassProperty actual, ClassProperty expected)
|
||||
private static void AssertProperty(ClassProperty expected, ClassProperty actual)
|
||||
{
|
||||
Assert.Equal(expected.PropertyType, actual.PropertyType);
|
||||
AssertProperties(actual.Properties, expected.Properties);
|
||||
AssertProperties(expected.Properties, actual.Properties);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ namespace DotTiled.Tests;
|
|||
|
||||
public partial class TestData
|
||||
{
|
||||
public static Map MapWithObjectTemplate() => new Map
|
||||
public static Map MapWithObjectTemplate(string templateExtension) => new Map
|
||||
{
|
||||
Version = "1.10",
|
||||
TiledVersion = "1.11.0",
|
||||
|
@ -49,7 +49,7 @@ public partial class TestData
|
|||
new RectangleObject
|
||||
{
|
||||
ID = 1,
|
||||
Template = "map-with-object-template.tx",
|
||||
Template = $"map-with-object-template.{templateExtension}",
|
||||
Name = "Thingy 2",
|
||||
X = 94.5749f,
|
||||
Y = 33.6842f,
|
||||
|
@ -73,7 +73,7 @@ public partial class TestData
|
|||
new RectangleObject
|
||||
{
|
||||
ID = 2,
|
||||
Template = "map-with-object-template.tx",
|
||||
Template = $"map-with-object-template.{templateExtension}",
|
||||
Name = "Thingy",
|
||||
X = 29.7976f,
|
||||
Y = 33.8693f,
|
||||
|
@ -97,7 +97,7 @@ public partial class TestData
|
|||
new RectangleObject
|
||||
{
|
||||
ID = 3,
|
||||
Template = "map-with-object-template.tx",
|
||||
Template = $"map-with-object-template.{templateExtension}",
|
||||
Name = "Thingy 3",
|
||||
X = 5,
|
||||
Y = 5,
|
||||
|
@ -112,7 +112,7 @@ public partial class TestData
|
|||
PropertyType = "TestClass",
|
||||
Properties = new Dictionary<string, IProperty>
|
||||
{
|
||||
["Amount"] = new FloatProperty { Name = "Amount", Value = 4.2f },
|
||||
["Amount"] = new FloatProperty { Name = "Amount", Value = 0.0f },
|
||||
["Name"] = new StringProperty { Name = "Name", Value = "I am here 3" }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
[
|
||||
{
|
||||
"color": "#ffa0a0a4",
|
||||
"drawFill": true,
|
||||
"id": 1,
|
||||
"members": [
|
||||
{
|
||||
"name": "Amount",
|
||||
"type": "float",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"name": "Name",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"name": "TestClass",
|
||||
"type": "class",
|
||||
"useAs": [
|
||||
"property"
|
||||
]
|
||||
}
|
||||
]
|
103
DotTiled.Tests/Serialization/TestData/propertytypes-2.json
Normal file
103
DotTiled.Tests/Serialization/TestData/propertytypes-2.json
Normal file
|
@ -0,0 +1,103 @@
|
|||
[
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
|
@ -20,17 +20,13 @@ public partial class TmjMapReaderTests
|
|||
var json = TestData.GetRawStringFor(testDataFile);
|
||||
static Template ResolveTemplate(string source)
|
||||
{
|
||||
var templateJson = TestData.GetRawStringFor($"Serialization.TestData.Template.{source}");
|
||||
//var templateReader = new TmjTemplateReader(templateJson, ResolveTemplate);
|
||||
return null;
|
||||
throw new NotSupportedException("External templates are not supported in this test.");
|
||||
}
|
||||
static Tileset ResolveTileset(string source)
|
||||
{
|
||||
var tilesetJson = TestData.GetXmlReaderFor($"Serialization.TestData.Tileset.{source}");
|
||||
//var tilesetReader = new TmjTilesetReader(tilesetJson, ResolveTileset, ResolveTemplate);
|
||||
return null;
|
||||
throw new NotSupportedException("External tilesets are not supported in this test.");
|
||||
}
|
||||
using var mapReader = new TmjMapReader(json, ResolveTileset, ResolveTemplate);
|
||||
using var mapReader = new TmjMapReader(json, ResolveTileset, ResolveTemplate, []);
|
||||
|
||||
// Act
|
||||
var map = mapReader.ReadMap();
|
||||
|
@ -42,7 +38,7 @@ public partial class TmjMapReaderTests
|
|||
|
||||
public static IEnumerable<object[]> DeserializeMap_ValidTmjExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected_Data =>
|
||||
[
|
||||
["Serialization.TestData.Map.map-with-object-template.tmj", TestData.MapWithObjectTemplate()],
|
||||
["Serialization.TestData.Map.map-with-object-template.tmj", TestData.MapWithObjectTemplate("tj")],
|
||||
["Serialization.TestData.Map.map-with-group.tmj", TestData.MapWithGroup()],
|
||||
];
|
||||
|
||||
|
@ -51,20 +47,55 @@ public partial class TmjMapReaderTests
|
|||
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);
|
||||
static Template ResolveTemplate(string source)
|
||||
Template ResolveTemplate(string source)
|
||||
{
|
||||
var templateJson = TestData.GetRawStringFor($"Serialization.TestData.Template.{source}");
|
||||
//var templateReader = new TmjTemplateReader(templateJson, ResolveTemplate);
|
||||
return null;
|
||||
using var templateReader = new TjTemplateReader(templateJson, ResolveTileset, ResolveTemplate, customTypeDefinitions);
|
||||
return templateReader.ReadTemplate();
|
||||
}
|
||||
static Tileset ResolveTileset(string source)
|
||||
Tileset ResolveTileset(string source)
|
||||
{
|
||||
var tilesetJson = TestData.GetXmlReaderFor($"Serialization.TestData.Tileset.{source}");
|
||||
//var tilesetReader = new TmjTilesetReader(tilesetJson, ResolveTileset, ResolveTemplate);
|
||||
return null;
|
||||
var tilesetJson = TestData.GetRawStringFor($"Serialization.TestData.Tileset.{source}");
|
||||
using var tilesetReader = new TsjTilesetReader(tilesetJson, ResolveTemplate, customTypeDefinitions);
|
||||
return tilesetReader.ReadTileset();
|
||||
}
|
||||
using var mapReader = new TmjMapReader(json, ResolveTileset, ResolveTemplate);
|
||||
using var mapReader = new TmjMapReader(json, ResolveTileset, ResolveTemplate, customTypeDefinitions);
|
||||
|
||||
// Act
|
||||
var map = mapReader.ReadMap();
|
||||
|
|
|
@ -116,7 +116,7 @@ public partial class TmxMapReaderTests
|
|||
|
||||
public static IEnumerable<object[]> DeserializeMap_ValidXmlExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected_Data =>
|
||||
[
|
||||
["Serialization.TestData.Map.map-with-object-template.tmx", TestData.MapWithObjectTemplate()],
|
||||
["Serialization.TestData.Map.map-with-object-template.tmx", TestData.MapWithObjectTemplate("tx")],
|
||||
["Serialization.TestData.Map.map-with-group.tmx", TestData.MapWithGroup()],
|
||||
];
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace DotTiled;
|
||||
|
||||
|
@ -18,6 +20,8 @@ public interface IProperty
|
|||
{
|
||||
public string Name { get; set; }
|
||||
public PropertyType Type { get; }
|
||||
|
||||
IProperty Clone();
|
||||
}
|
||||
|
||||
public class StringProperty : IProperty
|
||||
|
@ -25,6 +29,12 @@ 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
|
||||
|
@ -32,6 +42,12 @@ 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
|
||||
|
@ -39,6 +55,12 @@ 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
|
||||
|
@ -46,6 +68,12 @@ 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
|
||||
|
@ -53,6 +81,12 @@ 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
|
||||
|
@ -60,6 +94,12 @@ 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
|
||||
|
@ -67,6 +107,12 @@ 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
|
||||
|
@ -75,4 +121,53 @@ public class ClassProperty : IProperty
|
|||
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; }
|
||||
}
|
||||
|
|
64
DotTiled/Serialization/Tmj/TjTemplateReader.cs
Normal file
64
DotTiled/Serialization/Tmj/TjTemplateReader.cs
Normal file
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotTiled;
|
||||
|
||||
public class TjTemplateReader : ITemplateReader
|
||||
{
|
||||
// External resolvers
|
||||
private readonly Func<string, Tileset> _externalTilesetResolver;
|
||||
private readonly Func<string, Template> _externalTemplateResolver;
|
||||
|
||||
private readonly string _jsonString;
|
||||
private bool disposedValue;
|
||||
|
||||
private readonly IReadOnlyCollection<CustomTypeDefinition> _customTypeDefinitions;
|
||||
|
||||
public TjTemplateReader(
|
||||
string jsonString,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
_jsonString = jsonString ?? throw new ArgumentNullException(nameof(jsonString));
|
||||
_externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver));
|
||||
_externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver));
|
||||
_customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions));
|
||||
}
|
||||
|
||||
public Template ReadTemplate()
|
||||
{
|
||||
var jsonDoc = System.Text.Json.JsonDocument.Parse(_jsonString);
|
||||
var rootElement = jsonDoc.RootElement;
|
||||
return Tmj.ReadTemplate(rootElement, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: dispose managed state (managed objects)
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||
// TODO: set large fields to null
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||
// ~TjTemplateReader()
|
||||
// {
|
||||
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
// Dispose(disposing: false);
|
||||
// }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
|
@ -4,27 +4,33 @@ using System.Globalization;
|
|||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DotTiled;
|
||||
|
||||
internal partial class Tmj
|
||||
{
|
||||
internal static BaseLayer ReadLayer(JsonElement element)
|
||||
internal static BaseLayer ReadLayer(
|
||||
JsonElement element,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
var type = element.GetRequiredProperty<string>("type");
|
||||
|
||||
return type switch
|
||||
{
|
||||
"tilelayer" => ReadTileLayer(element),
|
||||
// "objectgroup" => ReadObjectGroup(element),
|
||||
"tilelayer" => ReadTileLayer(element, customTypeDefinitions),
|
||||
"objectgroup" => ReadObjectLayer(element, externalTemplateResolver, customTypeDefinitions),
|
||||
// "imagelayer" => ReadImageLayer(element),
|
||||
// "group" => ReadGroup(element),
|
||||
"group" => ReadGroup(element, externalTemplateResolver, customTypeDefinitions),
|
||||
_ => throw new JsonException($"Unsupported layer type '{type}'.")
|
||||
};
|
||||
}
|
||||
|
||||
internal static TileLayer ReadTileLayer(JsonElement element)
|
||||
internal static TileLayer ReadTileLayer(
|
||||
JsonElement element,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
var compression = element.GetOptionalPropertyParseable<DataCompression?>("compression", s => s switch
|
||||
{
|
||||
|
@ -50,7 +56,7 @@ internal partial class Tmj
|
|||
var opacity = element.GetOptionalProperty<float>("opacity", 1.0f);
|
||||
var parallaxx = element.GetOptionalProperty<float>("parallaxx", 1.0f);
|
||||
var parallaxy = element.GetOptionalProperty<float>("parallaxy", 1.0f);
|
||||
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", e => ReadProperties(e), null);
|
||||
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", e => ReadProperties(e, customTypeDefinitions), null);
|
||||
var repeatX = element.GetOptionalProperty<bool>("repeatx", false);
|
||||
var repeatY = element.GetOptionalProperty<bool>("repeaty", false);
|
||||
var startX = element.GetOptionalProperty<int>("startx", 0);
|
||||
|
@ -85,4 +91,276 @@ internal partial class Tmj
|
|||
Data = data ?? chunks
|
||||
};
|
||||
}
|
||||
|
||||
internal static Group ReadGroup(
|
||||
JsonElement element,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
var id = element.GetRequiredProperty<uint>("id");
|
||||
var name = element.GetRequiredProperty<string>("name");
|
||||
var @class = element.GetOptionalProperty<string>("class", "");
|
||||
var opacity = element.GetOptionalProperty<float>("opacity", 1.0f);
|
||||
var visible = element.GetOptionalProperty<bool>("visible", true);
|
||||
var tintColor = element.GetOptionalPropertyParseable<Color?>("tintcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null);
|
||||
var offsetX = element.GetOptionalProperty<float>("offsetx", 0.0f);
|
||||
var offsetY = element.GetOptionalProperty<float>("offsety", 0.0f);
|
||||
var parallaxX = element.GetOptionalProperty<float>("parallaxx", 1.0f);
|
||||
var parallaxY = element.GetOptionalProperty<float>("parallaxy", 1.0f);
|
||||
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", e => ReadProperties(e, customTypeDefinitions), null);
|
||||
var layers = element.GetOptionalPropertyCustom<List<BaseLayer>>("layers", e => e.GetValueAsList<BaseLayer>(el => ReadLayer(el, externalTemplateResolver, customTypeDefinitions)), []);
|
||||
|
||||
return new Group
|
||||
{
|
||||
ID = id,
|
||||
Name = name,
|
||||
Class = @class,
|
||||
Opacity = opacity,
|
||||
Visible = visible,
|
||||
TintColor = tintColor,
|
||||
OffsetX = offsetX,
|
||||
OffsetY = offsetY,
|
||||
ParallaxX = parallaxX,
|
||||
ParallaxY = parallaxY,
|
||||
Properties = properties,
|
||||
Layers = layers
|
||||
};
|
||||
}
|
||||
|
||||
internal static ObjectLayer ReadObjectLayer(
|
||||
JsonElement element,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
var id = element.GetRequiredProperty<uint>("id");
|
||||
var name = element.GetRequiredProperty<string>("name");
|
||||
var @class = element.GetOptionalProperty<string>("class", "");
|
||||
var opacity = element.GetOptionalProperty<float>("opacity", 1.0f);
|
||||
var visible = element.GetOptionalProperty<bool>("visible", true);
|
||||
var tintColor = element.GetOptionalPropertyParseable<Color?>("tintcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null);
|
||||
var offsetX = element.GetOptionalProperty<float>("offsetx", 0.0f);
|
||||
var offsetY = element.GetOptionalProperty<float>("offsety", 0.0f);
|
||||
var parallaxX = element.GetOptionalProperty<float>("parallaxx", 1.0f);
|
||||
var parallaxY = element.GetOptionalProperty<float>("parallaxy", 1.0f);
|
||||
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", e => ReadProperties(e, customTypeDefinitions), null);
|
||||
|
||||
var x = element.GetOptionalProperty<uint>("x", 0);
|
||||
var y = element.GetOptionalProperty<uint>("y", 0);
|
||||
var width = element.GetOptionalProperty<uint?>("width", null);
|
||||
var height = element.GetOptionalProperty<uint?>("height", null);
|
||||
var color = element.GetOptionalPropertyParseable<Color?>("color", s => Color.Parse(s, CultureInfo.InvariantCulture), null);
|
||||
var drawOrder = element.GetOptionalPropertyParseable<DrawOrder>("draworder", s => s switch
|
||||
{
|
||||
"topdown" => DrawOrder.TopDown,
|
||||
"index" => DrawOrder.Index,
|
||||
_ => throw new JsonException($"Unknown draw order '{s}'.")
|
||||
}, DrawOrder.TopDown);
|
||||
|
||||
var objects = element.GetOptionalPropertyCustom<List<Object>>("objects", e => e.GetValueAsList<Object>(el => ReadObject(el, externalTemplateResolver, customTypeDefinitions)), []);
|
||||
|
||||
return new ObjectLayer
|
||||
{
|
||||
ID = id,
|
||||
Name = name,
|
||||
Class = @class,
|
||||
Opacity = opacity,
|
||||
Visible = visible,
|
||||
TintColor = tintColor,
|
||||
OffsetX = offsetX,
|
||||
OffsetY = offsetY,
|
||||
ParallaxX = parallaxX,
|
||||
ParallaxY = parallaxY,
|
||||
Properties = properties,
|
||||
X = x,
|
||||
Y = y,
|
||||
Width = width,
|
||||
Height = height,
|
||||
Color = color,
|
||||
DrawOrder = drawOrder,
|
||||
Objects = objects
|
||||
};
|
||||
}
|
||||
|
||||
internal static Object ReadObject(
|
||||
JsonElement element,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
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;
|
||||
bool ellipseDefault = false;
|
||||
bool pointDefault = false;
|
||||
List<Vector2>? polygonDefault = null;
|
||||
List<Vector2>? polylineDefault = null;
|
||||
Dictionary<string, IProperty>? propertiesDefault = null;
|
||||
|
||||
var template = element.GetOptionalProperty<string?>("template", null);
|
||||
if (template is not null)
|
||||
{
|
||||
var resolvedTemplate = externalTemplateResolver(template);
|
||||
var templObj = resolvedTemplate.Object;
|
||||
|
||||
idDefault = templObj.ID;
|
||||
nameDefault = templObj.Name;
|
||||
typeDefault = templObj.Type;
|
||||
xDefault = templObj.X;
|
||||
yDefault = templObj.Y;
|
||||
widthDefault = templObj.Width;
|
||||
heightDefault = templObj.Height;
|
||||
rotationDefault = templObj.Rotation;
|
||||
gidDefault = templObj.GID;
|
||||
visibleDefault = templObj.Visible;
|
||||
propertiesDefault = templObj.Properties;
|
||||
ellipseDefault = templObj is EllipseObject;
|
||||
pointDefault = templObj is PointObject;
|
||||
polygonDefault = (templObj is PolygonObject polygonObj) ? polygonObj.Points : null;
|
||||
polylineDefault = (templObj is PolylineObject polylineObj) ? polylineObj.Points : null;
|
||||
}
|
||||
|
||||
var ellipse = element.GetOptionalProperty<bool>("ellipse", ellipseDefault);
|
||||
var gid = element.GetOptionalProperty<uint?>("gid", gidDefault);
|
||||
var height = element.GetOptionalProperty<float>("height", heightDefault);
|
||||
var id = element.GetOptionalProperty<uint?>("id", idDefault);
|
||||
var name = element.GetOptionalProperty<string>("name", nameDefault);
|
||||
var point = element.GetOptionalProperty<bool>("point", pointDefault);
|
||||
var polygon = element.GetOptionalPropertyCustom<List<Vector2>?>("polygon", e => ReadPoints(e), polygonDefault);
|
||||
var polyline = element.GetOptionalPropertyCustom<List<Vector2>?>("polyline", e => ReadPoints(e), polylineDefault);
|
||||
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", e => ReadProperties(e, customTypeDefinitions), propertiesDefault);
|
||||
var rotation = element.GetOptionalProperty<float>("rotation", rotationDefault);
|
||||
// var text
|
||||
var type = element.GetOptionalProperty<string>("type", typeDefault);
|
||||
var visible = element.GetOptionalProperty<bool>("visible", visibleDefault);
|
||||
var width = element.GetOptionalProperty<float>("width", widthDefault);
|
||||
var x = element.GetOptionalProperty<float>("x", xDefault);
|
||||
var y = element.GetOptionalProperty<float>("y", yDefault);
|
||||
|
||||
if (ellipse)
|
||||
{
|
||||
return new EllipseObject
|
||||
{
|
||||
ID = id,
|
||||
Name = name,
|
||||
Type = type,
|
||||
X = x,
|
||||
Y = y,
|
||||
Width = width,
|
||||
Height = height,
|
||||
Rotation = rotation,
|
||||
GID = gid,
|
||||
Visible = visible,
|
||||
Template = template,
|
||||
Properties = properties
|
||||
};
|
||||
}
|
||||
|
||||
if (point)
|
||||
{
|
||||
return new PointObject
|
||||
{
|
||||
ID = id,
|
||||
Name = name,
|
||||
Type = type,
|
||||
X = x,
|
||||
Y = y,
|
||||
Width = width,
|
||||
Height = height,
|
||||
Rotation = rotation,
|
||||
GID = gid,
|
||||
Visible = visible,
|
||||
Template = template,
|
||||
Properties = properties
|
||||
};
|
||||
}
|
||||
|
||||
if (polygon is not null)
|
||||
{
|
||||
return new PolygonObject
|
||||
{
|
||||
ID = id,
|
||||
Name = name,
|
||||
Type = type,
|
||||
X = x,
|
||||
Y = y,
|
||||
Width = width,
|
||||
Height = height,
|
||||
Rotation = rotation,
|
||||
GID = gid,
|
||||
Visible = visible,
|
||||
Template = template,
|
||||
Properties = properties,
|
||||
Points = polygon
|
||||
};
|
||||
}
|
||||
|
||||
if (polyline is not null)
|
||||
{
|
||||
return new PolylineObject
|
||||
{
|
||||
ID = id,
|
||||
Name = name,
|
||||
Type = type,
|
||||
X = x,
|
||||
Y = y,
|
||||
Width = width,
|
||||
Height = height,
|
||||
Rotation = rotation,
|
||||
GID = gid,
|
||||
Visible = visible,
|
||||
Template = template,
|
||||
Properties = properties,
|
||||
Points = polyline
|
||||
};
|
||||
}
|
||||
|
||||
// Text
|
||||
|
||||
return new RectangleObject
|
||||
{
|
||||
ID = id,
|
||||
Name = name,
|
||||
Type = type,
|
||||
X = x,
|
||||
Y = y,
|
||||
Width = width,
|
||||
Height = height,
|
||||
Rotation = rotation,
|
||||
GID = gid,
|
||||
Visible = visible,
|
||||
Template = template,
|
||||
Properties = properties
|
||||
};
|
||||
}
|
||||
|
||||
internal static List<Vector2> ReadPoints(JsonElement element) =>
|
||||
element.GetValueAsList<Vector2>(e =>
|
||||
{
|
||||
var x = e.GetRequiredProperty<float>("x");
|
||||
var y = e.GetRequiredProperty<float>("y");
|
||||
return new Vector2(x, y);
|
||||
});
|
||||
|
||||
internal static Template ReadTemplate(
|
||||
JsonElement element,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
var type = element.GetRequiredProperty<string>("type");
|
||||
var tileset = element.GetOptionalPropertyCustom<Tileset?>("tileset", el => ReadTileset(el, externalTilesetResolver, externalTemplateResolver, customTypeDefinitions), null);
|
||||
var @object = element.GetRequiredPropertyCustom<Object>("object", el => ReadObject(el, externalTemplateResolver, customTypeDefinitions));
|
||||
|
||||
return new Template
|
||||
{
|
||||
Tileset = tileset,
|
||||
Object = @object
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,11 @@ namespace DotTiled;
|
|||
|
||||
internal partial class Tmj
|
||||
{
|
||||
internal static Map ReadMap(JsonElement element, Func<string, Tileset>? externalTilesetResolver, Func<string, Template> externalTemplateResolver)
|
||||
internal static Map ReadMap(
|
||||
JsonElement element,
|
||||
Func<string, Tileset>? externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
var version = element.GetRequiredProperty<string>("version");
|
||||
var tiledVersion = element.GetRequiredProperty<string>("tiledversion");
|
||||
|
@ -55,10 +59,10 @@ internal partial class Tmj
|
|||
var nextObjectID = element.GetRequiredProperty<uint>("nextobjectid");
|
||||
var infinite = element.GetOptionalProperty<bool>("infinite", false);
|
||||
|
||||
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", ReadProperties, null);
|
||||
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", el => ReadProperties(el, customTypeDefinitions), null);
|
||||
|
||||
List<BaseLayer> layers = element.GetOptionalPropertyCustom<List<BaseLayer>>("layers", e => e.GetValueAsList<BaseLayer>(ReadLayer), []);
|
||||
List<Tileset> tilesets = element.GetOptionalPropertyCustom<List<Tileset>>("tilesets", e => e.GetValueAsList<Tileset>(el => ReadTileset(el, externalTilesetResolver, externalTemplateResolver)), []);
|
||||
List<BaseLayer> layers = element.GetOptionalPropertyCustom<List<BaseLayer>>("layers", e => e.GetValueAsList<BaseLayer>(el => ReadLayer(el, externalTemplateResolver, customTypeDefinitions)), []);
|
||||
List<Tileset> tilesets = element.GetOptionalPropertyCustom<List<Tileset>>("tilesets", e => e.GetValueAsList<Tileset>(el => ReadTileset(el, externalTilesetResolver, externalTemplateResolver, customTypeDefinitions)), []);
|
||||
|
||||
return new Map
|
||||
{
|
||||
|
|
|
@ -8,7 +8,9 @@ namespace DotTiled;
|
|||
|
||||
internal partial class Tmj
|
||||
{
|
||||
internal static Dictionary<string, IProperty> ReadProperties(JsonElement element) =>
|
||||
internal static Dictionary<string, IProperty> ReadProperties(
|
||||
JsonElement element,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions) =>
|
||||
element.GetValueAsList<IProperty>(e =>
|
||||
{
|
||||
var name = e.GetRequiredProperty<string>("name");
|
||||
|
@ -34,20 +36,105 @@ internal partial class Tmj
|
|||
PropertyType.Color => new ColorProperty { Name = name, Value = e.GetRequiredPropertyParseable<Color>("value") },
|
||||
PropertyType.File => new FileProperty { Name = name, Value = e.GetRequiredProperty<string>("value") },
|
||||
PropertyType.Object => new ObjectProperty { Name = name, Value = e.GetRequiredProperty<uint>("value") },
|
||||
PropertyType.Class => ReadClassProperty(e),
|
||||
PropertyType.Class => ReadClassProperty(e, customTypeDefinitions),
|
||||
_ => throw new JsonException("Invalid property type")
|
||||
};
|
||||
|
||||
return property!;
|
||||
}).ToDictionary(p => p.Name);
|
||||
|
||||
internal static ClassProperty ReadClassProperty(JsonElement element)
|
||||
internal static ClassProperty ReadClassProperty(
|
||||
JsonElement element,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
var name = element.GetRequiredProperty<string>("name");
|
||||
var propertyType = element.GetRequiredProperty<string>("propertytype");
|
||||
|
||||
var properties = element.GetRequiredPropertyCustom<Dictionary<string, IProperty>>("properties", ReadProperties);
|
||||
var customTypeDef = customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == propertyType);
|
||||
|
||||
return new ClassProperty { Name = name, PropertyType = propertyType, Properties = properties };
|
||||
if (customTypeDef is CustomClassDefinition ccd)
|
||||
{
|
||||
var propsInType = CreateInstanceOfCustomClass(ccd);
|
||||
var props = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>>("value", el => ReadCustomClassProperties(el, ccd, customTypeDefinitions), []);
|
||||
|
||||
var mergedProps = MergeProperties(propsInType, props);
|
||||
|
||||
return new ClassProperty
|
||||
{
|
||||
Name = name,
|
||||
PropertyType = propertyType,
|
||||
Properties = mergedProps
|
||||
};
|
||||
}
|
||||
|
||||
throw new JsonException($"Unknown custom class '{propertyType}'.");
|
||||
}
|
||||
|
||||
internal static Dictionary<string, IProperty> ReadCustomClassProperties(
|
||||
JsonElement element,
|
||||
CustomClassDefinition customClassDefinition,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
Dictionary<string, IProperty> resultingProps = [];
|
||||
|
||||
foreach (var prop in customClassDefinition.Members)
|
||||
{
|
||||
if (!element.TryGetProperty(prop.Name, out var propElement))
|
||||
continue; // Property not present in element, therefore will use default value
|
||||
|
||||
IProperty property = prop.Type switch
|
||||
{
|
||||
PropertyType.String => new StringProperty { Name = prop.Name, Value = propElement.GetValueAs<string>() },
|
||||
PropertyType.Int => new IntProperty { Name = prop.Name, Value = propElement.GetValueAs<int>() },
|
||||
PropertyType.Float => new FloatProperty { Name = prop.Name, Value = propElement.GetValueAs<float>() },
|
||||
PropertyType.Bool => new BoolProperty { Name = prop.Name, Value = propElement.GetValueAs<bool>() },
|
||||
PropertyType.Color => new ColorProperty { Name = prop.Name, Value = Color.Parse(propElement.GetValueAs<string>(), CultureInfo.InvariantCulture) },
|
||||
PropertyType.File => new FileProperty { Name = prop.Name, Value = propElement.GetValueAs<string>() },
|
||||
PropertyType.Object => new ObjectProperty { Name = prop.Name, Value = propElement.GetValueAs<uint>() },
|
||||
PropertyType.Class => ReadClassProperty(propElement, customTypeDefinitions),
|
||||
_ => throw new JsonException("Invalid property type")
|
||||
};
|
||||
|
||||
resultingProps[prop.Name] = property;
|
||||
}
|
||||
|
||||
return resultingProps;
|
||||
}
|
||||
|
||||
internal static Dictionary<string, IProperty> CreateInstanceOfCustomClass(CustomClassDefinition customClassDefinition)
|
||||
{
|
||||
return customClassDefinition.Members.ToDictionary(m => m.Name, m => m.Clone());
|
||||
}
|
||||
|
||||
internal static Dictionary<string, IProperty> MergeProperties(Dictionary<string, IProperty>? baseProperties, Dictionary<string, IProperty> overrideProperties)
|
||||
{
|
||||
if (baseProperties is null)
|
||||
return overrideProperties ?? new Dictionary<string, IProperty>();
|
||||
|
||||
if (overrideProperties is null)
|
||||
return baseProperties;
|
||||
|
||||
var result = baseProperties.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Clone());
|
||||
foreach (var (key, value) in overrideProperties)
|
||||
{
|
||||
if (!result.TryGetValue(key, out var baseProp))
|
||||
{
|
||||
result[key] = value;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value is ClassProperty classProp)
|
||||
{
|
||||
((ClassProperty)baseProp).Properties = MergeProperties(((ClassProperty)baseProp).Properties, classProp.Properties);
|
||||
}
|
||||
else
|
||||
{
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,11 @@ namespace DotTiled;
|
|||
|
||||
internal partial class Tmj
|
||||
{
|
||||
internal static Tileset ReadTileset(JsonElement element, Func<string, Tileset>? externalTilesetResolver, Func<string, Template> externalTemplateResolver)
|
||||
internal static Tileset ReadTileset(
|
||||
JsonElement element,
|
||||
Func<string, Tileset>? externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
var backgroundColor = element.GetOptionalPropertyParseable<Color?>("backgroundcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null);
|
||||
var @class = element.GetOptionalProperty<string>("class", "");
|
||||
|
@ -42,7 +46,7 @@ internal partial class Tmj
|
|||
"bottomright" => ObjectAlignment.BottomRight,
|
||||
_ => throw new JsonException($"Unknown object alignment '{s}'")
|
||||
}, ObjectAlignment.Unspecified);
|
||||
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", ReadProperties, null);
|
||||
var properties = element.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", el => ReadProperties(el, customTypeDefinitions), null);
|
||||
var source = element.GetOptionalProperty<string?>("source", null);
|
||||
var spacing = element.GetOptionalProperty<uint?>("spacing", null);
|
||||
var tileCount = element.GetOptionalProperty<uint?>("tilecount", null);
|
||||
|
@ -55,7 +59,7 @@ internal partial class Tmj
|
|||
"grid" => TileRenderSize.Grid,
|
||||
_ => throw new JsonException($"Unknown tile render size '{s}'")
|
||||
}, TileRenderSize.Tile);
|
||||
var tiles = element.GetOptionalPropertyCustom<List<Tile>>("tiles", ReadTiles, []);
|
||||
var tiles = element.GetOptionalPropertyCustom<List<Tile>>("tiles", el => ReadTiles(el, customTypeDefinitions), []);
|
||||
var tileWidth = element.GetOptionalProperty<uint?>("tilewidth", null);
|
||||
var transparentColor = element.GetOptionalPropertyParseable<Color?>("transparentcolor", s => Color.Parse(s, CultureInfo.InvariantCulture), null);
|
||||
var type = element.GetOptionalProperty<string?>("type", null);
|
||||
|
@ -153,7 +157,9 @@ internal partial class Tmj
|
|||
};
|
||||
}
|
||||
|
||||
internal static List<Tile> ReadTiles(JsonElement element) =>
|
||||
internal static List<Tile> ReadTiles(
|
||||
JsonElement element,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions) =>
|
||||
element.GetValueAsList<Tile>(e =>
|
||||
{
|
||||
//var animation = e.GetOptionalPropertyCustom<List<Frame>>("animation", ReadFrames, null);
|
||||
|
@ -167,7 +173,7 @@ internal partial class Tmj
|
|||
var height = e.GetOptionalProperty<uint>("height", imageHeight ?? 0);
|
||||
//var objectGroup = e.GetOptionalPropertyCustom<ObjectLayer?>("objectgroup", ReadObjectLayer, null);
|
||||
var probability = e.GetOptionalProperty<float>("probability", 1.0f);
|
||||
var properties = e.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", ReadProperties, null);
|
||||
var properties = e.GetOptionalPropertyCustom<Dictionary<string, IProperty>?>("properties", el => ReadProperties(el, customTypeDefinitions), null);
|
||||
// var terrain, replaced by wangsets
|
||||
var type = e.GetOptionalProperty<string>("type", "");
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
@ -14,18 +15,25 @@ public class TmjMapReader : IMapReader
|
|||
private string _jsonString;
|
||||
private bool disposedValue;
|
||||
|
||||
public TmjMapReader(string jsonString, Func<string, Tileset> externalTilesetResolver, Func<string, Template> externalTemplateResolver)
|
||||
private readonly IReadOnlyCollection<CustomTypeDefinition> _customTypeDefinitions;
|
||||
|
||||
public TmjMapReader(
|
||||
string jsonString,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
_jsonString = jsonString ?? throw new ArgumentNullException(nameof(jsonString));
|
||||
_externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver));
|
||||
_externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver));
|
||||
_customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions));
|
||||
}
|
||||
|
||||
public Map ReadMap()
|
||||
{
|
||||
var jsonDoc = JsonDocument.Parse(_jsonString);
|
||||
var rootElement = jsonDoc.RootElement;
|
||||
return Tmj.ReadMap(rootElement, _externalTilesetResolver, _externalTemplateResolver);
|
||||
return Tmj.ReadMap(rootElement, _externalTilesetResolver, _externalTemplateResolver, _customTypeDefinitions);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
|
|
65
DotTiled/Serialization/Tmj/TsjTilesetReader.cs
Normal file
65
DotTiled/Serialization/Tmj/TsjTilesetReader.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotTiled;
|
||||
|
||||
public class TsjTilesetReader : ITilesetReader
|
||||
{
|
||||
// External resolvers
|
||||
private readonly Func<string, Template> _externalTemplateResolver;
|
||||
|
||||
private readonly string _jsonString;
|
||||
private bool disposedValue;
|
||||
|
||||
private readonly IReadOnlyCollection<CustomTypeDefinition> _customTypeDefinitions;
|
||||
|
||||
public TsjTilesetReader(
|
||||
string jsonString,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
IReadOnlyCollection<CustomTypeDefinition> customTypeDefinitions)
|
||||
{
|
||||
_jsonString = jsonString ?? throw new ArgumentNullException(nameof(jsonString));
|
||||
_externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver));
|
||||
_customTypeDefinitions = customTypeDefinitions ?? throw new ArgumentNullException(nameof(customTypeDefinitions));
|
||||
}
|
||||
|
||||
public Tileset ReadTileset()
|
||||
{
|
||||
var jsonDoc = System.Text.Json.JsonDocument.Parse(_jsonString);
|
||||
var rootElement = jsonDoc.RootElement;
|
||||
return Tmj.ReadTileset(
|
||||
rootElement,
|
||||
_ => throw new NotSupportedException("External tilesets cannot refer to other external tilesets."),
|
||||
_externalTemplateResolver,
|
||||
_customTypeDefinitions);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: dispose managed state (managed objects)
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||
// TODO: set large fields to null
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||
// ~TsjTilesetReader()
|
||||
// {
|
||||
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
// Dispose(disposing: false);
|
||||
// }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
System.GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue