From d2361d18de223bf261f379a18f5f1484a5b5eb51 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 9 May 2021 20:31:17 +0200 Subject: [PATCH] Move CustomRpc stuff to different files --- Reactor/Networking/CustomRpc.cs | 191 +++---------------------- Reactor/Networking/CustomRpcManager.cs | 115 +++++++++++++++ Reactor/Networking/PlayerCustomRpc.cs | 38 +++++ Reactor/Networking/UnsafeCustomRpc.cs | 76 ++++++++++ 4 files changed, 245 insertions(+), 175 deletions(-) create mode 100644 Reactor/Networking/CustomRpcManager.cs create mode 100644 Reactor/Networking/PlayerCustomRpc.cs create mode 100644 Reactor/Networking/UnsafeCustomRpc.cs diff --git a/Reactor/Networking/CustomRpc.cs b/Reactor/Networking/CustomRpc.cs index 08eb627..6fdb86c 100644 --- a/Reactor/Networking/CustomRpc.cs +++ b/Reactor/Networking/CustomRpc.cs @@ -1,90 +1,10 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using BepInEx; using BepInEx.IL2CPP; -using HarmonyLib; using Hazel; using InnerNet; namespace Reactor.Networking { - public enum RpcLocalHandling - { - None, - Before, - After - } - - public abstract class UnsafeCustomRpc - { - internal CustomRpcManager Manager { get; set; } - - public uint Id { get; } - public BasePlugin UnsafePlugin { get; } - public string PluginId { get; } - - public abstract Type InnerNetObjectType { get; } - - public virtual SendOption SendOption { get; } = SendOption.Reliable; - public abstract RpcLocalHandling LocalHandling { get; } - - protected UnsafeCustomRpc(BasePlugin plugin, uint id) - { - UnsafePlugin = plugin; - PluginId = MetadataHelper.GetMetadata(plugin).GUID; - Id = id; - } - - public abstract void UnsafeWrite(MessageWriter writer, object data); - public abstract object UnsafeRead(MessageReader reader); - public abstract void UnsafeHandle(InnerNetObject innerNetObject, object data); - - public void UnsafeSend(InnerNetObject netObject, object data, bool immediately = false, int targetClientId = -1) - { - if (netObject == null) throw new ArgumentNullException(nameof(netObject)); - - if (Manager == null) - { - throw new InvalidOperationException("Can't send unregistered CustomRpc"); - } - - if (LocalHandling == RpcLocalHandling.Before) - { - UnsafeHandle(netObject, data); - } - - var writer = immediately switch - { - false => AmongUsClient.Instance.StartRpc(netObject.NetId, CustomRpcManager.CallId, SendOption), - true => AmongUsClient.Instance.StartRpcImmediately(netObject.NetId, CustomRpcManager.CallId, SendOption, targetClientId) - }; - - var pluginNetId = ModList.GetById(PluginId).NetId; - writer.WritePacked(pluginNetId); - writer.WritePacked(Id); - - writer.StartMessage(0); - UnsafeWrite(writer, data); - writer.EndMessage(); - - if (immediately) - { - AmongUsClient.Instance.FinishRpcImmediately(writer); - } - else - { - writer.EndMessage(); - } - - if (LocalHandling == RpcLocalHandling.After) - { - UnsafeHandle(netObject, data); - } - } - } - public abstract class CustomRpc : UnsafeCustomRpc where TPlugin : BasePlugin where TInnerNetObject : InnerNetObject { protected CustomRpc(TPlugin plugin, uint id) : base(plugin, id) @@ -124,118 +44,39 @@ namespace Reactor.Networking } } - public abstract class PlayerCustomRpc : CustomRpc where TPlugin : BasePlugin + public abstract class CustomRpc : UnsafeCustomRpc where TPlugin : BasePlugin where TInnerNetObject : InnerNetObject { - protected PlayerCustomRpc(TPlugin plugin, uint id) : base(plugin, id) + protected CustomRpc(TPlugin plugin, uint id) : base(plugin, id) { } - public void Send(TData data, bool immediately = false) + public TPlugin Plugin => (TPlugin) UnsafePlugin; + public override Type InnerNetObjectType => typeof(TInnerNetObject); + + public abstract void Handle(TInnerNetObject innerNetObject); + + public override void UnsafeWrite(MessageWriter writer, object data) { - Send(PlayerControl.LocalPlayer, data, immediately); } - public void SendTo(int targetId, TData data) + public override object UnsafeRead(MessageReader reader) { - SendTo(PlayerControl.LocalPlayer, targetId, data); - } - } - - public class CustomRpcManager - { - public const byte CallId = byte.MaxValue; - - private readonly List _list = new List(); - private readonly Dictionary> _map = new Dictionary>(); - - public IReadOnlyList List => _list.AsReadOnly(); - - public ILookup Map => - _map.SelectMany(pair => pair.Value, (pair, value) => new { pair.Key, Value = value }) - .ToLookup(pair => pair.Key, pair => pair.Value); - - public CustomRpcManager() - { - foreach (var type in HandleRpcPatch.InnerNetObjectTypes) - { - _map[type] = new List(); - } + return null; } - public UnsafeCustomRpc Register(UnsafeCustomRpc customRpc) + public override void UnsafeHandle(InnerNetObject innerNetObject, object data) { - if (_list.Any(x => x.UnsafePlugin == customRpc.UnsafePlugin && x.Id == customRpc.Id)) - { - throw new ArgumentException("Rpc with that id was already registered"); - } - - customRpc.Manager = this; - _list.Add(customRpc); - _map[customRpc.InnerNetObjectType].Add(customRpc); - - typeof(Rpc<>).MakeGenericType(customRpc.GetType()).GetProperty("Instance")!.SetValue(null, customRpc); - - return customRpc; + Handle((TInnerNetObject) innerNetObject); } - [HarmonyPatch] - private static class HandleRpcPatch + public void Send(InnerNetObject netObject, bool immediately = false) { - internal static List InnerNetObjectTypes { get; } = typeof(InnerNetObject).Assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(InnerNetObject)) && x != typeof(LobbyBehaviour)).ToList(); - - public static IEnumerable TargetMethods() - { - return InnerNetObjectTypes.Select(x => x.GetMethod(nameof(InnerNetObject.HandleRpc), AccessTools.all)); - } - - public static bool Prefix(InnerNetObject __instance, [HarmonyArgument(0)] byte callId, [HarmonyArgument(1)] MessageReader reader) - { - if (callId == CallId) - { - var manager = PluginSingleton.Instance.CustomRpcManager; - var customRpcs = manager.Map[__instance.GetType()]; - - var pluginNetId = reader.ReadPackedUInt32(); - var id = reader.ReadPackedUInt32(); - - var pluginId = ModList.GetByNetId(pluginNetId).Id; - var customRpc = customRpcs.Single(x => x.PluginId == pluginId && x.Id == id); - - customRpc.UnsafeHandle(__instance, customRpc.UnsafeRead(reader.ReadMessage())); - - return false; - } - - return true; - } + UnsafeSend(netObject, immediately); } - } - public static class Rpc where T : UnsafeCustomRpc - { - private static T _instance; - - public static T Instance + public void SendTo(InnerNetObject netObject, int targetId) { - get - { - if (_instance == null) - { - throw new Exception($"{typeof(T).FullName} isn't registered"); - } - - return _instance; - } - - internal set - { - if (_instance != null) - { - throw new Exception($"{typeof(T).FullName} is already registered"); - } - - _instance = value; - } + UnsafeSend(netObject, null, true, targetId); } } } diff --git a/Reactor/Networking/CustomRpcManager.cs b/Reactor/Networking/CustomRpcManager.cs new file mode 100644 index 0000000..a9cd767 --- /dev/null +++ b/Reactor/Networking/CustomRpcManager.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using HarmonyLib; +using Hazel; +using InnerNet; + +namespace Reactor.Networking +{ + public enum RpcLocalHandling + { + None, + Before, + After + } + + public class CustomRpcManager + { + public const byte CallId = byte.MaxValue; + + private readonly List _list = new List(); + private readonly Dictionary> _map = new Dictionary>(); + + public IReadOnlyList List => _list.AsReadOnly(); + + public ILookup Map => + _map.SelectMany(pair => pair.Value, (pair, value) => new { pair.Key, Value = value }) + .ToLookup(pair => pair.Key, pair => pair.Value); + + public CustomRpcManager() + { + foreach (var type in HandleRpcPatch.InnerNetObjectTypes) + { + _map[type] = new List(); + } + } + + public UnsafeCustomRpc Register(UnsafeCustomRpc customRpc) + { + if (_list.Any(x => x.UnsafePlugin == customRpc.UnsafePlugin && x.Id == customRpc.Id)) + { + throw new ArgumentException("Rpc with that id was already registered"); + } + + customRpc.Manager = this; + _list.Add(customRpc); + _map[customRpc.InnerNetObjectType].Add(customRpc); + + typeof(Rpc<>).MakeGenericType(customRpc.GetType()).GetProperty("Instance")!.SetValue(null, customRpc); + + return customRpc; + } + + [HarmonyPatch] + private static class HandleRpcPatch + { + internal static List InnerNetObjectTypes { get; } = typeof(InnerNetObject).Assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(InnerNetObject)) && x != typeof(LobbyBehaviour)).ToList(); + + public static IEnumerable TargetMethods() + { + return InnerNetObjectTypes.Select(x => x.GetMethod(nameof(InnerNetObject.HandleRpc), AccessTools.all)); + } + + public static bool Prefix(InnerNetObject __instance, [HarmonyArgument(0)] byte callId, [HarmonyArgument(1)] MessageReader reader) + { + if (callId == CallId) + { + var manager = PluginSingleton.Instance.CustomRpcManager; + var customRpcs = manager.Map[__instance.GetType()]; + + var pluginNetId = reader.ReadPackedUInt32(); + var id = reader.ReadPackedUInt32(); + + var pluginId = ModList.GetByNetId(pluginNetId).Id; + var customRpc = customRpcs.Single(x => x.PluginId == pluginId && x.Id == id); + + customRpc.UnsafeHandle(__instance, customRpc.UnsafeRead(reader.ReadMessage())); + + return false; + } + + return true; + } + } + } + + public static class Rpc where T : UnsafeCustomRpc + { + private static T _instance; + + public static T Instance + { + get + { + if (_instance == null) + { + throw new Exception($"{typeof(T).FullName} isn't registered"); + } + + return _instance; + } + + internal set + { + if (_instance != null) + { + throw new Exception($"{typeof(T).FullName} is already registered"); + } + + _instance = value; + } + } + } +} diff --git a/Reactor/Networking/PlayerCustomRpc.cs b/Reactor/Networking/PlayerCustomRpc.cs new file mode 100644 index 0000000..ffe9161 --- /dev/null +++ b/Reactor/Networking/PlayerCustomRpc.cs @@ -0,0 +1,38 @@ +using BepInEx.IL2CPP; + +namespace Reactor.Networking +{ + public abstract class PlayerCustomRpc : CustomRpc where TPlugin : BasePlugin + { + protected PlayerCustomRpc(TPlugin plugin, uint id) : base(plugin, id) + { + } + + public void Send(TData data, bool immediately = false) + { + Send(PlayerControl.LocalPlayer, data, immediately); + } + + public void SendTo(int targetId, TData data) + { + SendTo(PlayerControl.LocalPlayer, targetId, data); + } + } + + public abstract class PlayerCustomRpc : CustomRpc where TPlugin : BasePlugin + { + protected PlayerCustomRpc(TPlugin plugin, uint id) : base(plugin, id) + { + } + + public void Send(bool immediately = false) + { + Send(PlayerControl.LocalPlayer, immediately); + } + + public void SendTo(int targetId) + { + SendTo(PlayerControl.LocalPlayer, targetId); + } + } +} diff --git a/Reactor/Networking/UnsafeCustomRpc.cs b/Reactor/Networking/UnsafeCustomRpc.cs new file mode 100644 index 0000000..6a9f806 --- /dev/null +++ b/Reactor/Networking/UnsafeCustomRpc.cs @@ -0,0 +1,76 @@ +using System; +using BepInEx; +using BepInEx.IL2CPP; +using Hazel; +using InnerNet; + +namespace Reactor.Networking +{ + public abstract class UnsafeCustomRpc + { + internal CustomRpcManager Manager { get; set; } + + public uint Id { get; } + public BasePlugin UnsafePlugin { get; } + public string PluginId { get; } + + public abstract Type InnerNetObjectType { get; } + + public virtual SendOption SendOption => SendOption.Reliable; + public abstract RpcLocalHandling LocalHandling { get; } + + protected UnsafeCustomRpc(BasePlugin plugin, uint id) + { + UnsafePlugin = plugin; + PluginId = MetadataHelper.GetMetadata(plugin).GUID; + Id = id; + } + + public abstract void UnsafeWrite(MessageWriter writer, object data); + public abstract object UnsafeRead(MessageReader reader); + public abstract void UnsafeHandle(InnerNetObject innerNetObject, object data); + + public void UnsafeSend(InnerNetObject netObject, object data, bool immediately = false, int targetClientId = -1) + { + if (netObject == null) throw new ArgumentNullException(nameof(netObject)); + + if (Manager == null) + { + throw new InvalidOperationException("Can't send unregistered CustomRpc"); + } + + if (LocalHandling == RpcLocalHandling.Before) + { + UnsafeHandle(netObject, data); + } + + var writer = immediately switch + { + false => AmongUsClient.Instance.StartRpc(netObject.NetId, CustomRpcManager.CallId, SendOption), + true => AmongUsClient.Instance.StartRpcImmediately(netObject.NetId, CustomRpcManager.CallId, SendOption, targetClientId) + }; + + var pluginNetId = ModList.GetById(PluginId).NetId; + writer.WritePacked(pluginNetId); + writer.WritePacked(Id); + + writer.StartMessage(0); + UnsafeWrite(writer, data); + writer.EndMessage(); + + if (immediately) + { + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + else + { + writer.EndMessage(); + } + + if (LocalHandling == RpcLocalHandling.After) + { + UnsafeHandle(netObject, data); + } + } + } +}