diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs index f6eaea0a8c..b5761bdaea 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs @@ -22,7 +22,7 @@ namespace osu.Game.Beatmaps.ControlPoints [JsonIgnore] public IBindableList ControlPoints => controlPoints; - [JsonConverter(typeof(BindableListConverter))] + [JsonConverter(typeof(TypedListConverter))] [JsonProperty] private readonly BindableList controlPoints = new BindableList(); diff --git a/osu.Game/IO/Serialization/Converters/BindableListConverter.cs b/osu.Game/IO/Serialization/Converters/BindableListConverter.cs deleted file mode 100644 index 30b3d80bc9..0000000000 --- a/osu.Game/IO/Serialization/Converters/BindableListConverter.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; - -namespace osu.Game.IO.Serialization.Converters -{ - /// - /// A type of that serializes an alongside - /// a lookup table for the types contained. The lookup table is used in deserialization to - /// reconstruct the objects with their original types. - /// - /// The type of objects contained in the this attribute is attached to. - public class BindableListConverter : JsonConverter> - { - private readonly bool requiresTypeVersion; - - /// - /// Constructs a new . - /// - // ReSharper disable once UnusedMember.Global - public BindableListConverter() - { - } - - /// - /// Constructs a new . - /// - /// Whether the version of the type should be serialized. - // ReSharper disable once UnusedMember.Global (Used in Beatmap) - public BindableListConverter(bool requiresTypeVersion) - { - this.requiresTypeVersion = requiresTypeVersion; - } - - public override IBindableList ReadJson(JsonReader reader, Type objectType, IBindableList existingValue, bool hasExistingValue, JsonSerializer serializer) - { - var list = new BindableList(); - - var obj = JObject.Load(reader); - - if (obj["$lookup_table"] == null) - return list; - - var lookupTable = serializer.Deserialize>(obj["$lookup_table"].CreateReader()); - if (lookupTable == null) - return list; - - if (obj["$items"] == null) - return list; - - foreach (var tok in obj["$items"]) - { - var itemReader = tok.CreateReader(); - - if (tok["$type"] == null) - throw new JsonException("Expected $type token."); - - string typeName = lookupTable[(int)tok["$type"]]; - var instance = (T)Activator.CreateInstance(Type.GetType(typeName).AsNonNull())!; - serializer.Populate(itemReader, instance); - - list.Add(instance); - } - - return list; - } - - public override void WriteJson(JsonWriter writer, IBindableList value, JsonSerializer serializer) - { - var lookupTable = new List(); - var objects = new List(); - - foreach (var item in value) - { - var type = item.GetType(); - var assemblyName = type.Assembly.GetName(); - - string typeString = $"{type.FullName}, {assemblyName.Name}"; - if (requiresTypeVersion) - typeString += $", {assemblyName.Version}"; - - int typeId = lookupTable.IndexOf(typeString); - - if (typeId == -1) - { - lookupTable.Add(typeString); - typeId = lookupTable.Count - 1; - } - - var itemObject = JObject.FromObject(item, serializer); - itemObject.AddFirst(new JProperty("$type", typeId)); - objects.Add(itemObject); - } - - writer.WriteStartObject(); - - writer.WritePropertyName("$lookup_table"); - serializer.Serialize(writer, lookupTable); - - writer.WritePropertyName("$items"); - serializer.Serialize(writer, objects); - - writer.WriteEndObject(); - } - } -} diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index de25d3e30e..2f7db339d1 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -7,17 +7,18 @@ using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; namespace osu.Game.IO.Serialization.Converters { /// - /// A type of that serializes an alongside + /// A type of that serializes a list alongside /// a lookup table for the types contained. The lookup table is used in deserialization to /// reconstruct the objects with their original types. /// - /// The type of objects contained in the this attribute is attached to. - public class TypedListConverter : JsonConverter> + /// The type of objects contained in the list this attribute is attached to. + public class TypedListConverter : JsonConverter { private readonly bool requiresTypeVersion; @@ -39,10 +40,9 @@ namespace osu.Game.IO.Serialization.Converters this.requiresTypeVersion = requiresTypeVersion; } - public override IReadOnlyList ReadJson(JsonReader reader, Type objectType, IReadOnlyList existingValue, bool hasExistingValue, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var list = new List(); - var obj = JObject.Load(reader); if (obj["$lookup_table"] == null) @@ -69,15 +69,25 @@ namespace osu.Game.IO.Serialization.Converters list.Add(instance); } + if (objectType == typeof(IBindableList) || objectType == typeof(BindableList)) + return new BindableList(list); + + if (objectType == typeof(IReadOnlyList)) + return list.AsReadOnly(); + return list; } - public override void WriteJson(JsonWriter writer, IReadOnlyList value, JsonSerializer serializer) + public override bool CanConvert(Type objectType) + => objectType == typeof(IBindableList) || objectType == typeof(BindableList) || objectType == typeof(IReadOnlyList) || objectType == typeof(List); + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { + var enumerable = (IEnumerable)value!; var lookupTable = new List(); var objects = new List(); - foreach (var item in value) + foreach (var item in enumerable) { var type = item.GetType(); var assemblyName = type.Assembly.GetName();