mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-15 15:09:29 +00:00
Replace Newtonsoft.Json with System.Text.Json (#869)
* Converted to use `System.Text.Json` * Remove Newtonsoft.Json Dependency Newtonsoft.Json dependency has been removed in favor of System.Text.Json * Treat MGFXO file as binary
This commit is contained in:
committed by
GitHub
parent
ee0883ebb4
commit
d008b1bd41
+7
-3
@@ -30,10 +30,8 @@
|
||||
*.sln text eol=crlf merge=union
|
||||
|
||||
################################################################################
|
||||
### imageln file behavior
|
||||
### image file behavior
|
||||
### - Treat as binary
|
||||
### - Normalize to Windows-style line endings
|
||||
### - Use a union merge when resolving conflicts
|
||||
################################################################################
|
||||
*.bmp binary
|
||||
*.gif binary
|
||||
@@ -42,3 +40,9 @@
|
||||
*.jpeg binary
|
||||
*.png binary
|
||||
*.webp binary
|
||||
|
||||
################################################################################
|
||||
### MGFXO file behavior
|
||||
### - Treat as binary
|
||||
################################################################################
|
||||
*.mgfxo binary
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Content.Pipeline.Animations
|
||||
{
|
||||
@@ -10,15 +10,9 @@ namespace MonoGame.Extended.Content.Pipeline.Animations
|
||||
{
|
||||
public override ContentImporterResult<AstridAnimatorFile> Import(string filename, ContentImporterContext context)
|
||||
{
|
||||
using (var streamReader = new StreamReader(filename))
|
||||
{
|
||||
using (var jsonReader = new JsonTextReader(streamReader))
|
||||
{
|
||||
var serializer = new JsonSerializer();
|
||||
var data = serializer.Deserialize<AstridAnimatorFile>(jsonReader);
|
||||
return new ContentImporterResult<AstridAnimatorFile>(filename, data);
|
||||
}
|
||||
}
|
||||
var json = File.ReadAllText(filename);
|
||||
var data = JsonSerializer.Deserialize<AstridAnimatorFile>(json);
|
||||
return new ContentImporterResult<AstridAnimatorFile>(filename, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
<PackageReference Include="MonoGame.Framework.Content.Pipeline"
|
||||
Version="3.8.1.303"
|
||||
PrivateAssets="All" />
|
||||
|
||||
<PackageReference Include="Newtonsoft.Json"
|
||||
Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -25,10 +22,4 @@
|
||||
<ProjectReference Include="..\MonoGame.Extended\MonoGame.Extended.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Newtonsoft.Json.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Binary file not shown.
+5
-10
@@ -1,7 +1,8 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace MonoGame.Extended.Content.Pipeline.TextureAtlases
|
||||
{
|
||||
@@ -10,14 +11,8 @@ namespace MonoGame.Extended.Content.Pipeline.TextureAtlases
|
||||
{
|
||||
public override TexturePackerFile Import(string filename, ContentImporterContext context)
|
||||
{
|
||||
using (var streamReader = new StreamReader(filename))
|
||||
{
|
||||
using (var jsonReader = new JsonTextReader(streamReader))
|
||||
{
|
||||
var serializer = new JsonSerializer();
|
||||
return serializer.Deserialize<TexturePackerFile>(jsonReader);
|
||||
}
|
||||
}
|
||||
var json = File.ReadAllText(filename);
|
||||
return JsonSerializer.Deserialize<TexturePackerFile>(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.BitmapFonts;
|
||||
using MonoGame.Extended.Input.InputListeners;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Controls
|
||||
{
|
||||
@@ -98,7 +98,7 @@ namespace MonoGame.Extended.Gui.Controls
|
||||
public VerticalAlignment VerticalAlignment { get; set; } = VerticalAlignment.Stretch;
|
||||
public HorizontalAlignment HorizontalTextAlignment { get; set; } = HorizontalAlignment.Centre;
|
||||
public VerticalAlignment VerticalTextAlignment { get; set; } = VerticalAlignment.Centre;
|
||||
|
||||
|
||||
public abstract Size GetContentSize(IGuiContext context);
|
||||
|
||||
public virtual Size CalculateActualSize(IGuiContext context)
|
||||
@@ -177,7 +177,7 @@ namespace MonoGame.Extended.Gui.Controls
|
||||
public virtual bool OnPointerDown(IGuiContext context, PointerEventArgs args) { return true; }
|
||||
public virtual bool OnPointerMove(IGuiContext context, PointerEventArgs args) { return true; }
|
||||
public virtual bool OnPointerUp(IGuiContext context, PointerEventArgs args) { return true; }
|
||||
|
||||
|
||||
public virtual bool OnPointerEnter(IGuiContext context, PointerEventArgs args)
|
||||
{
|
||||
if (IsEnabled && !IsHovered)
|
||||
@@ -220,7 +220,7 @@ namespace MonoGame.Extended.Gui.Controls
|
||||
{
|
||||
return Parent != null && (Parent == control || Parent.HasParent(control));
|
||||
}
|
||||
|
||||
|
||||
protected TextInfo GetTextInfo(IGuiContext context, string text, Rectangle targetRectangle, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment)
|
||||
{
|
||||
var font = Font ?? context.DefaultFont;
|
||||
@@ -230,7 +230,7 @@ namespace MonoGame.Extended.Gui.Controls
|
||||
var textInfo = new TextInfo(text, font, textPosition, textSize, TextColor, targetRectangle);
|
||||
return textInfo;
|
||||
}
|
||||
|
||||
|
||||
public struct TextInfo
|
||||
{
|
||||
public TextInfo(string text, BitmapFont font, Vector2 position, Size size, Color color, Rectangle? clippingRectangle)
|
||||
@@ -268,4 +268,4 @@ namespace MonoGame.Extended.Gui.Controls
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui
|
||||
{
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using MonoGame.Extended.Gui.Controls;
|
||||
using MonoGame.Extended.Gui.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui
|
||||
{
|
||||
@@ -21,7 +22,7 @@ namespace MonoGame.Extended.Gui
|
||||
}
|
||||
|
||||
private Control _content;
|
||||
[JsonProperty(Order = 1)]
|
||||
[JsonPropertyOrder(1)]
|
||||
public Control Content
|
||||
{
|
||||
get { return _content; }
|
||||
@@ -49,7 +50,7 @@ namespace MonoGame.Extended.Gui
|
||||
|
||||
public virtual void Update(GameTime gameTime)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Show()
|
||||
@@ -113,21 +114,10 @@ namespace MonoGame.Extended.Gui
|
||||
where TScreen : Screen
|
||||
{
|
||||
var skinService = new SkinService();
|
||||
var serializer = new GuiJsonSerializer(contentManager, customControlTypes)
|
||||
{
|
||||
Converters =
|
||||
{
|
||||
new SkinJsonConverter(contentManager, skinService, customControlTypes),
|
||||
new ControlJsonConverter(skinService, customControlTypes)
|
||||
}
|
||||
};
|
||||
|
||||
using (var streamReader = new StreamReader(stream))
|
||||
using (var jsonReader = new JsonTextReader(streamReader))
|
||||
{
|
||||
var screen = serializer.Deserialize<TScreen>(jsonReader);
|
||||
return screen;
|
||||
}
|
||||
var options = GuiJsonSerializerOptionsProvider.GetOptions(contentManager, customControlTypes);
|
||||
options.Converters.Add(new SkinJsonConverter(contentManager, skinService, customControlTypes));
|
||||
options.Converters.Add(new ControlJsonConverter(skinService, customControlTypes));
|
||||
return JsonSerializer.Deserialize<TScreen>(stream, options);
|
||||
}
|
||||
|
||||
public static Screen FromFile(ContentManager contentManager, string path, params Type[] customControlTypes)
|
||||
@@ -147,4 +137,4 @@ namespace MonoGame.Extended.Gui
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization
|
||||
{
|
||||
public class AlignmentConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (objectType == typeof(HorizontalAlignment))
|
||||
{
|
||||
var value = reader.Value.ToString();
|
||||
|
||||
if (value == "Center" || string.Equals(value, "Centre", StringComparison.OrdinalIgnoreCase))
|
||||
return HorizontalAlignment.Centre;
|
||||
|
||||
HorizontalAlignment alignment;
|
||||
|
||||
if (Enum.TryParse(value, true, out alignment))
|
||||
return alignment;
|
||||
}
|
||||
|
||||
if (objectType == typeof(VerticalAlignment))
|
||||
{
|
||||
var value = reader.Value.ToString();
|
||||
|
||||
if (value == "Center" || string.Equals(value, "Centre", StringComparison.OrdinalIgnoreCase))
|
||||
return VerticalAlignment.Centre;
|
||||
|
||||
VerticalAlignment alignment;
|
||||
|
||||
if (Enum.TryParse(value, true, out alignment))
|
||||
return alignment;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Invalid value for '{objectType.Name}'");
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(HorizontalAlignment) || objectType == typeof(VerticalAlignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using MonoGame.Extended.Gui.Controls;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization
|
||||
{
|
||||
public class ControlJsonConverter : JsonConverter
|
||||
public class ControlJsonConverter : JsonConverter<Control>
|
||||
{
|
||||
private readonly IGuiSkinService _guiSkinService;
|
||||
private readonly ControlStyleJsonConverter _styleConverter;
|
||||
@@ -16,13 +17,13 @@ namespace MonoGame.Extended.Gui.Serialization
|
||||
_styleConverter = new ControlStyleJsonConverter(customControlTypes);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Control);
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
/// <inheritdoc />
|
||||
public override Control Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var style = (ControlStyle) _styleConverter.ReadJson(reader, objectType, existingValue, serializer);
|
||||
var style = _styleConverter.Read(ref reader, typeToConvert, options);
|
||||
var template = GetControlTemplate(style);
|
||||
var skin = _guiSkinService.Skin;
|
||||
var control = skin.Create(style.TargetType, template);
|
||||
@@ -48,10 +49,10 @@ namespace MonoGame.Extended.Gui.Serialization
|
||||
return control;
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(Control);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, Control value, JsonSerializerOptions options) { }
|
||||
|
||||
|
||||
|
||||
private static string GetControlTemplate(ControlStyle style)
|
||||
{
|
||||
@@ -63,4 +64,4 @@ namespace MonoGame.Extended.Gui.Serialization
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using MonoGame.Extended.Collections;
|
||||
using MonoGame.Extended.Gui.Controls;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization
|
||||
{
|
||||
public class ControlStyleJsonConverter : JsonConverter
|
||||
public class ControlStyleJsonConverter : JsonConverter<ControlStyle>
|
||||
{
|
||||
private readonly Dictionary<string, Type> _controlTypes;
|
||||
private const string _typeProperty = "Type";
|
||||
@@ -26,27 +27,20 @@ namespace MonoGame.Extended.Gui.Serialization
|
||||
.ToDictionary(t => t.Name);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(ControlStyle);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ControlStyle Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var style = (ControlStyle)value;
|
||||
var dictionary = new Dictionary<string, object> { [_typeProperty] = style.TargetType.Name };
|
||||
|
||||
foreach (var keyValuePair in style)
|
||||
dictionary.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
|
||||
serializer.Serialize(writer, dictionary);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var dictionary = serializer.Deserialize<Dictionary<string, object>>(reader);
|
||||
var dictionary = JsonSerializer.Deserialize<Dictionary<string, object>>(ref reader, options);
|
||||
var name = dictionary.GetValueOrDefault(_nameProperty) as string;
|
||||
var typeName = dictionary.GetValueOrDefault(_typeProperty) as string;
|
||||
|
||||
if (!_controlTypes.ContainsKey(typeName))
|
||||
if (!_controlTypes.TryGetValue(typeName, out Type controlType))
|
||||
throw new FormatException("invalid control type: " + typeName);
|
||||
|
||||
var targetType = typeName != null ? _controlTypes[typeName] : typeof(Control);
|
||||
var targetType = typeName != null ? controlType : typeof(Control);
|
||||
var properties = targetType
|
||||
.GetRuntimeProperties()
|
||||
.ToDictionary(p => p.Name);
|
||||
@@ -59,8 +53,8 @@ namespace MonoGame.Extended.Gui.Serialization
|
||||
|
||||
PropertyInfo propertyInfo;
|
||||
var value = properties.TryGetValue(propertyName, out propertyInfo)
|
||||
? DeserializeValueAs(serializer, rawValue, propertyInfo.PropertyType)
|
||||
: DeserializeValueAs(serializer, rawValue, typeof(object));
|
||||
? DeserializeValueAs(rawValue, propertyInfo.PropertyType)
|
||||
: DeserializeValueAs(rawValue, typeof(object));
|
||||
|
||||
style.Add(propertyName, value);
|
||||
}
|
||||
@@ -68,20 +62,28 @@ namespace MonoGame.Extended.Gui.Serialization
|
||||
return style;
|
||||
}
|
||||
|
||||
private static object DeserializeValueAs(JsonSerializer serializer, object value, Type type)
|
||||
private static object DeserializeValueAs(object value, Type type)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(value);
|
||||
|
||||
using (var textReader = new StringReader(json))
|
||||
using (var jsonReader = new JsonTextReader(textReader))
|
||||
{
|
||||
return serializer.Deserialize(jsonReader, type);
|
||||
}
|
||||
var json = JsonSerializer.Serialize(value, type);
|
||||
return JsonSerializer.Deserialize(json, type);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, ControlStyle value, JsonSerializerOptions options)
|
||||
{
|
||||
return objectType == typeof(ControlStyle);
|
||||
var style = (ControlStyle)value;
|
||||
var dictionary = new Dictionary<string, object> { [_typeProperty] = style.TargetType.Name };
|
||||
|
||||
foreach (var keyValuePair in style)
|
||||
dictionary.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
|
||||
JsonSerializer.Serialize(writer, dictionary);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using MonoGame.Extended.BitmapFonts;
|
||||
using MonoGame.Extended.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization
|
||||
{
|
||||
public sealed class GuiJsonSerializer : JsonSerializer
|
||||
{
|
||||
public GuiJsonSerializer(ContentManager contentManager, params Type[] customControlTypes)
|
||||
{
|
||||
var textureRegionService = new GuiTextureRegionService();
|
||||
Converters.Add(new Vector2JsonConverter());
|
||||
Converters.Add(new SizeJsonConverter());
|
||||
Converters.Add(new Size2JsonConverter());
|
||||
Converters.Add(new ColorJsonConverter());
|
||||
Converters.Add(new ThicknessJsonConverter());
|
||||
Converters.Add(new ContentManagerJsonConverter<BitmapFont>(contentManager, font => font.Name));
|
||||
Converters.Add(new ControlStyleJsonConverter(customControlTypes));
|
||||
Converters.Add(new GuiTextureAtlasJsonConverter(contentManager, textureRegionService));
|
||||
Converters.Add(new GuiNinePatchRegion2DJsonConverter(textureRegionService));
|
||||
Converters.Add(new TextureRegion2DJsonConverter(textureRegionService));
|
||||
Converters.Add(new AlignmentConverter());
|
||||
ContractResolver = new ShortNameJsonContractResolver();
|
||||
Formatting = Formatting.Indented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using MonoGame.Extended.BitmapFonts;
|
||||
using MonoGame.Extended.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization;
|
||||
|
||||
public static class GuiJsonSerializerOptionsProvider
|
||||
{
|
||||
public static JsonSerializerOptions GetOptions(ContentManager contentManager, params Type[] customControlTypes)
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
var textureRegionService = new GuiTextureRegionService();
|
||||
|
||||
options.Converters.Add(new Vector2JsonConverter());
|
||||
options.Converters.Add(new SizeJsonConverter());
|
||||
options.Converters.Add(new Size2JsonConverter());
|
||||
options.Converters.Add(new ColorJsonConverter());
|
||||
options.Converters.Add(new ThicknessJsonConverter());
|
||||
options.Converters.Add(new ContentManagerJsonConverter<BitmapFont>(contentManager, font => font.Name));
|
||||
options.Converters.Add(new ControlStyleJsonConverter(customControlTypes));
|
||||
options.Converters.Add(new GuiTextureAtlasJsonConverter(contentManager, textureRegionService));
|
||||
options.Converters.Add(new GuiNinePatchRegion2DJsonConverter(textureRegionService));
|
||||
options.Converters.Add(new TextureRegion2DJsonConverter(textureRegionService));
|
||||
options.Converters.Add(new VerticalAlignmentConverter());
|
||||
options.Converters.Add(new HorizontalAlignmentConverter());
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using MonoGame.Extended.Serialization;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization
|
||||
{
|
||||
@@ -14,15 +11,5 @@ namespace MonoGame.Extended.Gui.Serialization
|
||||
{
|
||||
_textureRegionService = textureRegionService;
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var ninePatch = base.ReadJson(reader, objectType, existingValue, serializer) as NinePatchRegion2D;
|
||||
|
||||
if(ninePatch != null)
|
||||
_textureRegionService.NinePatches.Add(ninePatch);
|
||||
|
||||
return ninePatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using MonoGame.Extended.Serialization;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization
|
||||
{
|
||||
@@ -16,14 +16,16 @@ namespace MonoGame.Extended.Gui.Serialization
|
||||
_textureRegionService = textureRegionService;
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
/// <inheritdoc />
|
||||
public override TextureAtlas Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var textureAtlas = base.ReadJson(reader, objectType, existingValue, serializer) as TextureAtlas;
|
||||
|
||||
if (textureAtlas != null)
|
||||
var textureAtlas = base.Read(ref reader, typeToConvert, options);
|
||||
if (textureAtlas is not null)
|
||||
{
|
||||
_textureRegionService.TextureAtlases.Add(textureAtlas);
|
||||
}
|
||||
|
||||
return textureAtlas;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization;
|
||||
|
||||
public class HorizontalAlignmentConverter : JsonConverter<HorizontalAlignment>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(HorizontalAlignment);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override HorizontalAlignment Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var value = reader.GetString();
|
||||
|
||||
if (value.Equals("Center", StringComparison.OrdinalIgnoreCase) || value.Equals("Centre", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return HorizontalAlignment.Centre;
|
||||
}
|
||||
|
||||
if (Enum.TryParse<HorizontalAlignment>(value, true, out var alignment))
|
||||
{
|
||||
return alignment;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Invalid value for '{nameof(HorizontalAlignment)}'");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, HorizontalAlignment value, JsonSerializerOptions options) { }
|
||||
}
|
||||
@@ -1,58 +1,57 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization
|
||||
namespace MonoGame.Extended.Gui.Serialization;
|
||||
|
||||
public interface IGuiSkinService
|
||||
{
|
||||
public interface IGuiSkinService
|
||||
Skin Skin { get; set; }
|
||||
}
|
||||
|
||||
public class SkinService : IGuiSkinService
|
||||
{
|
||||
public Skin Skin { get; set; }
|
||||
}
|
||||
|
||||
public class SkinJsonConverter : JsonConverter<Skin>
|
||||
{
|
||||
private readonly ContentManager _contentManager;
|
||||
private readonly IGuiSkinService _skinService;
|
||||
private readonly Type[] _customControlTypes;
|
||||
|
||||
public SkinJsonConverter(ContentManager contentManager, IGuiSkinService skinService, params Type[] customControlTypes)
|
||||
{
|
||||
Skin Skin { get; set; }
|
||||
_contentManager = contentManager;
|
||||
_skinService = skinService;
|
||||
_customControlTypes = customControlTypes;
|
||||
}
|
||||
|
||||
public class SkinService : IGuiSkinService
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Skin);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Skin Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
public Skin Skin { get; set; }
|
||||
}
|
||||
|
||||
public class SkinJsonConverter : JsonConverter
|
||||
{
|
||||
private readonly ContentManager _contentManager;
|
||||
private readonly IGuiSkinService _skinService;
|
||||
private readonly Type[] _customControlTypes;
|
||||
|
||||
public SkinJsonConverter(ContentManager contentManager, IGuiSkinService skinService, params Type[] customControlTypes)
|
||||
if (reader.TokenType == JsonTokenType.String)
|
||||
{
|
||||
_contentManager = contentManager;
|
||||
_skinService = skinService;
|
||||
_customControlTypes = customControlTypes;
|
||||
}
|
||||
var assetName = reader.GetString();
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.ValueType == typeof(string))
|
||||
// TODO: Load this using the ContentManager instead.
|
||||
using (var stream = TitleContainer.OpenStream(assetName))
|
||||
{
|
||||
var assetName = (string) reader.Value;
|
||||
|
||||
// TODO: Load this using the ContentManager instead.
|
||||
using (var stream = TitleContainer.OpenStream(assetName))
|
||||
{
|
||||
var skin = Skin.FromStream(_contentManager, stream, _customControlTypes);
|
||||
_skinService.Skin = skin;
|
||||
return skin;
|
||||
}
|
||||
var skin = Skin.FromStream(_contentManager, stream, _customControlTypes);
|
||||
_skinService.Skin = skin;
|
||||
return skin;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"{nameof(SkinJsonConverter)} can only convert from a string");
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(Skin);
|
||||
}
|
||||
throw new InvalidOperationException($"{nameof(SkinJsonConverter)} can only convert from a string");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, Skin value, JsonSerializerOptions options) { }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization;
|
||||
|
||||
public class VerticalAlignmentConverter : JsonConverter<VerticalAlignment>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(VerticalAlignment);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override VerticalAlignment Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var value = reader.GetString();
|
||||
|
||||
if (value.Equals("Center", StringComparison.OrdinalIgnoreCase) || value.Equals("Centre", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return VerticalAlignment.Centre;
|
||||
}
|
||||
|
||||
if (Enum.TryParse<VerticalAlignment>(value, true, out var alignment))
|
||||
{
|
||||
return alignment;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Invalid value for '{nameof(VerticalAlignment)}'");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, VerticalAlignment value, JsonSerializerOptions options) { }
|
||||
}
|
||||
@@ -10,7 +10,8 @@ using MonoGame.Extended.Collections;
|
||||
using MonoGame.Extended.Gui.Controls;
|
||||
using MonoGame.Extended.Gui.Serialization;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui
|
||||
{
|
||||
@@ -24,25 +25,25 @@ namespace MonoGame.Extended.Gui
|
||||
Styles = new KeyedCollection<string, ControlStyle>(s => s.Name ?? s.TargetType.Name);
|
||||
}
|
||||
|
||||
[JsonProperty(Order = 0)]
|
||||
[JsonPropertyOrder(0)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty(Order = 1)]
|
||||
[JsonPropertyOrder(1)]
|
||||
public IList<TextureAtlas> TextureAtlases { get; set; }
|
||||
|
||||
[JsonProperty(Order = 2)]
|
||||
[JsonPropertyOrder(2)]
|
||||
public IList<BitmapFont> Fonts { get; set; }
|
||||
|
||||
[JsonProperty(Order = 3)]
|
||||
[JsonPropertyOrder(3)]
|
||||
public IList<NinePatchRegion2D> NinePatches { get; set; }
|
||||
|
||||
[JsonProperty(Order = 4)]
|
||||
[JsonPropertyOrder(4)]
|
||||
public BitmapFont DefaultFont => Fonts.FirstOrDefault();
|
||||
|
||||
[JsonProperty(Order = 5)]
|
||||
[JsonPropertyOrder(5)]
|
||||
public Cursor Cursor { get; set; }
|
||||
|
||||
[JsonProperty(Order = 6)]
|
||||
[JsonPropertyOrder(6)]
|
||||
public KeyedCollection<string, ControlStyle> Styles { get; private set; }
|
||||
|
||||
public ControlStyle GetStyle(string name)
|
||||
@@ -87,13 +88,8 @@ namespace MonoGame.Extended.Gui
|
||||
|
||||
public static Skin FromStream(ContentManager contentManager, Stream stream, params Type[] customControlTypes)
|
||||
{
|
||||
var skinSerializer = new GuiJsonSerializer(contentManager, customControlTypes);
|
||||
|
||||
using (var streamReader = new StreamReader(stream))
|
||||
using (var jsonReader = new JsonTextReader(streamReader))
|
||||
{
|
||||
return skinSerializer.Deserialize<Skin>(jsonReader);
|
||||
}
|
||||
var options = GuiJsonSerializerOptionsProvider.GetOptions(contentManager, customControlTypes);
|
||||
return JsonSerializer.Deserialize<Skin>(stream, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +135,7 @@ namespace MonoGame.Extended.Gui
|
||||
{nameof(Control.Padding), new Thickness(5)},
|
||||
{nameof(Control.DisabledStyle), new ControlStyle(typeof(Control)) {
|
||||
{ nameof(Control.TextColor), new Color(78,78,80) }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new ControlStyle(typeof(LayoutControl)) {
|
||||
@@ -222,4 +218,4 @@ namespace MonoGame.Extended.Gui
|
||||
return Default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.Particles.Serialization;
|
||||
using MonoGame.Extended.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Particles
|
||||
{
|
||||
@@ -48,13 +48,8 @@ namespace MonoGame.Extended.Particles
|
||||
|
||||
public static ParticleEffect FromStream(ITextureRegionService textureRegionService, Stream stream)
|
||||
{
|
||||
var serializer = new ParticleJsonSerializer(textureRegionService);
|
||||
|
||||
using (var streamReader = new StreamReader(stream))
|
||||
using (var jsonReader = new JsonTextReader(streamReader))
|
||||
{
|
||||
return serializer.Deserialize<ParticleEffect>(jsonReader);
|
||||
}
|
||||
var options = ParticleJsonSerializerOptionsProvider.GetOptions(textureRegionService);
|
||||
return JsonSerializer.Deserialize<ParticleEffect>(stream, options);
|
||||
}
|
||||
|
||||
public void Update(float elapsedSeconds)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.Particles.Modifiers;
|
||||
using MonoGame.Extended.Particles.Profiles;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Particles
|
||||
{
|
||||
@@ -42,7 +42,7 @@ namespace MonoGame.Extended.Particles
|
||||
Buffer.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
~ParticleEmitter()
|
||||
{
|
||||
Dispose();
|
||||
@@ -197,7 +197,7 @@ namespace MonoGame.Extended.Particles
|
||||
_random.NextColor(out particle->Color, Parameters.Color);
|
||||
|
||||
particle->Opacity = _random.NextSingle(Parameters.Opacity);
|
||||
|
||||
|
||||
if(Parameters.MaintainAspectRatioOnScale)
|
||||
{
|
||||
var scale = _random.NextSingle(Parameters.Scale);
|
||||
@@ -207,7 +207,7 @@ namespace MonoGame.Extended.Particles
|
||||
{
|
||||
particle->Scale = new Vector2(_random.NextSingle(Parameters.ScaleX), _random.NextSingle(Parameters.ScaleY));
|
||||
}
|
||||
|
||||
|
||||
particle->Rotation = _random.NextSingle(Parameters.Rotation);
|
||||
particle->Mass = _random.NextSingle(Parameters.Mass);
|
||||
particle->LayerDepth = layerDepth;
|
||||
|
||||
+28
-21
@@ -1,27 +1,34 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Particles.Serialization
|
||||
namespace MonoGame.Extended.Particles.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="ParticleModifierExecutionStrategy"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class ModifierExecutionStrategyJsonConverter : JsonConverter<ParticleModifierExecutionStrategy>
|
||||
{
|
||||
public class ModifierExecutionStrategyJsonConverter : JsonConverter
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) =>
|
||||
typeToConvert == typeof(ParticleModifierExecutionStrategy) ||
|
||||
typeToConvert.GetTypeInfo().BaseType == typeof(ParticleModifierExecutionStrategy);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ParticleModifierExecutionStrategy Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue(value.ToString());
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var value = JToken.Load(reader).ToObject<string>();
|
||||
return ParticleModifierExecutionStrategy.Parse(value);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(ParticleModifierExecutionStrategy)
|
||||
|| objectType.GetTypeInfo().BaseType == typeof(ParticleModifierExecutionStrategy);
|
||||
}
|
||||
var value = JsonSerializer.Deserialize<string>(ref reader, options);
|
||||
return ParticleModifierExecutionStrategy.Parse(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, ParticleModifierExecutionStrategy value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
writer.WriteStringValue(value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using MonoGame.Extended.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Particles.Serialization
|
||||
{
|
||||
public sealed class ParticleJsonSerializer : JsonSerializer
|
||||
{
|
||||
public ParticleJsonSerializer(ITextureRegionService textureRegionService, NullValueHandling nullValueHandling = NullValueHandling.Include)
|
||||
{
|
||||
Converters.Add(new Vector2JsonConverter());
|
||||
Converters.Add(new Size2JsonConverter());
|
||||
Converters.Add(new ColorJsonConverter());
|
||||
Converters.Add(new TextureRegion2DJsonConverter(textureRegionService));
|
||||
Converters.Add(new ProfileJsonConverter());
|
||||
Converters.Add(new ModifierJsonConverter());
|
||||
Converters.Add(new InterpolatorJsonConverter());
|
||||
Converters.Add(new TimeSpanJsonConverter());
|
||||
Converters.Add(new RangeJsonConverter<int>());
|
||||
Converters.Add(new RangeJsonConverter<float>());
|
||||
Converters.Add(new RangeJsonConverter<HslColor>());
|
||||
Converters.Add(new HslColorJsonConverter());
|
||||
Converters.Add(new ModifierExecutionStrategyJsonConverter());
|
||||
ContractResolver = new ShortNameJsonContractResolver();
|
||||
NullValueHandling = nullValueHandling;
|
||||
Formatting = Formatting.Indented;
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using MonoGame.Extended.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Particles.Serialization;
|
||||
|
||||
public static class ParticleJsonSerializerOptionsProvider
|
||||
{
|
||||
public static JsonSerializerOptions GetOptions(ITextureRegionService textureRegionService)
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
options.Converters.Add(new Vector2JsonConverter());
|
||||
options.Converters.Add(new Size2JsonConverter());
|
||||
options.Converters.Add(new ColorJsonConverter());
|
||||
options.Converters.Add(new TextureRegion2DJsonConverter(textureRegionService));
|
||||
options.Converters.Add(new ProfileJsonConverter());
|
||||
options.Converters.Add(new ModifierJsonConverter());
|
||||
options.Converters.Add(new InterpolatorJsonConverter());
|
||||
options.Converters.Add(new TimeSpanJsonConverter());
|
||||
options.Converters.Add(new RangeJsonConverter<int>());
|
||||
options.Converters.Add(new RangeJsonConverter<float>());
|
||||
options.Converters.Add(new RangeJsonConverter<HslColor>());
|
||||
options.Converters.Add(new HslColorJsonConverter());
|
||||
options.Converters.Add(new ModifierExecutionStrategyJsonConverter());
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,33 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Particles.Serialization
|
||||
namespace MonoGame.Extended.Particles.Serialization;
|
||||
|
||||
public class TimeSpanJsonConverter : JsonConverter<TimeSpan>
|
||||
{
|
||||
public class TimeSpanJsonConverter : JsonConverter
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(TimeSpan);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
if (reader.TokenType == JsonTokenType.Number)
|
||||
{
|
||||
var timeSpan = (TimeSpan) value;
|
||||
writer.WriteValue(timeSpan.TotalSeconds);
|
||||
double seconds = reader.GetDouble();
|
||||
return TimeSpan.FromSeconds(seconds);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.ValueType == typeof(double))
|
||||
{
|
||||
var seconds = (double) reader.Value;
|
||||
return TimeSpan.FromSeconds(seconds);
|
||||
}
|
||||
|
||||
return TimeSpan.Zero;
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(TimeSpan);
|
||||
}
|
||||
return TimeSpan.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
writer.WriteNumberValue(value.TotalSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
<PackageReference Include="MonoGame.Framework.Content.Pipeline"
|
||||
Version="3.8.1.303"
|
||||
PrivateAssets="All" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
{
|
||||
public abstract class BaseTypeJsonConverter<T> : JsonConverter
|
||||
public abstract class BaseTypeJsonConverter<T> : JsonConverter<T>
|
||||
{
|
||||
private readonly string _suffix;
|
||||
private readonly Dictionary<string, Type> _namesToTypes;
|
||||
private readonly Dictionary<Type, string> _typesToNames;
|
||||
private readonly CamelCaseNamingStrategy _namingStrategy = new CamelCaseNamingStrategy();
|
||||
private readonly JsonSerializerOptions _serializerOptions;
|
||||
private readonly JsonNamingPolicy _namingPolicy = JsonNamingPolicy.CamelCase;
|
||||
|
||||
protected BaseTypeJsonConverter(IEnumerable<TypeInfo> supportedTypes, string suffix)
|
||||
{
|
||||
@@ -21,52 +21,60 @@ namespace MonoGame.Extended.Serialization
|
||||
_namesToTypes = supportedTypes
|
||||
.ToDictionary(t => TrimSuffix(t.Name, suffix), t => t.AsType(), StringComparer.OrdinalIgnoreCase);
|
||||
_typesToNames = _namesToTypes.ToDictionary(i => i.Value, i => i.Key);
|
||||
|
||||
_serializerOptions = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = _namingPolicy,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||
};
|
||||
_serializerOptions.Converters.Add(this);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) =>
|
||||
_namesToTypes.ContainsValue(typeToConvert) || typeof(T) == typeToConvert;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="InvalidOperationException" />
|
||||
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
using (JsonDocument doc = JsonDocument.ParseValue(ref reader))
|
||||
{
|
||||
var jObject = doc.RootElement;
|
||||
var key = jObject.GetProperty("type").GetString();
|
||||
|
||||
if (_namesToTypes.TryGetValue(key, out Type type))
|
||||
{
|
||||
var value = JsonSerializer.Deserialize(jObject.GetRawText(), type, options);
|
||||
return (T)value;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unknown {_suffix} type '{key}'");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
|
||||
{
|
||||
var type = value.GetType();
|
||||
var properties = type.GetRuntimeProperties();
|
||||
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("type");
|
||||
writer.WriteValue(_typesToNames[type]);
|
||||
writer.WriteString("type", _typesToNames[type]);
|
||||
|
||||
foreach (var property in properties.Where(p => p.CanWrite)) // TODO: Technically an IList property is writable as well.
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var propertyName = _namingStrategy.GetPropertyName(property.Name, false);
|
||||
var propertyName = _namingPolicy.ConvertName(property.Name);
|
||||
writer.WritePropertyName(propertyName);
|
||||
serializer.Serialize(writer, property.GetValue(value));
|
||||
JsonSerializer.Serialize(writer, property.GetValue(value), property.PropertyType, options);
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var jObject = JObject.Load(reader);
|
||||
var key = jObject.GetValue("type", StringComparison.OrdinalIgnoreCase).ToObject<string>();
|
||||
Type type;
|
||||
|
||||
if (_namesToTypes.TryGetValue(key, out type))
|
||||
{
|
||||
serializer.Converters.Remove(this);
|
||||
var value = jObject.ToObject(type, serializer);
|
||||
serializer.Converters.Add(this);
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unknown {_suffix} type '{key}'");
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
if (_namesToTypes.ContainsValue(objectType))
|
||||
return true;
|
||||
|
||||
return objectType == typeof(T);
|
||||
}
|
||||
|
||||
private static string TrimSuffix(string input, string suffix)
|
||||
{
|
||||
if (input.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
|
||||
@@ -75,4 +83,4 @@ namespace MonoGame.Extended.Serialization
|
||||
return input;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,34 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="Color"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class ColorJsonConverter : JsonConverter<Color>
|
||||
{
|
||||
public class ColorJsonConverter : JsonConverter
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Color);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Color Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue(ColorHelper.ToHex((Color)value));
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(Color);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var value = (string)reader.Value;
|
||||
return value.StartsWith("#") ? ColorHelper.FromHex(value) : ColorHelper.FromName(value);
|
||||
}
|
||||
var value = reader.GetString();
|
||||
return value[0] == '#' ? ColorHelper.FromHex(value) : ColorHelper.FromName(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, Color value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
var hexValue = ColorHelper.ToHex(value);
|
||||
writer.WriteStringValue(hexValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,49 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Loads content from a JSON file into the <see cref="ContentManager"/> using the asset name
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of content to load</typeparam>
|
||||
public class ContentManagerJsonConverter<T> : JsonConverter<T>
|
||||
{
|
||||
private readonly ContentManager _contentManager;
|
||||
private readonly Func<T, string> _getAssetName;
|
||||
|
||||
/// <summary>
|
||||
/// Loads content from a JSON file into the <see cref="ContentManager"/> using the asset name
|
||||
/// Initializes a new instance of the <see cref="ContentManagerJsonConverter{T}"/> class.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of content to load</typeparam>
|
||||
public class ContentManagerJsonConverter<T> : JsonConverter
|
||||
/// <param name="contentManager">The <see cref="ContentManager"/> used to load content.</param>
|
||||
/// <param name="getAssetName">A function that returns the asset name for a given instance of <typeparamref name="T"/>.</param>
|
||||
public ContentManagerJsonConverter(ContentManager contentManager, Func<T, string> getAssetName)
|
||||
{
|
||||
private readonly ContentManager _contentManager;
|
||||
private readonly Func<T, string> _getAssetName;
|
||||
|
||||
public ContentManagerJsonConverter(ContentManager contentManager, Func<T, string> getAssetName)
|
||||
{
|
||||
_contentManager = contentManager;
|
||||
_getAssetName = getAssetName;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var asset = (T)value;
|
||||
var assetName = _getAssetName(asset);
|
||||
writer.WriteValue(assetName);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var assetName = (string)reader.Value;
|
||||
return _contentManager.Load<T>(assetName);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(T);
|
||||
}
|
||||
_contentManager = contentManager;
|
||||
_getAssetName = getAssetName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(T);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var assetName = reader.GetString();
|
||||
return _contentManager.Load<T>(assetName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
var asset = (T)value;
|
||||
var assetName = _getAssetName(asset);
|
||||
writer.WriteStringValue(assetName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
public class FloatStringConverter : JsonConverter<float>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(float) || typeToConvert == typeof(string);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.String)
|
||||
{
|
||||
if (float.TryParse(reader.GetString(), out float value))
|
||||
return value;
|
||||
}
|
||||
else if (reader.TokenType == JsonTokenType.Number)
|
||||
{
|
||||
return reader.GetSingle();
|
||||
}
|
||||
|
||||
throw new JsonException($"Unable to convert value of type {reader.TokenType} to {typeof(float)}");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
writer.WriteNumberValue(value);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,33 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="HslColor"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class HslColorJsonConverter : JsonConverter<HslColor>
|
||||
{
|
||||
public class HslColorJsonConverter : JsonConverter
|
||||
private readonly ColorJsonConverter _colorConverter = new ColorJsonConverter();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(HslColor);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override HslColor Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
private readonly ColorJsonConverter _colorConverter = new ColorJsonConverter();
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var color = ((HslColor) value).ToRgb();
|
||||
_colorConverter.WriteJson(writer, color, serializer);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var color = (Color)_colorConverter.ReadJson(reader, objectType, existingValue, serializer);
|
||||
return HslColor.FromRgb(color);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(HslColor);
|
||||
}
|
||||
var color = _colorConverter.Read(ref reader, typeToConvert, options);
|
||||
return HslColor.FromRgb(color);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, HslColor value, JsonSerializerOptions options)
|
||||
{
|
||||
var color = ((HslColor)value).ToRgb();
|
||||
_colorConverter.Write(writer, color, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using MonoGame.Extended.Content;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
{
|
||||
@@ -9,13 +9,10 @@ namespace MonoGame.Extended.Serialization
|
||||
{
|
||||
public T Load<T>(ContentManager contentManager, string path)
|
||||
{
|
||||
using (var stream = contentManager.OpenStream(path))
|
||||
using (var reader = new StreamReader(stream))
|
||||
using (var jsonReader = new JsonTextReader(reader))
|
||||
{
|
||||
var serializer = new MonoGameJsonSerializer(contentManager, path);
|
||||
return serializer.Deserialize<T>(jsonReader);
|
||||
}
|
||||
|
||||
using var stream = contentManager.OpenStream(path);
|
||||
var monoGameSerializerOptions = MonoGameJsonSerializerOptionsProvider.GetOptions(contentManager, path);
|
||||
return JsonSerializer.Deserialize<T>(stream, monoGameSerializerOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
{
|
||||
@@ -9,13 +10,7 @@ namespace MonoGame.Extended.Serialization
|
||||
protected override T Read(ContentReader reader, T existingInstance)
|
||||
{
|
||||
var json = reader.ReadString();
|
||||
|
||||
using (var stringReader = new StringReader(json))
|
||||
using (var jsonReader = new JsonTextReader(stringReader))
|
||||
{
|
||||
var serializer = new JsonSerializer();
|
||||
return serializer.Deserialize<T>(jsonReader);
|
||||
}
|
||||
return JsonSerializer.Deserialize<T>(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
{
|
||||
public static class JsonReaderExtensions
|
||||
{
|
||||
private static readonly Dictionary<Type, Func<string, object>> _stringParsers = new Dictionary<Type, Func<string, object>>
|
||||
{
|
||||
{typeof(int), s => int.Parse(s, CultureInfo.InvariantCulture.NumberFormat)},
|
||||
{typeof(float), s => float.Parse(s, CultureInfo.InvariantCulture.NumberFormat)},
|
||||
{typeof(HslColor), s => ColorExtensions.FromHex(s).ToHsl() }
|
||||
};
|
||||
|
||||
public static T[] ReadAsMultiDimensional<T>(this JsonReader reader)
|
||||
{
|
||||
var tokenType = reader.TokenType;
|
||||
|
||||
switch (tokenType)
|
||||
{
|
||||
case JsonToken.StartArray:
|
||||
return reader.ReadAsJArray<T>();
|
||||
|
||||
case JsonToken.String:
|
||||
return reader.ReadAsDelimitedString<T>();
|
||||
|
||||
case JsonToken.Integer:
|
||||
case JsonToken.Float:
|
||||
return reader.ReadAsSingleValue<T>();
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"{tokenType} is not currently supported in the multi dimensional parser");
|
||||
}
|
||||
}
|
||||
|
||||
private static T[] ReadAsSingleValue<T>(this JsonReader reader)
|
||||
{
|
||||
return new[] { JToken.Load(reader).ToObject<T>() };
|
||||
}
|
||||
|
||||
private static T[] ReadAsJArray<T>(this JsonReader reader)
|
||||
{
|
||||
var jArray = JArray.Load(reader);
|
||||
var items = new List<T>();
|
||||
|
||||
foreach (var token in jArray)
|
||||
{
|
||||
if (token.Type == JTokenType.String)
|
||||
{
|
||||
var stringParser = _stringParsers[typeof(T)];
|
||||
var s = token.Value<string>();
|
||||
items.Add((T)stringParser(s));
|
||||
}
|
||||
else
|
||||
{
|
||||
items.Add(token.Value<T>());
|
||||
}
|
||||
}
|
||||
|
||||
return items.ToArray();
|
||||
}
|
||||
|
||||
private static T[] ReadAsDelimitedString<T>(this JsonReader reader)
|
||||
{
|
||||
var value = (string)reader.Value;
|
||||
var parser = _stringParsers[typeof(T)];
|
||||
return value.Split(' ')
|
||||
.Select(i => parser(i))
|
||||
.Cast<T>()
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
{
|
||||
public sealed class MonoGameJsonSerializer : JsonSerializer
|
||||
{
|
||||
public MonoGameJsonSerializer(ContentManager contentManager, string contentPath, NullValueHandling nullValueHandling = NullValueHandling.Include)
|
||||
{
|
||||
Converters.Add(new ColorJsonConverter());
|
||||
Converters.Add(new HslColorJsonConverter());
|
||||
Converters.Add(new RangeJsonConverter<int>());
|
||||
Converters.Add(new RangeJsonConverter<float>());
|
||||
Converters.Add(new RangeJsonConverter<HslColor>());
|
||||
Converters.Add(new ThicknessJsonConverter());
|
||||
Converters.Add(new RectangleFJsonConverter());
|
||||
Converters.Add(new TextureAtlasJsonConverter(contentManager, contentPath));
|
||||
Converters.Add(new Size2JsonConverter());
|
||||
|
||||
ContractResolver = new ShortNameJsonContractResolver();
|
||||
NullValueHandling = nullValueHandling;
|
||||
Formatting = Formatting.Indented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
public static class MonoGameJsonSerializerOptionsProvider
|
||||
{
|
||||
public static JsonSerializerOptions GetOptions(ContentManager contentManager, string contentPath)
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
options.Converters.Add(new RangeJsonConverter<int>());
|
||||
options.Converters.Add(new RangeJsonConverter<float>());
|
||||
options.Converters.Add(new RangeJsonConverter<HslColor>());
|
||||
options.Converters.Add(new ThicknessJsonConverter());
|
||||
options.Converters.Add(new RectangleFJsonConverter());
|
||||
options.Converters.Add(new TextureAtlasJsonConverter(contentManager, contentPath));
|
||||
options.Converters.Add(new Size2JsonConverter());
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,94 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="NinePatchRegion2D"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class NinePatchRegion2DJsonConverter : JsonConverter<NinePatchRegion2D>
|
||||
{
|
||||
public class NinePatchRegion2DJsonConverter : JsonConverter
|
||||
private readonly ITextureRegionService _textureRegionService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NinePatchRegion2DJsonConverter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="textureRegionService">The texture region service used to retrieve texture regions.</param>
|
||||
public NinePatchRegion2DJsonConverter(ITextureRegionService textureRegionService)
|
||||
{
|
||||
private readonly ITextureRegionService _textureRegionService;
|
||||
|
||||
public NinePatchRegion2DJsonConverter(ITextureRegionService textureRegionService)
|
||||
{
|
||||
_textureRegionService = textureRegionService;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var region = (NinePatchRegion2D)value;
|
||||
var jsonObject = new
|
||||
{
|
||||
TextureRegion = region.Name,
|
||||
Padding = region.Padding
|
||||
};
|
||||
serializer.Serialize(writer, jsonObject);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var jsonObject = serializer.Deserialize<JObject>(reader);
|
||||
var paddingAsString = jsonObject.Value<string>("Padding");
|
||||
var thickness = Thickness.Parse(paddingAsString);
|
||||
var regionName = jsonObject.Value<string>("TextureRegion");
|
||||
var region = _textureRegionService.GetTextureRegion(regionName);
|
||||
|
||||
return new NinePatchRegion2D(region, thickness.Left, thickness.Top, thickness.Right, thickness.Bottom);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(NinePatchRegion2D);
|
||||
}
|
||||
_textureRegionService = textureRegionService;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(NinePatchRegion2D);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="JsonException">
|
||||
/// Thrown if the JSON property does not contain a properly formatted <see cref="NinePatchRegion2D"/> value
|
||||
/// </exception>
|
||||
public override NinePatchRegion2D Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType != JsonTokenType.StartObject)
|
||||
{
|
||||
throw new JsonException($"Expected {nameof(JsonTokenType.StartObject)} token");
|
||||
}
|
||||
|
||||
string padding = string.Empty;
|
||||
string regionName = string.Empty;
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.EndObject)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (reader.TokenType == JsonTokenType.PropertyName)
|
||||
{
|
||||
var propertyName = reader.GetString();
|
||||
reader.Read();
|
||||
|
||||
if (propertyName.Equals("Padding", StringComparison.Ordinal))
|
||||
{
|
||||
padding = reader.GetString();
|
||||
}
|
||||
else if (propertyName.Equals("TextureRegion", StringComparison.Ordinal))
|
||||
{
|
||||
regionName = reader.GetString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(padding) || string.IsNullOrEmpty(regionName))
|
||||
{
|
||||
throw new JsonException($"Missing required properties \"Padding\" and \"TextureRegion\"");
|
||||
}
|
||||
|
||||
var thickness = Thickness.Parse(padding);
|
||||
var region = _textureRegionService.GetTextureRegion(regionName);
|
||||
|
||||
return new NinePatchRegion2D(region, thickness.Left, thickness.Top, thickness.Right, thickness.Bottom);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, NinePatchRegion2D value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
writer.WriteNullValue();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteStartObject();
|
||||
writer.WriteString("TextureRegion", value.Name);
|
||||
writer.WriteString("Padding", value.Padding.ToString());
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +1,50 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="Range{T}"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class RangeJsonConverter<T> : JsonConverter<Range<T>> where T : IComparable<T>
|
||||
{
|
||||
public class RangeJsonConverter<T> : JsonConverter where T : IComparable<T>
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Range<T>);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Range<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
Span<T> values = reader.ReadAsMultiDimensional<T>();
|
||||
|
||||
if (values.Length == 2)
|
||||
{
|
||||
var range = (Range<T>) value;
|
||||
|
||||
var formatting = writer.Formatting;
|
||||
writer.Formatting = Formatting.None;
|
||||
writer.WriteWhitespace(" ");
|
||||
writer.WriteStartArray();
|
||||
serializer.Serialize(writer, range.Min);
|
||||
serializer.Serialize(writer, range.Max);
|
||||
//writer.WriteValue(range.Min);
|
||||
//writer.WriteValue(range.Max);
|
||||
writer.WriteEndArray();
|
||||
writer.Formatting = formatting;
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var values = reader.ReadAsMultiDimensional<T>();
|
||||
|
||||
if (values.Length == 2)
|
||||
if (values[0].CompareTo(values[1]) < 0)
|
||||
{
|
||||
if (values[0].CompareTo(values[1]) < 0)
|
||||
return new Range<T>(values[0], values[1]);
|
||||
|
||||
return new Range<T>(values[1], values[0]);
|
||||
return new Range<T>(values[0], values[1]);
|
||||
}
|
||||
|
||||
|
||||
if (values.Length == 1)
|
||||
return new Range<T>(values[0], values[0]);
|
||||
|
||||
throw new InvalidOperationException("Invalid range");
|
||||
return new Range<T>(values[1], values[0]);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
if (values.Length == 1)
|
||||
{
|
||||
return objectType == typeof(Range<T>);
|
||||
return new Range<T>(values[0], values[0]);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Invalid range");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, Range<T> value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
writer.WriteStartArray();
|
||||
JsonSerializer.Serialize(writer, value.Min, options);
|
||||
JsonSerializer.Serialize(writer, value.Max, options);
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,31 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
public class RectangleFJsonConverter: JsonConverter
|
||||
/// <summary>
|
||||
/// Converts a <see cref="RectangleF"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class RectangleFJsonConverter : JsonConverter<RectangleF>
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var rect = (RectangleF)value;
|
||||
writer.WriteValue($"{rect.Left} {rect.Top} {rect.Width} {rect.Height}");
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(RectangleF);
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
/// <inheritdoc />
|
||||
public override RectangleF Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var values = reader.ReadAsMultiDimensional<float>();
|
||||
return new RectangleF(values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, RectangleF value, JsonSerializerOptions options)
|
||||
{
|
||||
return objectType == typeof(RectangleF);
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
writer.WriteStringValue($"{value.Left} {value.Top} {value.Width} {value.Height}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
{
|
||||
public class ShortNameJsonContractResolver : CamelCasePropertyNamesContractResolver
|
||||
{
|
||||
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||
{
|
||||
var properties = base.CreateProperties(type, memberSerialization)
|
||||
.Where(p => p.Writable || IsListProperty(p))
|
||||
.ToList();
|
||||
|
||||
var typeInfo = type.GetTypeInfo();
|
||||
|
||||
if (typeInfo.IsAbstract)
|
||||
{
|
||||
properties.Insert(0, new JsonProperty
|
||||
{
|
||||
PropertyType = typeof(string),
|
||||
PropertyName = "type",
|
||||
Readable = true,
|
||||
Writable = false,
|
||||
ValueProvider = new JsonShortTypeNameProvider()
|
||||
});
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
private static bool IsListProperty(JsonProperty property)
|
||||
{
|
||||
return typeof(IList).GetTypeInfo().IsAssignableFrom(property.PropertyType.GetTypeInfo());
|
||||
}
|
||||
|
||||
private class JsonShortTypeNameProvider : IValueProvider
|
||||
{
|
||||
public JsonShortTypeNameProvider()
|
||||
{
|
||||
}
|
||||
|
||||
public void SetValue(object target, object value)
|
||||
{
|
||||
}
|
||||
|
||||
public object GetValue(object target)
|
||||
{
|
||||
return target.GetType().Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,45 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="Size2"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class Size2JsonConverter : JsonConverter<Size2>
|
||||
{
|
||||
public class Size2JsonConverter : JsonConverter
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Size2);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="JsonException">
|
||||
/// Thrown if the JSON property does not contain a properly formatted <see cref="Size2"/> value
|
||||
/// </exception>
|
||||
public override Size2 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
var values = reader.ReadAsMultiDimensional<float>();
|
||||
|
||||
if (values.Length == 2)
|
||||
{
|
||||
var sizeF = (Size2) value;
|
||||
writer.WriteValue($"{sizeF.Width} {sizeF.Height}");
|
||||
return new Size2(values[0], values[1]);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
if (values.Length == 1)
|
||||
{
|
||||
var values = reader.ReadAsMultiDimensional<float>();
|
||||
|
||||
if(values.Length == 2)
|
||||
return new Size2(values[0], values[1]);
|
||||
|
||||
if (values.Length == 1)
|
||||
return new Size2(values[0], values[0]);
|
||||
|
||||
throw new FormatException("Invalid Size property value");
|
||||
return new Size2(values[0], values[0]);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(Size2);
|
||||
}
|
||||
throw new JsonException("Invalid Size2 property value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, Size2 value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
writer.WriteStringValue($"{value.Width} {value.Height}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,45 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="Size"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class SizeJsonConverter : JsonConverter<Size>
|
||||
{
|
||||
public class SizeJsonConverter : JsonConverter
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Size);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="JsonException">
|
||||
/// Thrown if the JSON property does not contain a properly formatted <see cref="Size"/> value
|
||||
/// </exception>
|
||||
public override Size Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
var values = reader.ReadAsMultiDimensional<int>();
|
||||
|
||||
if (values.Length == 2)
|
||||
{
|
||||
var sizeF = (Size) value;
|
||||
writer.WriteValue($"{sizeF.Width} {sizeF.Height}");
|
||||
return new Size(values[0], values[1]);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
if (values.Length == 1)
|
||||
{
|
||||
var values = reader.ReadAsMultiDimensional<int>();
|
||||
|
||||
if(values.Length == 2)
|
||||
return new Size(values[0], values[1]);
|
||||
|
||||
if (values.Length == 1)
|
||||
return new Size(values[0], values[0]);
|
||||
|
||||
throw new FormatException("Invalid Size property value");
|
||||
return new Size(values[0], values[0]);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(Size);
|
||||
}
|
||||
throw new JsonException("Invalid Size property value");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, Size value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
writer.WriteStringValue($"{value.Width} {value.Height}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,52 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="TextureRegion2D"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class TextureRegion2DJsonConverter : JsonConverter<TextureRegion2D>
|
||||
{
|
||||
public class TextureRegion2DJsonConverter : JsonConverter
|
||||
private readonly ITextureRegionService _textureRegionService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TextureRegion2DJsonConverter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="textureRegionService">The texture region service to use for retrieving texture regions.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="textureRegionService"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public TextureRegion2DJsonConverter(ITextureRegionService textureRegionService)
|
||||
{
|
||||
private readonly ITextureRegionService _textureRegionService;
|
||||
|
||||
public TextureRegion2DJsonConverter(ITextureRegionService textureRegionService)
|
||||
{
|
||||
_textureRegionService = textureRegionService;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var region = (TextureRegion2D)value;
|
||||
writer.WriteValue(region.Name);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var regionName = reader.Value as string;
|
||||
return regionName == null ? null : _textureRegionService.GetTextureRegion(regionName);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(TextureRegion2D);
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(textureRegionService);
|
||||
_textureRegionService = textureRegionService;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(TextureRegion2D);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override TextureRegion2D Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var regionName = reader.GetString();
|
||||
return string.IsNullOrEmpty(regionName) ? null : _textureRegionService.GetTextureRegion(regionName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
///
|
||||
/// -or-
|
||||
///
|
||||
/// Thrown if <paramref name="value"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, TextureRegion2D value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
writer.WriteStringValue(value.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="Thickness"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class ThicknessJsonConverter : JsonConverter<Thickness>
|
||||
{
|
||||
public class ThicknessJsonConverter : JsonConverter
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Thickness);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Thickness Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var thickness = (Thickness)value;
|
||||
writer.WriteValue($"{thickness.Left} {thickness.Top} {thickness.Right} {thickness.Bottom}");
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var values = reader.ReadAsMultiDimensional<int>();
|
||||
return Thickness.FromValues(values);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(Thickness);
|
||||
}
|
||||
var values = reader.ReadAsMultiDimensional<int>();
|
||||
return Thickness.FromValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, Thickness value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
writer.WriteStringValue($"{value.Left} {value.Top} {value.Right} {value.Bottom}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for working with <see cref="Utf8JsonReader"/>.
|
||||
/// </summary>
|
||||
public static class Utf8JsonReaderExtensions
|
||||
{
|
||||
private static readonly Dictionary<Type, Func<string, object>> s_stringParsers = new Dictionary<Type, Func<string, object>>
|
||||
{
|
||||
{typeof(int), s => int.Parse(s, CultureInfo.InvariantCulture.NumberFormat)},
|
||||
{typeof(float), s => float.Parse(s, CultureInfo.InvariantCulture.NumberFormat)},
|
||||
{typeof(HslColor), s => ColorExtensions.FromHex(s).ToHsl() }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Reads a multi-dimensional JSON array and converts it to an array of the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the array elements.</typeparam>
|
||||
/// <param name="reader">The <see cref="Utf8JsonReader"/> to read from.</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)
|
||||
{
|
||||
var tokenType = reader.TokenType;
|
||||
|
||||
switch (tokenType)
|
||||
{
|
||||
case JsonTokenType.StartArray:
|
||||
return reader.ReadAsJArray<T>();
|
||||
|
||||
case JsonTokenType.String:
|
||||
return reader.ReadAsDelimitedString<T>();
|
||||
|
||||
case JsonTokenType.Number:
|
||||
return reader.ReadAsSingleValue<T>();
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"{tokenType} is not currently supported in the multi-dimensional parser");
|
||||
}
|
||||
}
|
||||
|
||||
private static T[] ReadAsSingleValue<T>(this ref Utf8JsonReader reader)
|
||||
{
|
||||
var token = JsonDocument.ParseValue(ref reader).RootElement;
|
||||
var value = JsonSerializer.Deserialize<T>(token.GetRawText());
|
||||
return new T[] { value };
|
||||
}
|
||||
|
||||
private static T[] ReadAsJArray<T>(this ref Utf8JsonReader reader)
|
||||
{
|
||||
var items = new List<T>();
|
||||
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.EndArray)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
items.Add(JsonSerializer.Deserialize<T>(ref reader));
|
||||
}
|
||||
|
||||
return items.ToArray();
|
||||
}
|
||||
|
||||
private static T[] ReadAsDelimitedString<T>(this ref Utf8JsonReader reader)
|
||||
{
|
||||
var value = reader.GetString();
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return Array.Empty<T>();
|
||||
}
|
||||
|
||||
Span<string> values = value.Split(' ');
|
||||
var result = new T[values.Length];
|
||||
var parser = s_stringParsers[typeof(T)];
|
||||
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
result[i] = (T)parser(values[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,46 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="Vector2"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class Vector2JsonConverter : JsonConverter<Vector2>
|
||||
{
|
||||
public class Vector2JsonConverter : JsonConverter
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Vector2);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="JsonException">
|
||||
/// Thrown if the JSON property does not contain a properly formatted <see cref="Vector2"/> value
|
||||
/// </exception>
|
||||
public override Vector2 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
var values = reader.ReadAsMultiDimensional<float>();
|
||||
|
||||
if (values.Length == 2)
|
||||
{
|
||||
var vector2 = (Vector2) value;
|
||||
writer.WriteValue($"{vector2.X} {vector2.Y}");
|
||||
return new Vector2(values[0], values[1]);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
if (values.Length == 1)
|
||||
{
|
||||
var values = reader.ReadAsMultiDimensional<float>();
|
||||
|
||||
if(values.Length == 2)
|
||||
return new Vector2(values[0], values[1]);
|
||||
|
||||
if (values.Length == 1)
|
||||
return new Vector2(values[0]);
|
||||
|
||||
throw new InvalidOperationException("Invalid Vector2");
|
||||
return new Vector2(values[0]);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(Vector2);
|
||||
}
|
||||
throw new JsonException("Invalid Size2 property value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, Vector2 value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
writer.WriteStringValue($"{value.X} {value.Y}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
|
||||
namespace MonoGame.Extended.Sprites
|
||||
{
|
||||
@@ -20,31 +22,31 @@ namespace MonoGame.Extended.Sprites
|
||||
|
||||
public class SpriteSheetAnimationFrameJsonConverter : JsonConverter<SpriteSheetAnimationFrame>
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, SpriteSheetAnimationFrame value, JsonSerializer serializer)
|
||||
{
|
||||
serializer.Serialize(writer, value);
|
||||
}
|
||||
|
||||
public override SpriteSheetAnimationFrame ReadJson(JsonReader reader, Type objectType, SpriteSheetAnimationFrame existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||
/// <inheritdoc />
|
||||
public override SpriteSheetAnimationFrame Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.Integer:
|
||||
{
|
||||
var index = serializer.Deserialize<int>(reader);
|
||||
case JsonTokenType.Number:
|
||||
var index = reader.GetInt32();
|
||||
return new SpriteSheetAnimationFrame(index);
|
||||
}
|
||||
case JsonToken.StartObject:
|
||||
{
|
||||
var frame = new SpriteSheetAnimationFrame(0);
|
||||
serializer.Populate(reader, frame);
|
||||
|
||||
case JsonTokenType.StartObject:
|
||||
var frame = JsonSerializer.Deserialize<SpriteSheetAnimationFrame>(ref reader, options);
|
||||
return frame;
|
||||
}
|
||||
case JsonToken.Null:
|
||||
|
||||
case JsonTokenType.Null:
|
||||
return null;
|
||||
|
||||
default:
|
||||
throw new JsonSerializationException();
|
||||
throw new JsonException();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, SpriteSheetAnimationFrame value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
JsonSerializer.Serialize(writer, value, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.Content;
|
||||
using MonoGame.Extended.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using ContentReaderExtensions = MonoGame.Extended.Content.ContentReaderExtensions;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
@@ -13,13 +13,7 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
private static TexturePackerFile Load(ContentReader reader)
|
||||
{
|
||||
var json = reader.ReadString();
|
||||
|
||||
using (var stringReader = new StringReader(json))
|
||||
using (var jsonReader = new JsonTextReader(stringReader))
|
||||
{
|
||||
var serializer = new JsonSerializer();
|
||||
return serializer.Deserialize<TexturePackerFile>(jsonReader);
|
||||
}
|
||||
return JsonSerializer.Deserialize<TexturePackerFile>(json);
|
||||
}
|
||||
|
||||
protected override TextureAtlas Read(ContentReader reader, TextureAtlas existingInstance)
|
||||
@@ -44,4 +38,4 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
return atlas;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.Content;
|
||||
using MonoGame.Extended.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
public class TextureAtlasJsonConverter : JsonConverter
|
||||
public class TextureAtlasJsonConverter : JsonConverter<TextureAtlas>
|
||||
{
|
||||
private readonly ContentManager _contentManager;
|
||||
private readonly string _path;
|
||||
@@ -19,23 +20,16 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
_path = path;
|
||||
}
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Local
|
||||
private class InlineTextureAtlas
|
||||
{
|
||||
public string Texture { get; set; }
|
||||
public int RegionWidth { get; set; }
|
||||
public int RegionHeight { get; set; }
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(TextureAtlas);
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
public override TextureAtlas Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.ValueType == typeof(string))
|
||||
if(reader.TokenType == JsonTokenType.String)
|
||||
{
|
||||
var textureAtlasAssetName = reader.Value.ToString();
|
||||
// TODO: (Aristurtle 05/20/2024) What is this for? It's just an if block that throws an exception. Need
|
||||
// to investigate.
|
||||
var textureAtlasAssetName = reader.GetString();
|
||||
var contentPath = GetContentPath(textureAtlasAssetName);
|
||||
var texturePackerFile = _contentManager.Load<TexturePackerFile>(contentPath, new JsonContentLoader());
|
||||
var texture = _contentManager.Load<Texture2D>(texturePackerFile.Metadata.Image);
|
||||
@@ -44,7 +38,7 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
}
|
||||
else
|
||||
{
|
||||
var metadata = serializer.Deserialize<InlineTextureAtlas>(reader);
|
||||
var metadata = JsonSerializer.Deserialize<InlineTextureAtlas>(ref reader, options);
|
||||
|
||||
// TODO: When we get to .NET Standard 2.1 it would be more robust to use
|
||||
// [Path.GetRelativePath](https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getrelativepath?view=netstandard-2.1)
|
||||
@@ -58,8 +52,9 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
texture = _contentManager.Load<Texture2D>(resolvedAssetName);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (textureDirectory == null || textureDirectory == "")
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (textureDirectory == null || textureDirectory == "")
|
||||
texture = _contentManager.Load<Texture2D>(textureName);
|
||||
else
|
||||
texture = _contentManager.Load<Texture2D>(textureDirectory + "/" + textureName);
|
||||
@@ -68,15 +63,22 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, TextureAtlas value, JsonSerializerOptions options) { }
|
||||
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Local
|
||||
private class InlineTextureAtlas
|
||||
{
|
||||
public string Texture { get; set; }
|
||||
public int RegionWidth { get; set; }
|
||||
public int RegionHeight { get; set; }
|
||||
}
|
||||
|
||||
private string GetContentPath(string relativePath)
|
||||
{
|
||||
var directory = Path.GetDirectoryName(_path);
|
||||
return Path.Combine(directory, relativePath);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(TextureAtlas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
public class TexturePackerFile
|
||||
{
|
||||
[JsonProperty("frames")]
|
||||
[JsonPropertyName("frames")]
|
||||
public List<TexturePackerRegion> Regions { get; set; }
|
||||
|
||||
[JsonProperty("meta")]
|
||||
[JsonPropertyName("meta")]
|
||||
public TexturePackerMeta Metadata { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using MonoGame.Extended.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
public class TexturePackerMeta
|
||||
{
|
||||
[JsonProperty("app")]
|
||||
[JsonPropertyName("app")]
|
||||
public string App { get; set; }
|
||||
|
||||
[JsonProperty("version")]
|
||||
[JsonPropertyName("version")]
|
||||
public string Version { get; set; }
|
||||
|
||||
[JsonProperty("image")]
|
||||
[JsonPropertyName("image")]
|
||||
public string Image { get; set; }
|
||||
|
||||
[JsonProperty("format")]
|
||||
[JsonPropertyName("format")]
|
||||
public string Format { get; set; }
|
||||
|
||||
[JsonProperty("size")]
|
||||
[JsonPropertyName("size")]
|
||||
public TexturePackerSize Size { get; set; }
|
||||
|
||||
[JsonProperty("scale")]
|
||||
[JsonPropertyName("scale")]
|
||||
[JsonConverter(typeof(FloatStringConverter))]
|
||||
public float Scale { get; set; }
|
||||
|
||||
[JsonProperty("smartupdate")]
|
||||
[JsonPropertyName("smartupdate")]
|
||||
public string SmartUpdate { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
@@ -30,4 +32,5 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
return Image;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
public class TexturePackerPoint
|
||||
{
|
||||
[JsonProperty("x")]
|
||||
[JsonPropertyName("x")]
|
||||
public double X { get; set; }
|
||||
|
||||
[JsonProperty("y")]
|
||||
[JsonPropertyName("y")]
|
||||
public double Y { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
@@ -15,4 +15,4 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
return string.Format("{0} {1}", X, Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
public class TexturePackerRectangle
|
||||
{
|
||||
[JsonProperty("x")]
|
||||
[JsonPropertyName("x")]
|
||||
public int X { get; set; }
|
||||
|
||||
[JsonProperty("y")]
|
||||
[JsonPropertyName("y")]
|
||||
public int Y { get; set; }
|
||||
|
||||
[JsonProperty("w")]
|
||||
[JsonPropertyName("w")]
|
||||
public int Width { get; set; }
|
||||
|
||||
[JsonProperty("h")]
|
||||
[JsonPropertyName("h")]
|
||||
public int Height { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
@@ -21,4 +21,4 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
return string.Format("{0} {1} {2} {3}", X, Y, Width, Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
public class TexturePackerRegion
|
||||
{
|
||||
[JsonProperty("filename")]
|
||||
[JsonPropertyName("filename")]
|
||||
public string Filename { get; set; }
|
||||
|
||||
[JsonProperty("frame")]
|
||||
[JsonPropertyName("frame")]
|
||||
public TexturePackerRectangle Frame { get; set; }
|
||||
|
||||
[JsonProperty("rotated")]
|
||||
[JsonPropertyName("rotated")]
|
||||
public bool IsRotated { get; set; }
|
||||
|
||||
[JsonProperty("trimmed")]
|
||||
[JsonPropertyName("trimmed")]
|
||||
public bool IsTrimmed { get; set; }
|
||||
|
||||
[JsonProperty("spriteSourceSize")]
|
||||
[JsonPropertyName("spriteSourceSize")]
|
||||
public TexturePackerRectangle SourceRectangle { get; set; }
|
||||
|
||||
[JsonProperty("sourceSize")]
|
||||
[JsonPropertyName("sourceSize")]
|
||||
public TexturePackerSize SourceSize { get; set; }
|
||||
|
||||
[JsonProperty("pivot")]
|
||||
[JsonPropertyName("pivot")]
|
||||
public TexturePackerPoint PivotPoint { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
@@ -30,4 +30,4 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
return $"{Filename} {Frame}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
public class TexturePackerSize
|
||||
{
|
||||
[JsonProperty("w")]
|
||||
[JsonPropertyName("w")]
|
||||
public int Width { get; set; }
|
||||
|
||||
[JsonProperty("h")]
|
||||
[JsonPropertyName("h")]
|
||||
public int Height { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
@@ -15,4 +15,4 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
return $"{Width} {Height}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Tests.Serialization;
|
||||
|
||||
public sealed class ColorJsonConverterTests
|
||||
{
|
||||
private readonly ColorJsonConverter _converter = new ColorJsonConverter();
|
||||
|
||||
[Fact]
|
||||
public void CanConvert_ColorType_ReturnsTrue()
|
||||
{
|
||||
var colorType = typeof(Color);
|
||||
var result = _converter.CanConvert(colorType);
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanConvert_NonColorType_ReturnsFalse()
|
||||
{
|
||||
var otherType = typeof(string);
|
||||
var result = _converter.CanConvert(otherType);
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Red", 255, 0, 0, 255)]
|
||||
[InlineData("#FF0000FF", 255, 0, 0, 255)]
|
||||
public void Read_ValidColorJson_ReturnsExpectedColor(string jsonValue, byte r, byte g, byte b, byte a)
|
||||
{
|
||||
var json = $"\"{jsonValue}\"";
|
||||
var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
reader.Read();
|
||||
var actual = _converter.Read(ref reader, typeof(Color), new JsonSerializerOptions());
|
||||
|
||||
var expected = new Color(r, g, b, a);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_ValidColor_WritesExpectedJson()
|
||||
{
|
||||
var expected = "#ff000000";
|
||||
var color = ColorHelper.FromHex(expected);
|
||||
using var stream = new MemoryStream();
|
||||
using var writer = new Utf8JsonWriter(stream);
|
||||
|
||||
_converter.Write(writer, color, new JsonSerializerOptions());
|
||||
writer.Flush();
|
||||
var actual = Encoding.UTF8.GetString(stream.ToArray());
|
||||
|
||||
Assert.Equal($"\"{expected}\"", actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_NullWrier_ThrowArgumentNullException()
|
||||
{
|
||||
var color = Color.MonoGameOrange;
|
||||
Assert.Throws<ArgumentNullException>(() => _converter.Write(null, color, new JsonSerializerOptions()));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using MonoGame.Extended.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace MonoGame.Extended.Tests.Serialization;
|
||||
@@ -18,12 +18,15 @@ public class RectangleFJsonConverterTest
|
||||
{
|
||||
var jsonData = @"
|
||||
{
|
||||
box: ""1 1 10 10""
|
||||
""box"": ""1 1 10 10""
|
||||
}
|
||||
";
|
||||
var serializer = new JsonSerializer();
|
||||
serializer.Converters.Add(new RectangleFJsonConverter());
|
||||
var content = serializer.Deserialize<TestContent>(new JsonTextReader(new StringReader(jsonData)));
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
options.Converters.Add(new RectangleFJsonConverter());
|
||||
var content = JsonSerializer.Deserialize<TestContent>(jsonData, options);
|
||||
|
||||
Assert.Equal(1, content.Box.Left);
|
||||
Assert.Equal(1, content.Box.Top);
|
||||
|
||||
Reference in New Issue
Block a user