From 8b28bf31f69e44a1922ddc7a649c3f6d63875a48 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 20 Nov 2021 15:11:02 +0300 Subject: [PATCH] Separate SignalR workaround types away from resolver --- ...gnalRDerivedTypeWorkaroundJsonConverter.cs | 7 +-- .../Online/SignalRUnionWorkaroundResolver.cs | 45 +++++++------------ osu.Game/Online/SignalRWorkaroundTypes.cs | 26 +++++++++++ 3 files changed, 45 insertions(+), 33 deletions(-) create mode 100644 osu.Game/Online/SignalRWorkaroundTypes.cs diff --git a/osu.Game/Online/SignalRDerivedTypeWorkaroundJsonConverter.cs b/osu.Game/Online/SignalRDerivedTypeWorkaroundJsonConverter.cs index 55516d2223..5643c5ca74 100644 --- a/osu.Game/Online/SignalRDerivedTypeWorkaroundJsonConverter.cs +++ b/osu.Game/Online/SignalRDerivedTypeWorkaroundJsonConverter.cs @@ -17,8 +17,9 @@ namespace osu.Game.Online public class SignalRDerivedTypeWorkaroundJsonConverter : JsonConverter { public override bool CanConvert(Type objectType) => - SignalRUnionWorkaroundResolver.BASE_TYPES.Contains(objectType) || - SignalRUnionWorkaroundResolver.DERIVED_TYPES.Contains(objectType); + SignalRWorkaroundTypes.BASE_DERIVED.Any(t => + objectType == t.baseType || + objectType == t.derivedType); public override object? ReadJson(JsonReader reader, Type objectType, object? o, JsonSerializer jsonSerializer) { @@ -29,7 +30,7 @@ namespace osu.Game.Online string type = (string)obj[@"$dtype"]!; - var resolvedType = SignalRUnionWorkaroundResolver.DERIVED_TYPES.Single(t => t.Name == type); + var resolvedType = SignalRWorkaroundTypes.BASE_DERIVED.Select(t => t.derivedType).Single(t => t.Name == type); object? instance = Activator.CreateInstance(resolvedType); diff --git a/osu.Game/Online/SignalRUnionWorkaroundResolver.cs b/osu.Game/Online/SignalRUnionWorkaroundResolver.cs index 89052ad052..01e3c24c87 100644 --- a/osu.Game/Online/SignalRUnionWorkaroundResolver.cs +++ b/osu.Game/Online/SignalRUnionWorkaroundResolver.cs @@ -3,11 +3,10 @@ using System; using System.Collections.Generic; +using System.Linq; using MessagePack; using MessagePack.Formatters; using MessagePack.Resolvers; -using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; namespace osu.Game.Online { @@ -20,40 +19,26 @@ namespace osu.Game.Online public static readonly MessagePackSerializerOptions OPTIONS = MessagePackSerializerOptions.Standard.WithResolver(new SignalRUnionWorkaroundResolver()); - public static readonly IReadOnlyList BASE_TYPES = new[] + private static readonly IReadOnlyDictionary formatter_map = createFormatterMap(); + + private static IReadOnlyDictionary createFormatterMap() { - typeof(MatchServerEvent), - typeof(MatchUserRequest), - typeof(MatchRoomState), - typeof(MatchUserState), - }; + IEnumerable<(Type derivedType, Type baseType)> baseDerived = SignalRWorkaroundTypes.BASE_DERIVED; - public static readonly IReadOnlyList DERIVED_TYPES = new[] - { - typeof(ChangeTeamRequest), - typeof(TeamVersusRoomState), - typeof(TeamVersusUserState), - }; - - private static IReadOnlyDictionary formatterMapBacking; - - private static IReadOnlyDictionary formatterMap => formatterMapBacking ??= new Dictionary - { - { typeof(TeamVersusUserState), new TypeRedirectingFormatter() }, - { typeof(TeamVersusRoomState), new TypeRedirectingFormatter() }, - { typeof(ChangeTeamRequest), new TypeRedirectingFormatter() }, - - // These should not be required. The fallback should work. But something is weird with the way caching is done. + // This should not be required. The fallback should work. But something is weird with the way caching is done. // For future adventurers, I would not advise looking into this further. It's likely not worth the effort. - { typeof(MatchUserState), new TypeRedirectingFormatter() }, - { typeof(MatchRoomState), new TypeRedirectingFormatter() }, - { typeof(MatchUserRequest), new TypeRedirectingFormatter() }, - { typeof(MatchServerEvent), new TypeRedirectingFormatter() }, - }; + baseDerived = baseDerived.Concat(baseDerived.Select(t => (t.baseType, t.baseType))).Distinct(); + + return new Dictionary(baseDerived.Select(t => + { + var formatter = (IMessagePackFormatter)Activator.CreateInstance(typeof(TypeRedirectingFormatter<,>).MakeGenericType(t.derivedType, t.baseType)); + return new KeyValuePair(t.derivedType, formatter); + })); + } public IMessagePackFormatter GetFormatter() { - if (formatterMap.TryGetValue(typeof(T), out var formatter)) + if (formatter_map.TryGetValue(typeof(T), out var formatter)) return (IMessagePackFormatter)formatter; return StandardResolver.Instance.GetFormatter(); diff --git a/osu.Game/Online/SignalRWorkaroundTypes.cs b/osu.Game/Online/SignalRWorkaroundTypes.cs new file mode 100644 index 0000000000..ae2d8b997c --- /dev/null +++ b/osu.Game/Online/SignalRWorkaroundTypes.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; + +namespace osu.Game.Online +{ + /// + /// A static class providing the list of types requiring workarounds for serialisation in SignalR. + /// + /// + /// + internal static class SignalRWorkaroundTypes + { + internal static readonly IReadOnlyList<(Type derivedType, Type baseType)> BASE_DERIVED = new[] + { + (typeof(ChangeTeamRequest), typeof(MatchUserRequest)), + (typeof(TeamVersusRoomState), typeof(MatchRoomState)), + (typeof(TeamVersusUserState), typeof(MatchUserState)), + (typeof(MatchServerEvent), typeof(MatchServerEvent)), + }; + } +}