diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index 69ce3825ee..bff08b0515 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -23,6 +23,7 @@ namespace osu.Game.Online.API [JsonProperty("settings")] [Key(1)] + [MessagePackFormatter(typeof(ModSettingsDictionaryFormatter))] public Dictionary Settings { get; set; } = new Dictionary(); [JsonConstructor] diff --git a/osu.Game/Online/API/ModSettingsDictionaryFormatter.cs b/osu.Game/Online/API/ModSettingsDictionaryFormatter.cs new file mode 100644 index 0000000000..a8ee9beca5 --- /dev/null +++ b/osu.Game/Online/API/ModSettingsDictionaryFormatter.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using MessagePack; +using MessagePack.Formatters; +using osu.Framework.Bindables; + +namespace osu.Game.Online.API +{ + public class ModSettingsDictionaryFormatter : IMessagePackFormatter> + { + public int Serialize(ref byte[] bytes, int offset, Dictionary value, IFormatterResolver formatterResolver) + { + int startOffset = offset; + + offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, value.Count); + + foreach (var kvp in value) + { + offset += MessagePackBinary.WriteString(ref bytes, offset, kvp.Key); + + switch (kvp.Value) + { + case Bindable d: + offset += MessagePackBinary.WriteDouble(ref bytes, offset, d.Value); + break; + + case Bindable f: + offset += MessagePackBinary.WriteSingle(ref bytes, offset, f.Value); + break; + + case Bindable b: + offset += MessagePackBinary.WriteBoolean(ref bytes, offset, b.Value); + break; + + default: + throw new ArgumentException("A setting was of a type not supported by the messagepack serialiser", nameof(bytes)); + } + } + + return offset - startOffset; + } + + public Dictionary Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) + { + int startOffset = offset; + + var output = new Dictionary(); + + int itemCount = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); + offset += readSize; + + for (int i = 0; i < itemCount; i++) + { + var key = MessagePackBinary.ReadString(bytes, offset, out readSize); + offset += readSize; + + switch (MessagePackBinary.GetMessagePackType(bytes, offset)) + { + case MessagePackType.Float: + { + // could be either float or double... + // see https://github.com/msgpack/msgpack/blob/master/spec.md#serialization-type-to-format-conversion + switch (MessagePackCode.ToFormatName(bytes[offset])) + { + case "float 32": + output[key] = MessagePackBinary.ReadSingle(bytes, offset, out readSize); + offset += readSize; + break; + + case "float 64": + output[key] = MessagePackBinary.ReadDouble(bytes, offset, out readSize); + offset += readSize; + break; + + default: + throw new ArgumentException("A setting was of a type not supported by the messagepack deserialiser", nameof(bytes)); + } + + break; + } + + case MessagePackType.Boolean: + output[key] = MessagePackBinary.ReadBoolean(bytes, offset, out readSize); + offset += readSize; + break; + + default: + throw new ArgumentException("A setting was of a type not supported by the messagepack deserialiser", nameof(bytes)); + } + } + + readSize = offset - startOffset; + return output; + } + } +}