mirror of
https://github.com/dcronqvist/DotTiled.git
synced 2025-02-05 08:52:50 +02:00
Make custom types optional
This commit is contained in:
parent
67876c6532
commit
8c9068cc97
21 changed files with 189 additions and 59 deletions
|
@ -73,12 +73,12 @@ public class Program
|
|||
return templateReader.ReadTemplate();
|
||||
}
|
||||
|
||||
private static ICustomTypeDefinition ResolveCustomType(string name)
|
||||
private static Optional<ICustomTypeDefinition> ResolveCustomType(string name)
|
||||
{
|
||||
ICustomTypeDefinition[] allDefinedTypes =
|
||||
[
|
||||
new CustomClassDefinition() { Name = "a" },
|
||||
];
|
||||
return allDefinedTypes.FirstOrDefault(type => type.Name == name) ?? throw new InvalidOperationException();
|
||||
return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional<ICustomTypeDefinition>(ctd) : Optional<ICustomTypeDefinition>.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using DotTiled.Serialization;
|
||||
|
@ -57,12 +56,12 @@ public partial class MapParser : Node2D
|
|||
return templateReader.ReadTemplate();
|
||||
}
|
||||
|
||||
private static ICustomTypeDefinition ResolveCustomType(string name)
|
||||
private static Optional<ICustomTypeDefinition> ResolveCustomType(string name)
|
||||
{
|
||||
ICustomTypeDefinition[] allDefinedTypes =
|
||||
[
|
||||
new CustomClassDefinition() { Name = "a" },
|
||||
];
|
||||
return allDefinedTypes.FirstOrDefault(type => type.Name == name) ?? throw new InvalidOperationException();
|
||||
return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional<ICustomTypeDefinition>(ctd) : Optional<ICustomTypeDefinition>.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -246,7 +246,7 @@ public class LoaderTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void LoadMap_MapHasClassAndLoaderHasNoCustomTypes_ThrowsException()
|
||||
public void LoadMap_MapHasClassAndLoaderHasNoCustomTypes_ReturnsMapWithEmptyProperties()
|
||||
{
|
||||
// Arrange
|
||||
var resourceReader = Substitute.For<IResourceReader>();
|
||||
|
@ -270,8 +270,11 @@ public class LoaderTests
|
|||
var customTypeDefinitions = Enumerable.Empty<ICustomTypeDefinition>();
|
||||
var loader = new Loader(resourceReader, resourceCache, customTypeDefinitions);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<KeyNotFoundException>(() => loader.LoadMap("map.tmx"));
|
||||
// Act
|
||||
var result = loader.LoadMap("map.tmx");
|
||||
|
||||
// Assert
|
||||
DotTiledAssert.AssertProperties([], result.Properties);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -32,9 +32,14 @@ public partial class MapReaderTests
|
|||
using var tilesetReader = new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType);
|
||||
return tilesetReader.ReadTileset();
|
||||
}
|
||||
ICustomTypeDefinition ResolveCustomType(string name)
|
||||
Optional<ICustomTypeDefinition> ResolveCustomType(string name)
|
||||
{
|
||||
return customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name)!;
|
||||
if (customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd)
|
||||
{
|
||||
return new Optional<ICustomTypeDefinition>(ctd);
|
||||
}
|
||||
|
||||
return Optional<ICustomTypeDefinition>.Empty;
|
||||
}
|
||||
using var mapReader = new MapReader(mapString, ResolveTileset, ResolveTemplate, ResolveCustomType);
|
||||
|
||||
|
|
|
@ -28,9 +28,14 @@ public partial class TmjMapReaderTests
|
|||
using var tilesetReader = new TsjTilesetReader(tilesetJson, ResolveTileset, ResolveTemplate, ResolveCustomType);
|
||||
return tilesetReader.ReadTileset();
|
||||
}
|
||||
ICustomTypeDefinition ResolveCustomType(string name)
|
||||
Optional<ICustomTypeDefinition> ResolveCustomType(string name)
|
||||
{
|
||||
return customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name)!;
|
||||
if (customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd)
|
||||
{
|
||||
return new Optional<ICustomTypeDefinition>(ctd);
|
||||
}
|
||||
|
||||
return Optional<ICustomTypeDefinition>.Empty;
|
||||
}
|
||||
using var mapReader = new TmjMapReader(json, ResolveTileset, ResolveTemplate, ResolveCustomType);
|
||||
|
||||
|
|
|
@ -28,9 +28,14 @@ public partial class TmxMapReaderTests
|
|||
using var tilesetReader = new TsxTilesetReader(xmlTilesetReader, ResolveTileset, ResolveTemplate, ResolveCustomType);
|
||||
return tilesetReader.ReadTileset();
|
||||
}
|
||||
ICustomTypeDefinition ResolveCustomType(string name)
|
||||
Optional<ICustomTypeDefinition> ResolveCustomType(string name)
|
||||
{
|
||||
return customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name)!;
|
||||
if (customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd)
|
||||
{
|
||||
return new Optional<ICustomTypeDefinition>(ctd);
|
||||
}
|
||||
|
||||
return Optional<ICustomTypeDefinition>.Empty;
|
||||
}
|
||||
using var mapReader = new TmxMapReader(reader, ResolveTileset, ResolveTemplate, ResolveCustomType);
|
||||
|
||||
|
|
|
@ -86,13 +86,16 @@ internal static partial class Helpers
|
|||
};
|
||||
}
|
||||
|
||||
internal static List<IProperty> ResolveClassProperties(string className, Func<string, ICustomTypeDefinition> customTypeResolver)
|
||||
internal static List<IProperty> ResolveClassProperties(string className, Func<string, Optional<ICustomTypeDefinition>> customTypeResolver)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(className))
|
||||
return null;
|
||||
|
||||
var customType = customTypeResolver(className) ?? throw new InvalidOperationException($"Could not resolve custom type '{className}'.");
|
||||
if (customType is not CustomClassDefinition ccd)
|
||||
if (!customType.HasValue)
|
||||
return null;
|
||||
|
||||
if (customType.Value is not CustomClassDefinition ccd)
|
||||
throw new InvalidOperationException($"Custom type '{className}' is not a class.");
|
||||
|
||||
return CreateInstanceOfCustomClass(ccd, customTypeResolver);
|
||||
|
@ -100,17 +103,31 @@ internal static partial class Helpers
|
|||
|
||||
internal static List<IProperty> CreateInstanceOfCustomClass(
|
||||
CustomClassDefinition customClassDefinition,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver)
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver)
|
||||
{
|
||||
return customClassDefinition.Members.Select(x =>
|
||||
{
|
||||
if (x is ClassProperty cp)
|
||||
{
|
||||
var resolvedType = customTypeResolver(cp.PropertyType);
|
||||
if (!resolvedType.HasValue)
|
||||
{
|
||||
return new ClassProperty
|
||||
{
|
||||
Name = cp.Name,
|
||||
PropertyType = cp.PropertyType,
|
||||
Value = []
|
||||
};
|
||||
}
|
||||
|
||||
if (resolvedType.Value is not CustomClassDefinition ccd)
|
||||
throw new InvalidOperationException($"Custom type '{cp.PropertyType}' is not a class.");
|
||||
|
||||
return new ClassProperty
|
||||
{
|
||||
Name = cp.Name,
|
||||
PropertyType = cp.PropertyType,
|
||||
Value = CreateInstanceOfCustomClass((CustomClassDefinition)customTypeResolver(cp.PropertyType), customTypeResolver)
|
||||
Value = CreateInstanceOfCustomClass(ccd, customTypeResolver)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ public class Loader
|
|||
{
|
||||
private readonly IResourceReader _resourceReader;
|
||||
private readonly IResourceCache _resourceCache;
|
||||
private readonly IDictionary<string, ICustomTypeDefinition> _customTypeDefinitions;
|
||||
private readonly Dictionary<string, ICustomTypeDefinition> _customTypeDefinitions;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Loader"/> class with the given <paramref name="resourceReader"/>, <paramref name="resourceCache"/>, and <paramref name="customTypeDefinitions"/>.
|
||||
|
@ -114,5 +114,11 @@ public class Loader
|
|||
return templateReader.ReadTemplate();
|
||||
});
|
||||
|
||||
private ICustomTypeDefinition CustomTypeResolver(string name) => _customTypeDefinitions[name];
|
||||
private Optional<ICustomTypeDefinition> CustomTypeResolver(string name)
|
||||
{
|
||||
if (_customTypeDefinitions.TryGetValue(name, out var customTypeDefinition))
|
||||
return new Optional<ICustomTypeDefinition>(customTypeDefinition);
|
||||
|
||||
return Optional<ICustomTypeDefinition>.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ public class MapReader : IMapReader
|
|||
// External resolvers
|
||||
private readonly Func<string, Tileset> _externalTilesetResolver;
|
||||
private readonly Func<string, Template> _externalTemplateResolver;
|
||||
private readonly Func<string, ICustomTypeDefinition> _customTypeResolver;
|
||||
private readonly Func<string, Optional<ICustomTypeDefinition>> _customTypeResolver;
|
||||
|
||||
private readonly StringReader _mapStringReader;
|
||||
private readonly XmlReader _xmlReader;
|
||||
|
@ -33,7 +33,7 @@ public class MapReader : IMapReader
|
|||
string map,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver)
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver)
|
||||
{
|
||||
_externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver));
|
||||
_externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver));
|
||||
|
|
|
@ -14,7 +14,7 @@ public class TemplateReader : ITemplateReader
|
|||
// External resolvers
|
||||
private readonly Func<string, Tileset> _externalTilesetResolver;
|
||||
private readonly Func<string, Template> _externalTemplateResolver;
|
||||
private readonly Func<string, ICustomTypeDefinition> _customTypeResolver;
|
||||
private readonly Func<string, Optional<ICustomTypeDefinition>> _customTypeResolver;
|
||||
|
||||
private readonly StringReader _templateStringReader;
|
||||
private readonly XmlReader _xmlReader;
|
||||
|
@ -33,7 +33,7 @@ public class TemplateReader : ITemplateReader
|
|||
string template,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver)
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver)
|
||||
{
|
||||
_externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver));
|
||||
_externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver));
|
||||
|
|
|
@ -14,7 +14,7 @@ public class TilesetReader : ITilesetReader
|
|||
// External resolvers
|
||||
private readonly Func<string, Tileset> _externalTilesetResolver;
|
||||
private readonly Func<string, Template> _externalTemplateResolver;
|
||||
private readonly Func<string, ICustomTypeDefinition> _customTypeResolver;
|
||||
private readonly Func<string, Optional<ICustomTypeDefinition>> _customTypeResolver;
|
||||
|
||||
private readonly StringReader _tilesetStringReader;
|
||||
private readonly XmlReader _xmlReader;
|
||||
|
@ -33,7 +33,7 @@ public class TilesetReader : ITilesetReader
|
|||
string tileset,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver)
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver)
|
||||
{
|
||||
_externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver));
|
||||
_externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver));
|
||||
|
|
|
@ -19,7 +19,7 @@ public class TjTemplateReader : TmjReaderBase, ITemplateReader
|
|||
string jsonString,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver) : base(
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver) : base(
|
||||
jsonString, externalTilesetResolver, externalTemplateResolver, customTypeResolver)
|
||||
{ }
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ public class TmjMapReader : TmjReaderBase, IMapReader
|
|||
string jsonString,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver) : base(
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver) : base(
|
||||
jsonString, externalTilesetResolver, externalTemplateResolver, customTypeResolver)
|
||||
{ }
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
@ -63,21 +64,38 @@ public abstract partial class TmjReaderBase
|
|||
var propertyType = element.GetRequiredProperty<string>("propertytype");
|
||||
var customTypeDef = _customTypeResolver(propertyType);
|
||||
|
||||
if (customTypeDef is CustomClassDefinition ccd)
|
||||
// If the custom class definition is not found,
|
||||
// we assume an empty class definition.
|
||||
if (!customTypeDef.HasValue)
|
||||
{
|
||||
var propsInType = Helpers.CreateInstanceOfCustomClass(ccd, _customTypeResolver);
|
||||
var props = element.GetOptionalPropertyCustom<List<IProperty>>("value", e => ReadPropertiesInsideClass(e, ccd)).GetValueOr([]);
|
||||
var mergedProps = Helpers.MergeProperties(propsInType, props);
|
||||
if (!element.TryGetProperty("value", out var valueElement))
|
||||
return new ClassProperty { Name = name, PropertyType = propertyType, Value = [] };
|
||||
|
||||
return new ClassProperty
|
||||
{
|
||||
Name = name,
|
||||
PropertyType = propertyType,
|
||||
Value = mergedProps
|
||||
Value = ReadPropertiesInsideClass(valueElement, new CustomClassDefinition
|
||||
{
|
||||
Name = propertyType,
|
||||
Members = []
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
throw new JsonException($"Unknown custom class '{propertyType}'.");
|
||||
if (customTypeDef.Value is not CustomClassDefinition ccd)
|
||||
throw new JsonException($"Custom type {propertyType} is not a class.");
|
||||
|
||||
var propsInType = Helpers.CreateInstanceOfCustomClass(ccd, _customTypeResolver);
|
||||
var props = element.GetOptionalPropertyCustom<List<IProperty>>("value", e => ReadPropertiesInsideClass(e, ccd)).GetValueOr([]);
|
||||
var mergedProps = Helpers.MergeProperties(propsInType, props);
|
||||
|
||||
return new ClassProperty
|
||||
{
|
||||
Name = name,
|
||||
PropertyType = propertyType,
|
||||
Value = mergedProps
|
||||
};
|
||||
}
|
||||
|
||||
internal List<IProperty> ReadPropertiesInsideClass(
|
||||
|
@ -91,6 +109,33 @@ public abstract partial class TmjReaderBase
|
|||
if (!element.TryGetProperty(prop.Name, out var propElement))
|
||||
continue;
|
||||
|
||||
if (prop is ClassProperty classProp)
|
||||
{
|
||||
var resolvedCustomType = _customTypeResolver(classProp.PropertyType);
|
||||
if (!resolvedCustomType.HasValue)
|
||||
{
|
||||
resultingProps.Add(new ClassProperty
|
||||
{
|
||||
Name = classProp.Name,
|
||||
PropertyType = classProp.PropertyType,
|
||||
Value = []
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (resolvedCustomType.Value is not CustomClassDefinition ccd)
|
||||
throw new JsonException($"Custom type '{classProp.PropertyType}' is not a class.");
|
||||
|
||||
var readProps = ReadPropertiesInsideClass(propElement, ccd);
|
||||
resultingProps.Add(new ClassProperty
|
||||
{
|
||||
Name = classProp.Name,
|
||||
PropertyType = classProp.PropertyType,
|
||||
Value = readProps
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
IProperty property = prop.Type switch
|
||||
{
|
||||
PropertyType.String => new StringProperty { Name = prop.Name, Value = propElement.GetValueAs<string>() },
|
||||
|
@ -100,8 +145,8 @@ public abstract partial class TmjReaderBase
|
|||
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 => new ClassProperty { Name = prop.Name, PropertyType = ((ClassProperty)prop).PropertyType, Value = ReadPropertiesInsideClass(propElement, (CustomClassDefinition)_customTypeResolver(((ClassProperty)prop).PropertyType)) },
|
||||
PropertyType.Enum => ReadEnumProperty(propElement),
|
||||
PropertyType.Class => throw new NotImplementedException("Class properties should be handled elsewhere"),
|
||||
_ => throw new JsonException("Invalid property type")
|
||||
};
|
||||
|
||||
|
@ -115,7 +160,7 @@ public abstract partial class TmjReaderBase
|
|||
{
|
||||
var name = element.GetRequiredProperty<string>("name");
|
||||
var propertyType = element.GetRequiredProperty<string>("propertytype");
|
||||
var typeInXml = element.GetOptionalPropertyParseable<PropertyType>("type", (s) => s switch
|
||||
var typeInJson = element.GetOptionalPropertyParseable<PropertyType>("type", (s) => s switch
|
||||
{
|
||||
"string" => PropertyType.String,
|
||||
"int" => PropertyType.Int,
|
||||
|
@ -123,8 +168,24 @@ public abstract partial class TmjReaderBase
|
|||
}).GetValueOr(PropertyType.String);
|
||||
var customTypeDef = _customTypeResolver(propertyType);
|
||||
|
||||
if (customTypeDef is not CustomEnumDefinition ced)
|
||||
throw new JsonException($"Unknown custom enum '{propertyType}'. Enums must be defined");
|
||||
if (!customTypeDef.HasValue)
|
||||
{
|
||||
if (typeInJson == PropertyType.String)
|
||||
{
|
||||
var value = element.GetRequiredProperty<string>("value");
|
||||
var values = value.Split(',').Select(v => v.Trim()).ToHashSet();
|
||||
return new EnumProperty { Name = name, PropertyType = propertyType, Value = values };
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = element.GetRequiredProperty<int>("value");
|
||||
var values = new HashSet<string> { value.ToString(CultureInfo.InvariantCulture) };
|
||||
return new EnumProperty { Name = name, PropertyType = propertyType, Value = values };
|
||||
}
|
||||
}
|
||||
|
||||
if (customTypeDef.Value is not CustomEnumDefinition ced)
|
||||
throw new JsonException($"Custom type '{propertyType}' is not an enum.");
|
||||
|
||||
if (ced.StorageType == CustomEnumStorageType.String)
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@ public abstract partial class TmjReaderBase : IDisposable
|
|||
// External resolvers
|
||||
private readonly Func<string, Tileset> _externalTilesetResolver;
|
||||
private readonly Func<string, Template> _externalTemplateResolver;
|
||||
private readonly Func<string, ICustomTypeDefinition> _customTypeResolver;
|
||||
private readonly Func<string, Optional<ICustomTypeDefinition>> _customTypeResolver;
|
||||
|
||||
/// <summary>
|
||||
/// The root element of the JSON document being read.
|
||||
|
@ -34,7 +34,7 @@ public abstract partial class TmjReaderBase : IDisposable
|
|||
string jsonString,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver)
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver)
|
||||
{
|
||||
RootElement = JsonDocument.Parse(jsonString ?? throw new ArgumentNullException(nameof(jsonString))).RootElement;
|
||||
_externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver));
|
||||
|
|
|
@ -19,7 +19,7 @@ public class TsjTilesetReader : TmjReaderBase, ITilesetReader
|
|||
string jsonString,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver) : base(
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver) : base(
|
||||
jsonString, externalTilesetResolver, externalTemplateResolver, customTypeResolver)
|
||||
{ }
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ public class TmxMapReader : TmxReaderBase, IMapReader
|
|||
XmlReader reader,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver) : base(
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver) : base(
|
||||
reader, externalTilesetResolver, externalTemplateResolver, customTypeResolver)
|
||||
{ }
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
|
||||
|
@ -66,25 +67,35 @@ public abstract partial class TmxReaderBase
|
|||
var propertyType = _reader.GetRequiredAttribute("propertytype");
|
||||
var customTypeDef = _customTypeResolver(propertyType);
|
||||
|
||||
if (customTypeDef is CustomClassDefinition ccd)
|
||||
// If the custom class definition is not found,
|
||||
// we assume an empty class definition.
|
||||
if (!customTypeDef.HasValue)
|
||||
{
|
||||
if (!_reader.IsEmptyElement)
|
||||
{
|
||||
_reader.ReadStartElement("property");
|
||||
var propsInType = Helpers.CreateInstanceOfCustomClass(ccd, _customTypeResolver);
|
||||
var props = ReadProperties();
|
||||
var mergedProps = Helpers.MergeProperties(propsInType, props);
|
||||
_reader.ReadEndElement();
|
||||
return new ClassProperty { Name = name, PropertyType = propertyType, Value = mergedProps };
|
||||
}
|
||||
else
|
||||
{
|
||||
var propsInType = Helpers.CreateInstanceOfCustomClass(ccd, _customTypeResolver);
|
||||
return new ClassProperty { Name = name, PropertyType = propertyType, Value = propsInType };
|
||||
return new ClassProperty { Name = name, PropertyType = propertyType, Value = props };
|
||||
}
|
||||
|
||||
return new ClassProperty { Name = name, PropertyType = propertyType, Value = [] };
|
||||
}
|
||||
|
||||
throw new XmlException($"Unkonwn custom class definition: {propertyType}");
|
||||
if (customTypeDef.Value is not CustomClassDefinition ccd)
|
||||
throw new XmlException($"Custom type {propertyType} is not a class.");
|
||||
|
||||
var propsInType = Helpers.CreateInstanceOfCustomClass(ccd, _customTypeResolver);
|
||||
if (!_reader.IsEmptyElement)
|
||||
{
|
||||
_reader.ReadStartElement("property");
|
||||
var props = ReadProperties();
|
||||
var mergedProps = Helpers.MergeProperties(propsInType, props);
|
||||
_reader.ReadEndElement();
|
||||
return new ClassProperty { Name = name, PropertyType = propertyType, Value = mergedProps };
|
||||
}
|
||||
|
||||
return new ClassProperty { Name = name, PropertyType = propertyType, Value = propsInType };
|
||||
}
|
||||
|
||||
internal EnumProperty ReadEnumProperty()
|
||||
|
@ -99,8 +110,26 @@ public abstract partial class TmxReaderBase
|
|||
}) ?? PropertyType.String;
|
||||
var customTypeDef = _customTypeResolver(propertyType);
|
||||
|
||||
if (customTypeDef is not CustomEnumDefinition ced)
|
||||
throw new XmlException($"Unknown custom enum definition: {propertyType}. Enums must be defined");
|
||||
// If the custom enum definition is not found,
|
||||
// we assume an empty enum definition.
|
||||
if (!customTypeDef.HasValue)
|
||||
{
|
||||
if (typeInXml == PropertyType.String)
|
||||
{
|
||||
var value = _reader.GetRequiredAttribute("value");
|
||||
var values = value.Split(',').Select(v => v.Trim()).ToHashSet();
|
||||
return new EnumProperty { Name = name, PropertyType = propertyType, Value = values };
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = _reader.GetRequiredAttributeParseable<int>("value");
|
||||
var values = new HashSet<string> { value.ToString(CultureInfo.InvariantCulture) };
|
||||
return new EnumProperty { Name = name, PropertyType = propertyType, Value = values };
|
||||
}
|
||||
}
|
||||
|
||||
if (customTypeDef.Value is not CustomEnumDefinition ced)
|
||||
throw new XmlException($"Custom defined type {propertyType} is not an enum.");
|
||||
|
||||
if (ced.StorageType == CustomEnumStorageType.String)
|
||||
{
|
||||
|
@ -144,6 +173,6 @@ public abstract partial class TmxReaderBase
|
|||
}
|
||||
}
|
||||
|
||||
throw new XmlException($"Unknown custom enum storage type: {ced.StorageType}");
|
||||
throw new XmlException($"Unable to read enum property {name} with type {propertyType}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ public abstract partial class TmxReaderBase : IDisposable
|
|||
// External resolvers
|
||||
private readonly Func<string, Tileset> _externalTilesetResolver;
|
||||
private readonly Func<string, Template> _externalTemplateResolver;
|
||||
private readonly Func<string, ICustomTypeDefinition> _customTypeResolver;
|
||||
private readonly Func<string, Optional<ICustomTypeDefinition>> _customTypeResolver;
|
||||
|
||||
private readonly XmlReader _reader;
|
||||
private bool disposedValue;
|
||||
|
@ -28,7 +28,7 @@ public abstract partial class TmxReaderBase : IDisposable
|
|||
XmlReader reader,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver)
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver)
|
||||
{
|
||||
_reader = reader ?? throw new ArgumentNullException(nameof(reader));
|
||||
_externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver));
|
||||
|
|
|
@ -16,7 +16,7 @@ public class TsxTilesetReader : TmxReaderBase, ITilesetReader
|
|||
XmlReader reader,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver) : base(
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver) : base(
|
||||
reader, externalTilesetResolver, externalTemplateResolver, customTypeResolver)
|
||||
{ }
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ public class TxTemplateReader : TmxReaderBase, ITemplateReader
|
|||
XmlReader reader,
|
||||
Func<string, Tileset> externalTilesetResolver,
|
||||
Func<string, Template> externalTemplateResolver,
|
||||
Func<string, ICustomTypeDefinition> customTypeResolver) : base(
|
||||
Func<string, Optional<ICustomTypeDefinition>> customTypeResolver) : base(
|
||||
reader, externalTilesetResolver, externalTemplateResolver, customTypeResolver)
|
||||
{ }
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue