mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-15 15:09:29 +00:00
Read particle file issue (#938)
* Correct exception message * Pass serializer options as param for MultiDimensional reads * Refactor to use TryGetRegion * Update for System.Text.Json parsing
This commit is contained in:
committed by
GitHub
parent
da81c353f6
commit
b1ad92a7a0
@@ -1,25 +1,306 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Unicode;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.Particles.Profiles;
|
||||
using MonoGame.Extended.Serialization.Json;
|
||||
|
||||
namespace MonoGame.Extended.Particles.Serialization
|
||||
{
|
||||
public class ProfileJsonConverter : BaseTypeJsonConverter<Profile>
|
||||
public class ProfileJsonConverter : JsonConverter<Profile>
|
||||
{
|
||||
public ProfileJsonConverter()
|
||||
: base(GetSupportedTypes(), nameof(Profile))
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Profile);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Profile Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType != JsonTokenType.StartObject)
|
||||
{
|
||||
throw new JsonException($"Expected {nameof(JsonTokenType.StartObject)} token");
|
||||
}
|
||||
|
||||
Profile profile = null;
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.EndObject)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (reader.TokenType == JsonTokenType.PropertyName)
|
||||
{
|
||||
var propertyName = reader.GetString();
|
||||
reader.Read();
|
||||
|
||||
if (propertyName.Equals("type", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
var type = reader.GetString();
|
||||
profile = type switch
|
||||
{
|
||||
nameof(Profile.Point) => Profile.Point(),
|
||||
nameof(Profile.Line) => ReadLineProfile(ref reader),
|
||||
nameof(Profile.Ring) => ReadRingProfile(ref reader),
|
||||
nameof(Profile.Box) => ReadBoxProfile(ref reader),
|
||||
nameof(Profile.BoxFill) => ReadBoxFillProfile(ref reader),
|
||||
nameof(Profile.BoxUniform) => ReadBoxUniformProfile(ref reader),
|
||||
nameof(Profile.Circle) => ReadCircleProfile(ref reader),
|
||||
nameof(Profile.Spray) => ReadSprayProfile(ref reader),
|
||||
|
||||
_ => throw new NotSupportedException($"The profile type {type} is not supported at this time")
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
private static IEnumerable<TypeInfo> GetSupportedTypes()
|
||||
private static Profile ReadLineProfile(ref Utf8JsonReader reader)
|
||||
{
|
||||
return typeof(Profile)
|
||||
.GetTypeInfo()
|
||||
.Assembly
|
||||
.DefinedTypes
|
||||
.Where(type => type.IsSubclassOf(typeof(Profile)) && !type.IsAbstract);
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("axis", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
string[] split = reader.GetString().Split(" ", StringSplitOptions.RemoveEmptyEntries);
|
||||
Debug.Assert(split.Length == 2);
|
||||
Vector2 axis = new Vector2(float.Parse(split[0]), float.Parse(split[1]));
|
||||
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("length", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
float length = reader.GetSingle();
|
||||
|
||||
return Profile.Line(axis, length);
|
||||
}
|
||||
|
||||
private static Profile ReadRingProfile(ref Utf8JsonReader reader)
|
||||
{
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("radius", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
float radius = reader.GetSingle();
|
||||
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("radiate", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
int radiate = reader.GetInt32();
|
||||
|
||||
return Profile.Ring(radius, (Profile.CircleRadiation)radiate);
|
||||
}
|
||||
|
||||
private static Profile ReadBoxProfile(ref Utf8JsonReader reader)
|
||||
{
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("width", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
float width = reader.GetSingle();
|
||||
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("height", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
float height = reader.GetSingle();
|
||||
|
||||
return Profile.Box(width, height);
|
||||
}
|
||||
|
||||
private static Profile ReadBoxFillProfile(ref Utf8JsonReader reader)
|
||||
{
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("width", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
float width = reader.GetSingle();
|
||||
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("height", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
float height = reader.GetSingle();
|
||||
|
||||
return Profile.BoxFill(width, height);
|
||||
}
|
||||
|
||||
private static Profile ReadBoxUniformProfile(ref Utf8JsonReader reader)
|
||||
{
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("width", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
float width = reader.GetSingle();
|
||||
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("height", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
float height = reader.GetSingle();
|
||||
|
||||
return Profile.BoxUniform(width, height);
|
||||
}
|
||||
|
||||
private static Profile ReadCircleProfile(ref Utf8JsonReader reader)
|
||||
{
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("radius", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
float radius = reader.GetSingle();
|
||||
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("radiate", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
int radiate = reader.GetInt32();
|
||||
|
||||
return Profile.Circle(radius, (Profile.CircleRadiation)radiate);
|
||||
|
||||
}
|
||||
|
||||
private static Profile ReadSprayProfile(ref Utf8JsonReader reader)
|
||||
{
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("direction", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
string[] split = reader.GetString().Split(" ", StringSplitOptions.RemoveEmptyEntries);
|
||||
Debug.Assert(split.Length == 2);
|
||||
Vector2 direction = new Vector2(float.Parse(split[0]), float.Parse(split[1]));
|
||||
|
||||
reader.Read();
|
||||
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
|
||||
Debug.Assert(reader.GetString().Equals("spread", StringComparison.InvariantCultureIgnoreCase));
|
||||
reader.Read();
|
||||
float spread = reader.GetSingle();
|
||||
|
||||
return Profile.Spray(direction, spread);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, Profile value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
var type = value.GetType().ToString();
|
||||
switch (type)
|
||||
{
|
||||
case nameof(PointProfile):
|
||||
WritePointProfile(ref writer, (PointProfile)value);
|
||||
break;
|
||||
|
||||
case nameof(LineProfile):
|
||||
WriteLineProfile(ref writer, (LineProfile)value);
|
||||
break;
|
||||
|
||||
case nameof(RingProfile):
|
||||
WriteRingProfile(ref writer, (RingProfile)value);
|
||||
break;
|
||||
|
||||
case nameof(BoxProfile):
|
||||
WriteBoxProfile(ref writer, (BoxProfile)value);
|
||||
break;
|
||||
|
||||
case nameof(BoxFillProfile):
|
||||
WriteBoxFillProfile(ref writer, (BoxFillProfile)value);
|
||||
break;
|
||||
|
||||
case nameof(BoxUniformProfile):
|
||||
WriteBoxUniformProfile(ref writer, (BoxUniformProfile)value);
|
||||
break;
|
||||
|
||||
case nameof(CircleProfile):
|
||||
WriteCircleProfile(ref writer, (CircleProfile)value);
|
||||
break;
|
||||
|
||||
case nameof(SprayProfile):
|
||||
WriteSprayProfile(ref writer, (SprayProfile)value);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Unknown profile type");
|
||||
}
|
||||
}
|
||||
|
||||
private static void WritePointProfile(ref Utf8JsonWriter writer, PointProfile value)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("type");
|
||||
writer.WriteStringValue(value.GetType().ToString());
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
private static void WriteLineProfile(ref Utf8JsonWriter writer, LineProfile value)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WriteString("type", value.GetType().ToString());
|
||||
writer.WriteString("axis", $"{value.Axis.X} {value.Axis.Y}");
|
||||
writer.WriteNumber("length", value.Length);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
private static void WriteRingProfile(ref Utf8JsonWriter writer, RingProfile value)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WriteString("type", value.GetType().ToString());
|
||||
writer.WriteNumber("radius", value.Radius);
|
||||
writer.WriteNumber("radiate", (int)value.Radiate);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
private static void WriteBoxProfile(ref Utf8JsonWriter writer, BoxProfile value)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WriteString("type", value.GetType().ToString());
|
||||
writer.WriteNumber("width", value.Width);
|
||||
writer.WriteNumber("height", value.Height);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
private static void WriteBoxFillProfile(ref Utf8JsonWriter writer, BoxFillProfile value)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WriteString("type", value.GetType().ToString());
|
||||
writer.WriteNumber("width", value.Width);
|
||||
writer.WriteNumber("height", value.Height);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
private static void WriteBoxUniformProfile(ref Utf8JsonWriter writer, BoxUniformProfile value)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WriteString("type", value.GetType().ToString());
|
||||
writer.WriteNumber("width", value.Width);
|
||||
writer.WriteNumber("height", value.Height);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
private static void WriteCircleProfile(ref Utf8JsonWriter writer, CircleProfile value)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WriteString("type", value.GetType().ToString());
|
||||
writer.WriteNumber("radius", value.Radius);
|
||||
writer.WriteNumber("radiate", (int)value.Radiate);
|
||||
writer.WriteEndObject();
|
||||
|
||||
}
|
||||
|
||||
private static void WriteSprayProfile(ref Utf8JsonWriter writer, SprayProfile value)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WriteString("type", value.GetType().ToString());
|
||||
writer.WriteString("direction", $"{value.Direction.X} {value.Direction.Y}");
|
||||
writer.WriteNumber("spread", value.Spread);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public class RangeJsonConverter<T> : JsonConverter<Range<T>> where T : IComparab
|
||||
/// <inheritdoc />
|
||||
public override Range<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
Span<T> values = reader.ReadAsMultiDimensional<T>();
|
||||
Span<T> values = reader.ReadAsMultiDimensional<T>(options);
|
||||
|
||||
if (values.Length == 2)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ public class RectangleFJsonConverter : JsonConverter<RectangleF>
|
||||
/// <inheritdoc />
|
||||
public override RectangleF Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var values = reader.ReadAsMultiDimensional<float>();
|
||||
var values = reader.ReadAsMultiDimensional<float>(options);
|
||||
return new RectangleF(values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ public class Size2JsonConverter : JsonConverter<SizeF>
|
||||
/// </exception>
|
||||
public override SizeF Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var values = reader.ReadAsMultiDimensional<float>();
|
||||
var values = reader.ReadAsMultiDimensional<float>(options);
|
||||
|
||||
if (values.Length == 2)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ public class SizeJsonConverter : JsonConverter<Size>
|
||||
/// </exception>
|
||||
public override Size Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var values = reader.ReadAsMultiDimensional<int>();
|
||||
var values = reader.ReadAsMultiDimensional<int>(options);
|
||||
|
||||
if (values.Length == 2)
|
||||
{
|
||||
|
||||
@@ -20,9 +20,14 @@ namespace MonoGame.Extended.Serialization.Json
|
||||
|
||||
public Texture2DRegion GetTextureRegion(string name)
|
||||
{
|
||||
return TextureAtlases
|
||||
.Select(textureAtlas => textureAtlas.GetRegion(name))
|
||||
.FirstOrDefault(region => region != null);
|
||||
foreach (Texture2DAtlas atlas in TextureAtlases)
|
||||
{
|
||||
if (atlas.TryGetRegion(name, out Texture2DRegion region))
|
||||
{
|
||||
return region;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public class ThicknessJsonConverter : JsonConverter<Thickness>
|
||||
/// <inheritdoc />
|
||||
public override Thickness Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var values = reader.ReadAsMultiDimensional<int>();
|
||||
var values = reader.ReadAsMultiDimensional<int>(options);
|
||||
return Thickness.FromValues(values);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,36 +22,37 @@ public static class Utf8JsonReaderExtensions
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the array elements.</typeparam>
|
||||
/// <param name="reader">The <see cref="Utf8JsonReader"/> to read from.</param>
|
||||
/// <param name="options">An object that specifies serialization options to use.</param>
|
||||
/// <returns>An array of the specified type.</returns>
|
||||
/// <exception cref="NotSupportedException">Thrown when the token type is not supported.</exception>
|
||||
public static T[] ReadAsMultiDimensional<T>(this ref Utf8JsonReader reader)
|
||||
public static T[] ReadAsMultiDimensional<T>(this ref Utf8JsonReader reader, JsonSerializerOptions options)
|
||||
{
|
||||
var tokenType = reader.TokenType;
|
||||
|
||||
switch (tokenType)
|
||||
{
|
||||
case JsonTokenType.StartArray:
|
||||
return reader.ReadAsJArray<T>();
|
||||
return reader.ReadAsJArray<T>(options);
|
||||
|
||||
case JsonTokenType.String:
|
||||
return reader.ReadAsDelimitedString<T>();
|
||||
|
||||
case JsonTokenType.Number:
|
||||
return reader.ReadAsSingleValue<T>();
|
||||
return reader.ReadAsSingleValue<T>(options);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"{tokenType} is not currently supported in the multi-dimensional parser");
|
||||
}
|
||||
}
|
||||
|
||||
private static T[] ReadAsSingleValue<T>(this ref Utf8JsonReader reader)
|
||||
private static T[] ReadAsSingleValue<T>(this ref Utf8JsonReader reader, JsonSerializerOptions options)
|
||||
{
|
||||
var token = JsonDocument.ParseValue(ref reader).RootElement;
|
||||
var value = JsonSerializer.Deserialize<T>(token.GetRawText());
|
||||
var value = JsonSerializer.Deserialize<T>(token.GetRawText(), options);
|
||||
return new T[] { value };
|
||||
}
|
||||
|
||||
private static T[] ReadAsJArray<T>(this ref Utf8JsonReader reader)
|
||||
private static T[] ReadAsJArray<T>(this ref Utf8JsonReader reader, JsonSerializerOptions options)
|
||||
{
|
||||
var items = new List<T>();
|
||||
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
|
||||
@@ -61,7 +62,7 @@ public static class Utf8JsonReaderExtensions
|
||||
break;
|
||||
}
|
||||
|
||||
items.Add(JsonSerializer.Deserialize<T>(ref reader));
|
||||
items.Add(JsonSerializer.Deserialize<T>(ref reader, options));
|
||||
}
|
||||
|
||||
return items.ToArray();
|
||||
|
||||
@@ -19,7 +19,7 @@ public class Vector2JsonConverter : JsonConverter<Vector2>
|
||||
/// </exception>
|
||||
public override Vector2 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var values = reader.ReadAsMultiDimensional<float>();
|
||||
var values = reader.ReadAsMultiDimensional<float>(options);
|
||||
|
||||
if (values.Length == 2)
|
||||
{
|
||||
@@ -31,7 +31,7 @@ public class Vector2JsonConverter : JsonConverter<Vector2>
|
||||
return new Vector2(values[0]);
|
||||
}
|
||||
|
||||
throw new JsonException("Invalid Size2 property value");
|
||||
throw new JsonException("Invalid Vector2 property value");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
Reference in New Issue
Block a user