From 5004ac8d5b585dcf65b2141657e23fe668679c77 Mon Sep 17 00:00:00 2001 From: js6pak Date: Tue, 23 Aug 2022 21:01:13 +0200 Subject: [PATCH] Reformat code --- Reactor.Debugger/DebuggerPlugin.cs | 183 +++++---- Reactor.Debugger/Patches.cs | 87 +++-- Reactor.Example/CustomRpcs.cs | 11 +- Reactor.Example/ExamplePlugin.cs | 63 ++- Reactor.Example/ExampleRpc.cs | 61 ++- Reactor.Shared/Networking/Mod.cs | 55 ++- .../Networking/ReactorMessageFlags.cs | 13 +- .../Networking/ReactorProtocolVersion.cs | 25 +- Reactor.Shared/PluginSide.cs | 25 +- Reactor/ChainloaderHooks.cs | 43 +-- Reactor/Coroutines.cs | 67 ++-- Reactor/CustomStringName.cs | 73 ++-- Reactor/Extensions/Extensions.cs | 195 +++++----- Reactor/Extensions/ExtraMessageExtensions.cs | 63 ++- Reactor/Extensions/GUIExtensions.cs | 241 ++++++------ Reactor/Extensions/StreamExtensions.cs | 151 ++++---- Reactor/Extensions/UnityObjectExtensions.cs | 59 ++- Reactor/Il2CppEqualityComparer.cs | 57 ++- Reactor/IsExternalInit.cs | 7 +- Reactor/Logger.cs | 33 +- Reactor/Networking/CustomRpc.cs | 131 ++++--- Reactor/Networking/CustomRpcManager.cs | 185 +++++---- Reactor/Networking/MethodRpc/MethodRpc.cs | 363 +++++++++--------- .../MethodRpc/MethodRpcAttribute.cs | 69 ++-- Reactor/Networking/ModDeclaration.cs | 21 +- Reactor/Networking/ModList.cs | 61 ++- Reactor/Networking/ModdedHandshakeC2S.cs | 13 +- Reactor/Networking/ModdedHandshakeS2C.cs | 37 +- Reactor/Networking/Patches/ClientPatches.cs | 275 +++++++------ Reactor/Networking/Patches/ServerPatches.cs | 21 +- Reactor/Networking/PlayerCustomRpc.cs | 53 ++- .../Serialization/InnerNetObjectConverter.cs | 46 ++- .../Serialization/MessageConverter.cs | 35 +- .../MessageConverterAttribute.cs | 49 ++- .../Serialization/MessageSerializer.cs | 277 +++++++------ Reactor/Networking/UnsafeCustomRpc.cs | 105 +++-- Reactor/Patches/BetterGuestPatch.cs | 18 +- Reactor/Patches/CursorPosPatch.cs | 31 +- Reactor/Patches/CustomServersPatch.cs | 47 ++- Reactor/Patches/FreeNamePatch.cs | 114 +++--- Reactor/Patches/PlayerIdPatch.cs | 29 +- Reactor/Patches/ReactorVersionShower.cs | 98 +++-- Reactor/Patches/RegionInfoWatcher.cs | 117 +++--- Reactor/Patches/ServerInfoFixes.cs | 65 ++-- Reactor/Patches/SplashSkip.cs | 57 ++- Reactor/Patches/SteamPatch.cs | 47 ++- Reactor/PluginSingleton.cs | 27 +- Reactor/ReactorPlugin.cs | 147 ++++--- Reactor/ReactorPluginSideAttribute.cs | 45 ++- Reactor/RegisterCustomRpcAttribute.cs | 61 ++- Reactor/RegisterInIl2CppAttribute.cs | 101 +++-- Reactor/Unstrip/DefaultBundle.cs | 49 ++- 52 files changed, 2126 insertions(+), 2180 deletions(-) diff --git a/Reactor.Debugger/DebuggerPlugin.cs b/Reactor.Debugger/DebuggerPlugin.cs index 1587756..61d42b5 100644 --- a/Reactor.Debugger/DebuggerPlugin.cs +++ b/Reactor.Debugger/DebuggerPlugin.cs @@ -9,110 +9,109 @@ using UnhollowerBaseLib; using UnhollowerBaseLib.Attributes; using UnityEngine; -namespace Reactor.Debugger +namespace Reactor.Debugger; + +[BepInAutoPlugin("gg.reactor.debugger")] +[BepInProcess("Among Us.exe")] +[BepInDependency(ReactorPlugin.Id)] +[ReactorPluginSide(PluginSide.ClientOnly)] +public partial class DebuggerPlugin : BasePlugin { - [BepInAutoPlugin("gg.reactor.debugger")] - [BepInProcess("Among Us.exe")] - [BepInDependency(ReactorPlugin.Id)] - [ReactorPluginSide(PluginSide.ClientOnly)] - public partial class DebuggerPlugin : BasePlugin + public Harmony Harmony { get; } = new(Id); + public DebuggerComponent Component { get; private set; } + + public override void Load() { - public Harmony Harmony { get; } = new Harmony(Id); - public DebuggerComponent Component { get; private set; } + Component = this.AddComponent(); - public override void Load() + GameOptionsData.MaxImpostors = GameOptionsData.RecommendedImpostors = Enumerable.Repeat((int) byte.MaxValue, byte.MaxValue).ToArray(); + GameOptionsData.MinPlayers = Enumerable.Repeat(1, 4).ToArray(); + + Harmony.PatchAll(); + } + + [RegisterInIl2Cpp] + public class DebuggerComponent : MonoBehaviour + { + [HideFromIl2Cpp] + public bool DisableGameEnd { get; set; } + + [HideFromIl2Cpp] + public DragWindow TestWindow { get; } + + public DebuggerComponent(IntPtr ptr) : base(ptr) { - Component = this.AddComponent(); + TestWindow = new DragWindow(new Rect(20, 20, 0, 0), "Debugger", () => + { + GUILayout.Label("Name: " + SaveManager.PlayerName); + DisableGameEnd = GUILayout.Toggle(DisableGameEnd, "Disable game end"); - GameOptionsData.MaxImpostors = GameOptionsData.RecommendedImpostors = Enumerable.Repeat((int) byte.MaxValue, byte.MaxValue).ToArray(); - GameOptionsData.MinPlayers = Enumerable.Repeat(1, 4).ToArray(); + if (ShipStatus.Instance && AmongUsClient.Instance.AmHost) + { + if (GUILayout.Button("Force game end")) + { + ShipStatus.Instance.enabled = false; + ShipStatus.RpcEndGame(GameOverReason.ImpostorDisconnect, false); + } - Harmony.PatchAll(); + if (GUILayout.Button("Call a meeting")) + { + PlayerControl.LocalPlayer.CmdReportDeadBody(null); + } + } + + if (TutorialManager.InstanceExists && PlayerControl.LocalPlayer) + { + var data = PlayerControl.LocalPlayer.Data; + + var newIsImpostor = GUILayout.Toggle(data.Role.IsImpostor, "Is Impostor"); + if (data.Role.IsImpostor != newIsImpostor) + { + PlayerControl.LocalPlayer.RpcSetRole(newIsImpostor ? RoleTypes.Impostor : RoleTypes.Crewmate); + } + + if (GUILayout.Button("Spawn a dummy")) + { + var playerControl = Instantiate(TutorialManager.Instance.PlayerPrefab); + var i = playerControl.PlayerId = (byte) GameData.Instance.GetAvailableId(); + GameData.Instance.AddPlayer(playerControl); + AmongUsClient.Instance.Spawn(playerControl, -2, SpawnFlags.None); + playerControl.transform.position = PlayerControl.LocalPlayer.transform.position; + playerControl.GetComponent().enabled = true; + playerControl.NetTransform.enabled = false; + playerControl.SetName($"{TranslationController.Instance.GetString(StringNames.Dummy, Array.Empty())} {i}"); + var color = (byte) (i % Palette.PlayerColors.Length); + playerControl.SetColor(color); + playerControl.SetHat(HatManager.Instance.allHats[i % HatManager.Instance.allHats.Count].ProdId, playerControl.Data.DefaultOutfit.ColorId); + playerControl.SetPet(HatManager.Instance.allPets[i % HatManager.Instance.allPets.Count].ProdId); + playerControl.SetSkin(HatManager.Instance.allSkins[i % HatManager.Instance.allSkins.Count].ProdId, color); + GameData.Instance.RpcSetTasks(playerControl.PlayerId, new Il2CppStructArray(0)); + } + } + + if (PlayerControl.LocalPlayer) + { + var position = PlayerControl.LocalPlayer.transform.position; + GUILayout.Label($"x: {position.x}"); + GUILayout.Label($"y: {position.y}"); + } + }) + { + Enabled = false, + }; } - [RegisterInIl2Cpp] - public class DebuggerComponent : MonoBehaviour + private void Update() { - [HideFromIl2Cpp] - public bool DisableGameEnd { get; set; } - - [HideFromIl2Cpp] - public DragWindow TestWindow { get; } - - public DebuggerComponent(IntPtr ptr) : base(ptr) + if (Input.GetKeyDown(KeyCode.F1)) { - TestWindow = new DragWindow(new Rect(20, 20, 0, 0), "Debugger", () => - { - GUILayout.Label("Name: " + SaveManager.PlayerName); - DisableGameEnd = GUILayout.Toggle(DisableGameEnd, "Disable game end"); - - if (ShipStatus.Instance && AmongUsClient.Instance.AmHost) - { - if (GUILayout.Button("Force game end")) - { - ShipStatus.Instance.enabled = false; - ShipStatus.RpcEndGame(GameOverReason.ImpostorDisconnect, false); - } - - if (GUILayout.Button("Call a meeting")) - { - PlayerControl.LocalPlayer.CmdReportDeadBody(null); - } - } - - if (TutorialManager.InstanceExists && PlayerControl.LocalPlayer) - { - var data = PlayerControl.LocalPlayer.Data; - - var newIsImpostor = GUILayout.Toggle(data.Role.IsImpostor, "Is Impostor"); - if (data.Role.IsImpostor != newIsImpostor) - { - PlayerControl.LocalPlayer.RpcSetRole(newIsImpostor ? RoleTypes.Impostor : RoleTypes.Crewmate); - } - - if (GUILayout.Button("Spawn a dummy")) - { - var playerControl = Instantiate(TutorialManager.Instance.PlayerPrefab); - var i = playerControl.PlayerId = (byte) GameData.Instance.GetAvailableId(); - GameData.Instance.AddPlayer(playerControl); - AmongUsClient.Instance.Spawn(playerControl, -2, SpawnFlags.None); - playerControl.transform.position = PlayerControl.LocalPlayer.transform.position; - playerControl.GetComponent().enabled = true; - playerControl.NetTransform.enabled = false; - playerControl.SetName($"{TranslationController.Instance.GetString(StringNames.Dummy, Array.Empty())} {i}"); - var color = (byte) (i % Palette.PlayerColors.Length); - playerControl.SetColor(color); - playerControl.SetHat(HatManager.Instance.allHats[i % HatManager.Instance.allHats.Count].ProdId, playerControl.Data.DefaultOutfit.ColorId); - playerControl.SetPet(HatManager.Instance.allPets[i % HatManager.Instance.allPets.Count].ProdId); - playerControl.SetSkin(HatManager.Instance.allSkins[i % HatManager.Instance.allSkins.Count].ProdId, color); - GameData.Instance.RpcSetTasks(playerControl.PlayerId, new Il2CppStructArray(0)); - } - } - - if (PlayerControl.LocalPlayer) - { - var position = PlayerControl.LocalPlayer.transform.position; - GUILayout.Label($"x: {position.x}"); - GUILayout.Label($"y: {position.y}"); - } - }) - { - Enabled = false - }; + TestWindow.Enabled = !TestWindow.Enabled; } + } - private void Update() - { - if (Input.GetKeyDown(KeyCode.F1)) - { - TestWindow.Enabled = !TestWindow.Enabled; - } - } - - private void OnGUI() - { - TestWindow.OnGUI(); - } + private void OnGUI() + { + TestWindow.OnGUI(); } } } diff --git a/Reactor.Debugger/Patches.cs b/Reactor.Debugger/Patches.cs index 0a01865..210f622 100644 --- a/Reactor.Debugger/Patches.cs +++ b/Reactor.Debugger/Patches.cs @@ -3,68 +3,67 @@ using HarmonyLib; using UnhollowerBaseLib; using UnityEngine; -namespace Reactor.Debugger +namespace Reactor.Debugger; + +internal static class Patches { - internal static class Patches + [HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Update))] + public static class UpdatePatch { - [HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Update))] - public static class UpdatePatch + public static void Prefix(GameStartManager __instance) { - public static void Prefix(GameStartManager __instance) - { - __instance.MinPlayers = 1; - } + __instance.MinPlayers = 1; } + } - [HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Update))] - public static class CountdownPatch + [HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Update))] + public static class CountdownPatch + { + public static void Prefix(GameStartManager __instance) { - public static void Prefix(GameStartManager __instance) - { - __instance.countDownTimer = 0; - } + __instance.countDownTimer = 0; } + } - [HarmonyPatch(typeof(StatsManager), nameof(StatsManager.AmBanned), MethodType.Getter)] - public static class AmBannedPatch + [HarmonyPatch(typeof(StatsManager), nameof(StatsManager.AmBanned), MethodType.Getter)] + public static class AmBannedPatch + { + public static void Postfix(out bool __result) { - public static void Postfix(out bool __result) - { - __result = false; - } + __result = false; } + } - [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.CheckEndCriteria))] - [HarmonyPriority(Priority.First)] - public static class CheckEndCriteriaPatch + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.CheckEndCriteria))] + [HarmonyPriority(Priority.First)] + public static class CheckEndCriteriaPatch + { + public static bool Prefix() { - public static bool Prefix() - { - return !PluginSingleton.Instance.Component.DisableGameEnd; - } + return !PluginSingleton.Instance.Component.DisableGameEnd; } + } - [HarmonyPatch(typeof(GameSettingMenu), nameof(GameSettingMenu.Start))] - public static class GameSettingMenuPatch + [HarmonyPatch(typeof(GameSettingMenu), nameof(GameSettingMenu.Start))] + public static class GameSettingMenuPatch + { + public static void Prefix(GameSettingMenu __instance) { - public static void Prefix(GameSettingMenu __instance) - { - // Unlocks map/impostor amount changing in online (for testing on your custom servers) - __instance.HideForOnline = new Il2CppReferenceArray(0); - } + // Unlocks map/impostor amount changing in online (for testing on your custom servers) + __instance.HideForOnline = new Il2CppReferenceArray(0); } + } - [HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.Start))] - [HarmonyPriority(Priority.First)] - public static class GameOptionsMenuPatch + [HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.Start))] + [HarmonyPriority(Priority.First)] + public static class GameOptionsMenuPatch + { + public static void Postfix(GameOptionsMenu __instance) { - public static void Postfix(GameOptionsMenu __instance) - { - __instance.Children - .Single(o => o.Title == StringNames.GameNumImpostors) - .Cast() - .ValidRange = new FloatRange(0, byte.MaxValue); - } + __instance.Children + .Single(o => o.Title == StringNames.GameNumImpostors) + .Cast() + .ValidRange = new FloatRange(0, byte.MaxValue); } } } diff --git a/Reactor.Example/CustomRpcs.cs b/Reactor.Example/CustomRpcs.cs index 975da54..8adea47 100644 --- a/Reactor.Example/CustomRpcs.cs +++ b/Reactor.Example/CustomRpcs.cs @@ -1,8 +1,7 @@ -namespace Reactor.Example +namespace Reactor.Example; + +public enum CustomRpcCalls : uint { - public enum CustomRpcCalls : uint - { - Example, - MethodRpcExample - } + Example, + MethodRpcExample, } diff --git a/Reactor.Example/ExamplePlugin.cs b/Reactor.Example/ExamplePlugin.cs index 63a1bc5..34d7a1a 100644 --- a/Reactor.Example/ExamplePlugin.cs +++ b/Reactor.Example/ExamplePlugin.cs @@ -8,52 +8,51 @@ using UnhollowerBaseLib.Attributes; using UnityEngine; using Random = UnityEngine.Random; -namespace Reactor.Example +namespace Reactor.Example; + +[BepInAutoPlugin("gg.reactor.Example")] +[BepInProcess("Among Us.exe")] +[BepInDependency(ReactorPlugin.Id)] +public partial class ExamplePlugin : BasePlugin { - [BepInAutoPlugin("gg.reactor.Example")] - [BepInProcess("Among Us.exe")] - [BepInDependency(ReactorPlugin.Id)] - public partial class ExamplePlugin : BasePlugin + public override void Load() { - public override void Load() + this.AddComponent(); + } + + [RegisterInIl2Cpp] + public class ExampleComponent : MonoBehaviour + { + public ExampleComponent(IntPtr ptr) : base(ptr) { - this.AddComponent(); } - [RegisterInIl2Cpp] - public class ExampleComponent : MonoBehaviour + private void Update() { - public ExampleComponent(IntPtr ptr) : base(ptr) + if (AmongUsClient.Instance && PlayerControl.LocalPlayer) { - } - - private void Update() - { - if (AmongUsClient.Instance && PlayerControl.LocalPlayer) + if (Input.GetKeyDown(KeyCode.F3)) { - if (Input.GetKeyDown(KeyCode.F3)) - { - var name = PlayerControl.LocalPlayer.Data.PlayerName; - Rpc.Instance.Send(new ExampleRpc.Data($"Send: from {name}")); + var name = PlayerControl.LocalPlayer.Data.PlayerName; + Rpc.Instance.Send(new ExampleRpc.Data($"Send: from {name}")); - if (!AmongUsClient.Instance.AmHost) - { - Rpc.Instance.SendTo(AmongUsClient.Instance.HostId, new ExampleRpc.Data($"SendTo: from {name} to host")); - } - } - - if (Input.GetKeyDown(KeyCode.F4)) + if (!AmongUsClient.Instance.AmHost) { - RpcSay(PlayerControl.LocalPlayer, "Hello from method rpc", Random.value, PlayerControl.LocalPlayer); + Rpc.Instance.SendTo(AmongUsClient.Instance.HostId, new ExampleRpc.Data($"SendTo: from {name} to host")); } } + + if (Input.GetKeyDown(KeyCode.F4)) + { + RpcSay(PlayerControl.LocalPlayer, "Hello from method rpc", Random.value, PlayerControl.LocalPlayer); + } } } + } - [MethodRpc((uint) CustomRpcCalls.MethodRpcExample)] - public static void RpcSay(PlayerControl player, string text, float number, PlayerControl testPlayer) - { - Logger.Info($"{player.Data.PlayerName} text: {text} number: {number} testPlayer: {testPlayer.NetId}"); - } + [MethodRpc((uint) CustomRpcCalls.MethodRpcExample)] + public static void RpcSay(PlayerControl player, string text, float number, PlayerControl testPlayer) + { + Logger.Info($"{player.Data.PlayerName} text: {text} number: {number} testPlayer: {testPlayer.NetId}"); } } diff --git a/Reactor.Example/ExampleRpc.cs b/Reactor.Example/ExampleRpc.cs index dfc18e3..b068e6e 100644 --- a/Reactor.Example/ExampleRpc.cs +++ b/Reactor.Example/ExampleRpc.cs @@ -1,40 +1,39 @@ using Hazel; using Reactor.Networking; -namespace Reactor.Example +namespace Reactor.Example; + +[RegisterCustomRpc((uint) CustomRpcCalls.Example)] +public class ExampleRpc : PlayerCustomRpc { - [RegisterCustomRpc((uint) CustomRpcCalls.Example)] - public class ExampleRpc : PlayerCustomRpc + public ExampleRpc(ExamplePlugin plugin, uint id) : base(plugin, id) { - public ExampleRpc(ExamplePlugin plugin, uint id) : base(plugin, id) + } + + public readonly struct Data + { + public readonly string Message; + + public Data(string message) { - } - - public readonly struct Data - { - public readonly string Message; - - public Data(string message) - { - Message = message; - } - } - - public override RpcLocalHandling LocalHandling => RpcLocalHandling.None; - - public override void Write(MessageWriter writer, Data data) - { - writer.Write(data.Message); - } - - public override Data Read(MessageReader reader) - { - return new Data(reader.ReadString()); - } - - public override void Handle(PlayerControl innerNetObject, Data data) - { - Plugin.Log.LogWarning($"Handle: {innerNetObject.Data.PlayerName} sent \"{data.Message}\""); + Message = message; } } + + public override RpcLocalHandling LocalHandling => RpcLocalHandling.None; + + public override void Write(MessageWriter writer, Data data) + { + writer.Write(data.Message); + } + + public override Data Read(MessageReader reader) + { + return new Data(reader.ReadString()); + } + + public override void Handle(PlayerControl innerNetObject, Data data) + { + Plugin.Log.LogWarning($"Handle: {innerNetObject.Data.PlayerName} sent \"{data.Message}\""); + } } diff --git a/Reactor.Shared/Networking/Mod.cs b/Reactor.Shared/Networking/Mod.cs index 4f58f79..ef3a106 100644 --- a/Reactor.Shared/Networking/Mod.cs +++ b/Reactor.Shared/Networking/Mod.cs @@ -2,39 +2,38 @@ using System; -namespace Reactor.Networking +namespace Reactor.Networking; + +public class Mod { - public class Mod + public Mod(uint netId, string id, string version, PluginSide side) { - public Mod(uint netId, string id, string version, PluginSide side) - { - NetId = netId; - Id = id; - Version = version; - Side = side; - } + NetId = netId; + Id = id; + Version = version; + Side = side; + } - public uint NetId { get; } - public string Id { get; } - public string Version { get; } - public PluginSide Side { get; } + public uint NetId { get; } + public string Id { get; } + public string Version { get; } + public PluginSide Side { get; } - protected bool Equals(Mod other) - { - return Id == other.Id && Version == other.Version; - } + protected bool Equals(Mod other) + { + return Id == other.Id && Version == other.Version; + } - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((Mod) obj); - } + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((Mod) obj); + } - public override int GetHashCode() - { - return HashCode.Combine(Id, Version); - } + public override int GetHashCode() + { + return HashCode.Combine(Id, Version); } } diff --git a/Reactor.Shared/Networking/ReactorMessageFlags.cs b/Reactor.Shared/Networking/ReactorMessageFlags.cs index 4e7462a..372971e 100644 --- a/Reactor.Shared/Networking/ReactorMessageFlags.cs +++ b/Reactor.Shared/Networking/ReactorMessageFlags.cs @@ -1,9 +1,8 @@ -namespace Reactor.Networking +namespace Reactor.Networking; + +public enum ReactorMessageFlags : byte { - public enum ReactorMessageFlags : byte - { - Handshake, - ModDeclaration, - PluginDeclaration - } + Handshake, + ModDeclaration, + PluginDeclaration, } diff --git a/Reactor.Shared/Networking/ReactorProtocolVersion.cs b/Reactor.Shared/Networking/ReactorProtocolVersion.cs index dde00fe..cca0ad4 100644 --- a/Reactor.Shared/Networking/ReactorProtocolVersion.cs +++ b/Reactor.Shared/Networking/ReactorProtocolVersion.cs @@ -1,18 +1,17 @@ -namespace Reactor.Networking +namespace Reactor.Networking; + +/// +/// Version of the Reactor.Net protocol format. +/// +public enum ReactorProtocolVersion : byte { /// - /// Version of the Reactor.Net protocol format. + /// Initial version. /// - public enum ReactorProtocolVersion : byte - { - /// - /// Initial version. - /// - Initial = 1, + Initial = 1, - /// - /// Latest version. - /// - Latest = Initial, - } + /// + /// Latest version. + /// + Latest = Initial, } diff --git a/Reactor.Shared/PluginSide.cs b/Reactor.Shared/PluginSide.cs index f895e30..f7fb1db 100644 --- a/Reactor.Shared/PluginSide.cs +++ b/Reactor.Shared/PluginSide.cs @@ -1,18 +1,17 @@ -namespace Reactor +namespace Reactor; + +/// +/// Plugin side used in modded handshake +/// +public enum PluginSide : byte { /// - /// Plugin side used in modded handshake + /// Required by both sides, reject connection if missing on the other side /// - public enum PluginSide : byte - { - /// - /// Required by both sides, reject connection if missing on the other side - /// - Both, + Both, - /// - /// Required only by client - /// - ClientOnly - } + /// + /// Required only by client + /// + ClientOnly, } diff --git a/Reactor/ChainloaderHooks.cs b/Reactor/ChainloaderHooks.cs index ffc170b..2f99ec2 100644 --- a/Reactor/ChainloaderHooks.cs +++ b/Reactor/ChainloaderHooks.cs @@ -3,32 +3,31 @@ using System.Reflection.Emit; using BepInEx.IL2CPP; using HarmonyLib; -namespace Reactor +namespace Reactor; + +public static class ChainloaderHooks { - public static class ChainloaderHooks + public delegate void PluginLoadHandler(BasePlugin plugin); + + public static event PluginLoadHandler? PluginLoad; + + internal static void OnPluginLoad(BasePlugin plugin) { - public delegate void PluginLoadHandler(BasePlugin plugin); + PluginLoad?.Invoke(plugin); + } - public static event PluginLoadHandler? PluginLoad; - - internal static void OnPluginLoad(BasePlugin plugin) + [HarmonyPatch(typeof(IL2CPPChainloader), nameof(IL2CPPChainloader.LoadPlugin))] + private static class LoadPluginPatch + { + public static IEnumerable Transpiler(IEnumerable instructions) { - PluginLoad?.Invoke(plugin); - } - - [HarmonyPatch(typeof(IL2CPPChainloader), nameof(IL2CPPChainloader.LoadPlugin))] - private static class LoadPluginPatch - { - public static IEnumerable Transpiler(IEnumerable instructions) - { - return new CodeMatcher(instructions) - .MatchForward(false, new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(BasePlugin), nameof(BasePlugin.Load)))) - .Insert( - new CodeInstruction(OpCodes.Dup), - new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(ChainloaderHooks), nameof(OnPluginLoad))) - ) - .InstructionEnumeration(); - } + return new CodeMatcher(instructions) + .MatchForward(false, new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(BasePlugin), nameof(BasePlugin.Load)))) + .Insert( + new CodeInstruction(OpCodes.Dup), + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(ChainloaderHooks), nameof(OnPluginLoad))) + ) + .InstructionEnumeration(); } } } diff --git a/Reactor/Coroutines.cs b/Reactor/Coroutines.cs index 53cb0f1..366ea52 100644 --- a/Reactor/Coroutines.cs +++ b/Reactor/Coroutines.cs @@ -5,49 +5,48 @@ using System.Runtime.CompilerServices; using BepInEx.IL2CPP.Utils; using UnityEngine; -namespace Reactor +namespace Reactor; + +public static class Coroutines { - public static class Coroutines + [RegisterInIl2Cpp] + internal class Component : MonoBehaviour { - [RegisterInIl2Cpp] - internal class Component : MonoBehaviour + internal static Component? Instance { get; set; } + + public Component(IntPtr ptr) : base(ptr) { - internal static Component? Instance { get; set; } - - public Component(IntPtr ptr) : base(ptr) - { - } - - private void Awake() - { - Instance = this; - } - - private void OnDestroy() - { - Instance = null; - } } - private static readonly ConditionalWeakTable _ourCoroutineStore = new(); - - [return: NotNullIfNotNull("routine")] - public static IEnumerator? Start(IEnumerator? routine) + private void Awake() { - if (routine != null) - { - _ourCoroutineStore.AddOrUpdate(routine, Component.Instance!.StartCoroutine(routine)); - } - - return routine; + Instance = this; } - public static void Stop(IEnumerator? enumerator) + private void OnDestroy() { - if (enumerator != null && _ourCoroutineStore.TryGetValue(enumerator, out var routine)) - { - Component.Instance!.StopCoroutine(routine); - } + Instance = null; + } + } + + private static readonly ConditionalWeakTable _ourCoroutineStore = new(); + + [return: NotNullIfNotNull("routine")] + public static IEnumerator? Start(IEnumerator? routine) + { + if (routine != null) + { + _ourCoroutineStore.AddOrUpdate(routine, Component.Instance!.StartCoroutine(routine)); + } + + return routine; + } + + public static void Stop(IEnumerator? enumerator) + { + if (enumerator != null && _ourCoroutineStore.TryGetValue(enumerator, out var routine)) + { + Component.Instance!.StopCoroutine(routine); } } } diff --git a/Reactor/CustomStringName.cs b/Reactor/CustomStringName.cs index 5534369..15fbd9d 100644 --- a/Reactor/CustomStringName.cs +++ b/Reactor/CustomStringName.cs @@ -3,52 +3,51 @@ using System.Linq; using HarmonyLib; using UnhollowerBaseLib; -namespace Reactor +namespace Reactor; + +public class CustomStringName { - public class CustomStringName + private static int _lastId = -1; + + private static readonly List _list = new(); + + public static IReadOnlyList List => _list.AsReadOnly(); + + public static CustomStringName Register(string value) { - private static int _lastId = -1; + var customStringName = new CustomStringName(_lastId--, value); + _list.Add(customStringName); - private static readonly List _list = new List(); + return customStringName; + } - public static IReadOnlyList List => _list.AsReadOnly(); + public int Id { get; } - public static CustomStringName Register(string value) + public string Value { get; } + + private CustomStringName(int id, string value) + { + Id = id; + Value = value; + } + + public static implicit operator StringNames(CustomStringName name) => (StringNames) name.Id; + public static explicit operator CustomStringName?(StringNames name) => List.SingleOrDefault(x => x.Id == (int) name); + + [HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), typeof(StringNames), typeof(Il2CppReferenceArray))] + private static class GetStringPatch + { + public static bool Prefix(StringNames id, Il2CppReferenceArray parts, ref string __result) { - var customStringName = new CustomStringName(_lastId--, value); - _list.Add(customStringName); + var customStringName = (CustomStringName?) id; - return customStringName; - } - - public int Id { get; } - - public string Value { get; } - - private CustomStringName(int id, string value) - { - Id = id; - Value = value; - } - - public static implicit operator StringNames(CustomStringName name) => (StringNames) name.Id; - public static explicit operator CustomStringName?(StringNames name) => List.SingleOrDefault(x => x.Id == (int) name); - - [HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), typeof(StringNames), typeof(Il2CppReferenceArray))] - private static class GetStringPatch - { - public static bool Prefix(StringNames id, Il2CppReferenceArray parts, ref string __result) + if (customStringName != null) { - var customStringName = (CustomStringName?) id; - - if (customStringName != null) - { - __result = string.Format(customStringName.Value, parts); - return false; - } - - return true; + __result = string.Format(customStringName.Value, parts); + return false; } + + return true; } } } diff --git a/Reactor/Extensions/Extensions.cs b/Reactor/Extensions/Extensions.cs index 85682d3..6f55f7a 100644 --- a/Reactor/Extensions/Extensions.cs +++ b/Reactor/Extensions/Extensions.cs @@ -11,113 +11,112 @@ using UnityEngine.Networking; using UnityEngine.SceneManagement; using Il2CppType = UnhollowerRuntimeLib.Il2CppType; -namespace Reactor.Extensions +namespace Reactor.Extensions; + +/// +/// General utilities +/// +public static class Extensions { /// - /// General utilities + /// Adds a delegate to get one notification when a scene has loaded. /// - public static class Extensions + public static void once_sceneLoaded(Action value) { - /// - /// Adds a delegate to get one notification when a scene has loaded. - /// - public static void once_sceneLoaded(Action value) + UnityAction? unityAction = null; + + unityAction = (Action) ((scene, loadMode) => { - UnityAction? unityAction = null; + SceneManager.remove_sceneLoaded(unityAction); + value.Invoke(scene, loadMode); + }); - unityAction = (Action) ((scene, loadMode) => - { - SceneManager.remove_sceneLoaded(unityAction); - value.Invoke(scene, loadMode); - }); + SceneManager.add_sceneLoaded(unityAction); + } - SceneManager.add_sceneLoaded(unityAction); - } + /// + /// Returns random from + /// + public static T? Random(this IEnumerable input) + { + var list = input as IList ?? input.ToList(); + return list.Count == 0 ? default : list[UnityEngine.Random.Range(0, list.Count)]; + } - /// - /// Returns random from - /// - public static T? Random(this IEnumerable input) + /// + /// Returns the color as a hexadecimal string in the format "RRGGBBAA". + /// + /// The color to be converted. + /// Hexadecimal string representing the color. + /// https://docs.unity3d.com/ScriptReference/ColorUtility.ToHtmlStringRGBA.html + public static string ToHtmlStringRGBA(this Color32 color) + { + return $"{color.r:X2}{color.g:X2}{color.b:X2}{color.a:X2}"; + } + + /// + public static string ToHtmlStringRGBA(this Color color) + { + return ((Color32) color).ToHtmlStringRGBA(); + } + + /// + /// Fully read stream, can be used as workaround for il2cpp streams. + /// + public static byte[] ReadFully(this Stream input) + { + using (var ms = new MemoryStream()) { - var list = input as IList ?? input.ToList(); - return list.Count == 0 ? default : list[UnityEngine.Random.Range(0, list.Count)]; - } - - /// - /// Returns the color as a hexadecimal string in the format "RRGGBBAA". - /// - /// The color to be converted. - /// Hexadecimal string representing the color. - /// https://docs.unity3d.com/ScriptReference/ColorUtility.ToHtmlStringRGBA.html - public static string ToHtmlStringRGBA(this Color32 color) - { - return $"{color.r:X2}{color.g:X2}{color.b:X2}{color.a:X2}"; - } - - /// - public static string ToHtmlStringRGBA(this Color color) - { - return ((Color32) color).ToHtmlStringRGBA(); - } - - /// - /// Fully read stream, can be used as workaround for il2cpp streams. - /// - public static byte[] ReadFully(this Stream input) - { - using (var ms = new MemoryStream()) - { - input.CopyTo(ms); - return ms.ToArray(); - } - } - - /// - /// Sends and return task that finishes on completion. - /// - public static Task SendAsync(this UnityWebRequest request) - { - var task = new TaskCompletionSource(); - - request.Send().m_completeCallback = (Action) (_ => - { - task.SetResult(null); - }); - - return task.Task; - } - - private static readonly int _outline = Shader.PropertyToID("_Outline"); - private static readonly int _outlineColor = Shader.PropertyToID("_OutlineColor"); - private static readonly int _addColor = Shader.PropertyToID("_AddColor"); - - /// - /// Sets color outline for renderers using default Among Us shader - /// - public static void SetOutline(this Renderer renderer, Color? color) - { - renderer.material.SetFloat(_outline, color.HasValue ? 1 : 0); - - if (color.HasValue) - { - renderer.material.SetColor(_outlineColor, color.Value); - renderer.material.SetColor(_addColor, color.Value); - } - } - - public static IEnumerable GetMethods(this Type type, BindingFlags bindingAttr, Type returnType, params Type[] parameterTypes) - { - return type.GetMethods(bindingAttr).Where(x => x.ReturnType == returnType && x.GetParameters().Select(x => x.ParameterType).SequenceEqual(parameterTypes)); - } - - public static IEnumerable GetMethods(this Type type, Type returnType, params Type[] parameterTypes) - { - return type.GetMethods(AccessTools.all, returnType, parameterTypes); - } - - public static T? LoadAsset(this AssetBundle assetBundle, string name) where T : UnityEngine.Object - { - return assetBundle.LoadAsset(name, Il2CppType.Of())?.Cast(); + input.CopyTo(ms); + return ms.ToArray(); } } + + /// + /// Sends and return task that finishes on completion. + /// + public static Task SendAsync(this UnityWebRequest request) + { + var task = new TaskCompletionSource(); + + request.Send().m_completeCallback = (Action) (_ => + { + task.SetResult(null); + }); + + return task.Task; + } + + private static readonly int _outline = Shader.PropertyToID("_Outline"); + private static readonly int _outlineColor = Shader.PropertyToID("_OutlineColor"); + private static readonly int _addColor = Shader.PropertyToID("_AddColor"); + + /// + /// Sets color outline for renderers using default Among Us shader + /// + public static void SetOutline(this Renderer renderer, Color? color) + { + renderer.material.SetFloat(_outline, color.HasValue ? 1 : 0); + + if (color.HasValue) + { + renderer.material.SetColor(_outlineColor, color.Value); + renderer.material.SetColor(_addColor, color.Value); + } + } + + public static IEnumerable GetMethods(this Type type, BindingFlags bindingAttr, Type returnType, params Type[] parameterTypes) + { + return type.GetMethods(bindingAttr).Where(x => x.ReturnType == returnType && x.GetParameters().Select(x => x.ParameterType).SequenceEqual(parameterTypes)); + } + + public static IEnumerable GetMethods(this Type type, Type returnType, params Type[] parameterTypes) + { + return type.GetMethods(AccessTools.all, returnType, parameterTypes); + } + + public static T? LoadAsset(this AssetBundle assetBundle, string name) where T : UnityEngine.Object + { + return assetBundle.LoadAsset(name, Il2CppType.Of())?.Cast(); + } } diff --git a/Reactor/Extensions/ExtraMessageExtensions.cs b/Reactor/Extensions/ExtraMessageExtensions.cs index 879ff06..2d48010 100644 --- a/Reactor/Extensions/ExtraMessageExtensions.cs +++ b/Reactor/Extensions/ExtraMessageExtensions.cs @@ -3,47 +3,46 @@ using Hazel; using Hazel.Udp; using UnityEngine; -namespace Reactor.Extensions +namespace Reactor.Extensions; + +public static class ExtraMessageExtensions { - public static class ExtraMessageExtensions + private const float MIN = -50f; + private const float MAX = 50f; + + private static float ReverseLerp(float t) { - private const float MIN = -50f; - private const float MAX = 50f; + return Mathf.Clamp((t - MIN) / (MAX - MIN), 0f, 1f); + } - private static float ReverseLerp(float t) - { - return Mathf.Clamp((t - MIN) / (MAX - MIN), 0f, 1f); - } + public static void Write(this MessageWriter writer, Vector2 value) + { + var x = (ushort) (ReverseLerp(value.x) * ushort.MaxValue); + var y = (ushort) (ReverseLerp(value.y) * ushort.MaxValue); - public static void Write(this MessageWriter writer, Vector2 value) - { - var x = (ushort) (ReverseLerp(value.x) * ushort.MaxValue); - var y = (ushort) (ReverseLerp(value.y) * ushort.MaxValue); + writer.Write(x); + writer.Write(y); + } - writer.Write(x); - writer.Write(y); - } + public static Vector2 ReadVector2(this MessageReader reader) + { + var x = reader.ReadUInt16() / (float) ushort.MaxValue; + var y = reader.ReadUInt16() / (float) ushort.MaxValue; - public static Vector2 ReadVector2(this MessageReader reader) - { - var x = reader.ReadUInt16() / (float) ushort.MaxValue; - var y = reader.ReadUInt16() / (float) ushort.MaxValue; + return new Vector2(Mathf.Lerp(MIN, MAX, x), Mathf.Lerp(MIN, MAX, y)); + } - return new Vector2(Mathf.Lerp(MIN, MAX, x), Mathf.Lerp(MIN, MAX, y)); - } + public static void Send(this UdpConnection connection, MessageWriter msg, Action ackCallback) + { + if (msg.SendOption != SendOption.Reliable) + throw new InvalidOperationException("Message SendOption has to be Reliable."); - public static void Send(this UdpConnection connection, MessageWriter msg, Action ackCallback) - { - if (msg.SendOption != SendOption.Reliable) - throw new InvalidOperationException("Message SendOption has to be Reliable."); + var buffer = new byte[msg.Length]; + Buffer.BlockCopy(msg.Buffer, 0, buffer, 0, msg.Length); - var buffer = new byte[msg.Length]; - Buffer.BlockCopy(msg.Buffer, 0, buffer, 0, msg.Length); + connection.ResetKeepAliveTimer(); - connection.ResetKeepAliveTimer(); - - connection.AttachReliableID(buffer, 1, ackCallback); - connection.WriteBytesToConnection(buffer, buffer.Length); - } + connection.AttachReliableID(buffer, 1, ackCallback); + connection.WriteBytesToConnection(buffer, buffer.Length); } } diff --git a/Reactor/Extensions/GUIExtensions.cs b/Reactor/Extensions/GUIExtensions.cs index 385c610..c6658eb 100644 --- a/Reactor/Extensions/GUIExtensions.cs +++ b/Reactor/Extensions/GUIExtensions.cs @@ -4,146 +4,145 @@ using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; -namespace Reactor.Extensions +namespace Reactor.Extensions; + +/// +/// GUI utilities +/// +public static class GUIExtensions { /// - /// GUI utilities + /// Shortcut for empty texture /// - public static class GUIExtensions + public static Texture2D CreateEmptyTexture(int width = 0, int height = 0) { - /// - /// Shortcut for empty texture - /// - public static Texture2D CreateEmptyTexture(int width = 0, int height = 0) - { - return new Texture2D(width, height, TextureFormat.RGBA32, Texture.GenerateAllMips, false, IntPtr.Zero); - } - - /// - /// Clamp Rect to screen size - /// - public static Rect ClampScreen(this Rect rect) - { - rect.x = Mathf.Clamp(rect.x, 0, Screen.width - rect.width); - rect.y = Mathf.Clamp(rect.y, 0, Screen.height - rect.height); - - return rect; - } - - /// - /// Reset Rect size - /// - public static Rect ResetSize(this Rect rect) - { - rect.width = rect.height = 0; - - return rect; - } - - /// - /// Create from - /// - public static Sprite CreateSprite(this Texture2D tex) - { - return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100f); - } - - public static DefaultControls.Resources StandardResources { get; internal set; } = null!; - - public static GameObject CreateCanvas() - { - var gameObject = new GameObject("Canvas"); - var canvas = gameObject.AddComponent(); - canvas.renderMode = RenderMode.ScreenSpaceOverlay; - - var canvasScaler = gameObject.AddComponent(); - - canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand; - canvasScaler.referencePixelsPerUnit = 100f; - - gameObject.AddComponent(); - - return gameObject; - } - - public static GameObject CreateEventSystem() - { - var gameObject = new GameObject("EventSystem"); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - - return gameObject; - } - - public static void SetSize(this RectTransform rectTransform, float width, float height) - { - rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width); - rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height); - } + return new Texture2D(width, height, TextureFormat.RGBA32, Texture.GenerateAllMips, false, IntPtr.Zero); } - public class Window + /// + /// Clamp Rect to screen size + /// + public static Rect ClampScreen(this Rect rect) { - private static int _lastWindowId; + rect.x = Mathf.Clamp(rect.x, 0, Screen.width - rect.width); + rect.y = Mathf.Clamp(rect.y, 0, Screen.height - rect.height); - public static int NextWindowId() + return rect; + } + + /// + /// Reset Rect size + /// + public static Rect ResetSize(this Rect rect) + { + rect.width = rect.height = 0; + + return rect; + } + + /// + /// Create from + /// + public static Sprite CreateSprite(this Texture2D tex) + { + return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100f); + } + + public static DefaultControls.Resources StandardResources { get; internal set; } = null!; + + public static GameObject CreateCanvas() + { + var gameObject = new GameObject("Canvas"); + var canvas = gameObject.AddComponent(); + canvas.renderMode = RenderMode.ScreenSpaceOverlay; + + var canvasScaler = gameObject.AddComponent(); + + canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand; + canvasScaler.referencePixelsPerUnit = 100f; + + gameObject.AddComponent(); + + return gameObject; + } + + public static GameObject CreateEventSystem() + { + var gameObject = new GameObject("EventSystem"); + gameObject.AddComponent(); + gameObject.AddComponent(); + gameObject.AddComponent(); + + return gameObject; + } + + public static void SetSize(this RectTransform rectTransform, float width, float height) + { + rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width); + rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height); + } +} + +public class Window +{ + private static int _lastWindowId; + + public static int NextWindowId() + { + return _lastWindowId++; + } + + public int Id { get; set; } = NextWindowId(); + + public bool Enabled { get; set; } = true; + public Rect Rect { get; set; } + public Action Func { get; set; } + public string Title { get; set; } + + public Window(Rect rect, string title, Action func) + { + Rect = rect; + Title = title; + Func = func; + } + + public Window(Rect rect, string title, Action func) : this(rect, title, id => func()) + { + } + + public void OnGUI() + { + if (Enabled) { - return _lastWindowId++; - } - - public int Id { get; set; } = NextWindowId(); - - public bool Enabled { get; set; } = true; - public Rect Rect { get; set; } - public Action Func { get; set; } - public string Title { get; set; } - - public Window(Rect rect, string title, Action func) - { - Rect = rect; - Title = title; - Func = func; - } - - public Window(Rect rect, string title, Action func) : this(rect, title, id => func()) - { - } - - public void OnGUI() - { - if (Enabled) + if (Event.current.type == EventType.Layout) { - if (Event.current.type == EventType.Layout) - { - Rect = Rect.ResetSize(); - } + Rect = Rect.ResetSize(); + } - Rect = GUILayout.Window(Id, Rect, Func, Title); + Rect = GUILayout.Window(Id, Rect, Func, Title); - if ((Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1)) && Rect.Contains(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y))) - { - Input.ResetInputAxes(); - } + if ((Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1)) && Rect.Contains(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y))) + { + Input.ResetInputAxes(); } } } +} - public class DragWindow : Window +public class DragWindow : Window +{ + public DragWindow(Rect rect, string title, Action func) : base(rect, title, func) { - public DragWindow(Rect rect, string title, Action func) : base(rect, title, func) + Func = id => { - Func = id => - { - func(id); + func(id); - GUI.DragWindow(new Rect(0, 0, 10000, 20)); - Rect = Rect.ClampScreen(); - }; - } + GUI.DragWindow(new Rect(0, 0, 10000, 20)); + Rect = Rect.ClampScreen(); + }; + } - public DragWindow(Rect rect, string title, Action func) : this(rect, title, id => func()) - { - } + public DragWindow(Rect rect, string title, Action func) : this(rect, title, id => func()) + { } } diff --git a/Reactor/Extensions/StreamExtensions.cs b/Reactor/Extensions/StreamExtensions.cs index 5c7867f..67396a6 100644 --- a/Reactor/Extensions/StreamExtensions.cs +++ b/Reactor/Extensions/StreamExtensions.cs @@ -5,89 +5,88 @@ using UnhollowerBaseLib; using UnhollowerBaseLib.Attributes; using UnhollowerRuntimeLib; -namespace Reactor.Extensions +namespace Reactor.Extensions; + +[RegisterInIl2Cpp] +public class StreamWrapper : Il2CppSystem.IO.Stream { - [RegisterInIl2Cpp] - public class StreamWrapper : Il2CppSystem.IO.Stream - { - private readonly Stream _stream; + private readonly Stream _stream; #pragma warning disable 8618 - public StreamWrapper(IntPtr ptr) : base(ptr) { } + public StreamWrapper(IntPtr ptr) : base(ptr) { } #pragma warning restore 8618 - public StreamWrapper(Stream stream) : base(ClassInjector.DerivedConstructorPointer()) - { - ClassInjector.DerivedConstructorBody(this); - _stream = stream; - } - - [HideFromIl2Cpp] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe Span GetSpan(Il2CppStructArray buffer, int offset, int count) - { - var rawBuffer = (byte*) buffer.Pointer + 4 * IntPtr.Size; - return new Span(rawBuffer + offset, count); - } - - public override int Read(Il2CppStructArray buffer, int offset, int count) - { - return _stream.Read(GetSpan(buffer, offset, count)); - } - - public override void Write(Il2CppStructArray buffer, int offset, int count) - { - _stream.Write(GetSpan(buffer, offset, count)); - } - - public override void Flush() - { - _stream.Flush(); - } - - public override void Close() - { - _stream.Close(); - } - - public override void Dispose() - { - _stream.Dispose(); - } - - public override long Seek(long offset, Il2CppSystem.IO.SeekOrigin origin) - { - return _stream.Seek(offset, origin switch - { - Il2CppSystem.IO.SeekOrigin.Begin => SeekOrigin.Begin, - Il2CppSystem.IO.SeekOrigin.Current => SeekOrigin.Current, - Il2CppSystem.IO.SeekOrigin.End => SeekOrigin.End, - _ => throw new ArgumentOutOfRangeException(nameof(origin), origin, null) - }); - } - - public override void SetLength(long value) - { - _stream.SetLength(value); - } - - public override bool CanRead => _stream.CanRead; - public override bool CanSeek => _stream.CanSeek; - public override bool CanWrite => _stream.CanWrite; - public override long Length => _stream.Length; - - public override long Position - { - get => _stream.Position; - set => _stream.Position = value; - } + public StreamWrapper(Stream stream) : base(ClassInjector.DerivedConstructorPointer()) + { + ClassInjector.DerivedConstructorBody(this); + _stream = stream; } - public static class StreamExtensions + [HideFromIl2Cpp] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe Span GetSpan(Il2CppStructArray buffer, int offset, int count) { - /// - /// Wraps a System Stream into an Il2Cpp Stream - /// - public static StreamWrapper AsIl2Cpp(this Stream stream) => new(stream); + var rawBuffer = (byte*) buffer.Pointer + 4 * IntPtr.Size; + return new Span(rawBuffer + offset, count); + } + + public override int Read(Il2CppStructArray buffer, int offset, int count) + { + return _stream.Read(GetSpan(buffer, offset, count)); + } + + public override void Write(Il2CppStructArray buffer, int offset, int count) + { + _stream.Write(GetSpan(buffer, offset, count)); + } + + public override void Flush() + { + _stream.Flush(); + } + + public override void Close() + { + _stream.Close(); + } + + public override void Dispose() + { + _stream.Dispose(); + } + + public override long Seek(long offset, Il2CppSystem.IO.SeekOrigin origin) + { + return _stream.Seek(offset, origin switch + { + Il2CppSystem.IO.SeekOrigin.Begin => SeekOrigin.Begin, + Il2CppSystem.IO.SeekOrigin.Current => SeekOrigin.Current, + Il2CppSystem.IO.SeekOrigin.End => SeekOrigin.End, + _ => throw new ArgumentOutOfRangeException(nameof(origin), origin, null), + }); + } + + public override void SetLength(long value) + { + _stream.SetLength(value); + } + + public override bool CanRead => _stream.CanRead; + public override bool CanSeek => _stream.CanSeek; + public override bool CanWrite => _stream.CanWrite; + public override long Length => _stream.Length; + + public override long Position + { + get => _stream.Position; + set => _stream.Position = value; } } + +public static class StreamExtensions +{ + /// + /// Wraps a System Stream into an Il2Cpp Stream + /// + public static StreamWrapper AsIl2Cpp(this Stream stream) => new(stream); +} diff --git a/Reactor/Extensions/UnityObjectExtensions.cs b/Reactor/Extensions/UnityObjectExtensions.cs index 7787130..2d7d186 100644 --- a/Reactor/Extensions/UnityObjectExtensions.cs +++ b/Reactor/Extensions/UnityObjectExtensions.cs @@ -1,43 +1,42 @@ using UnityEngine; -namespace Reactor.Extensions +namespace Reactor.Extensions; + +public static class UnityObjectExtensions { - public static class UnityObjectExtensions + /// + /// Stops from being destroyed + /// + /// Object to stop from being destroyed + /// Passed + public static T DontDestroy(this T obj) where T : Object { - /// - /// Stops from being destroyed - /// - /// Object to stop from being destroyed - /// Passed - public static T DontDestroy(this T obj) where T : Object - { - obj.hideFlags |= HideFlags.HideAndDontSave; + obj.hideFlags |= HideFlags.HideAndDontSave; - return obj.DontDestroyOnLoad(); - } + return obj.DontDestroyOnLoad(); + } - public static T DontUnload(this T obj) where T : Object - { - obj.hideFlags |= HideFlags.DontUnloadUnusedAsset; + public static T DontUnload(this T obj) where T : Object + { + obj.hideFlags |= HideFlags.DontUnloadUnusedAsset; - return obj; - } + return obj; + } - public static T DontDestroyOnLoad(this T obj) where T : Object - { - Object.DontDestroyOnLoad(obj); + public static T DontDestroyOnLoad(this T obj) where T : Object + { + Object.DontDestroyOnLoad(obj); - return obj; - } + return obj; + } - public static void Destroy(this Object obj) - { - Object.Destroy(obj); - } + public static void Destroy(this Object obj) + { + Object.Destroy(obj); + } - public static void DestroyImmediate(this Object obj) - { - Object.DestroyImmediate(obj); - } + public static void DestroyImmediate(this Object obj) + { + Object.DestroyImmediate(obj); } } diff --git a/Reactor/Il2CppEqualityComparer.cs b/Reactor/Il2CppEqualityComparer.cs index 9f789da..fbcad16 100644 --- a/Reactor/Il2CppEqualityComparer.cs +++ b/Reactor/Il2CppEqualityComparer.cs @@ -1,38 +1,37 @@ using System.Collections.Generic; using Il2CppSystem.Runtime.CompilerServices; -namespace Reactor +namespace Reactor; + +public sealed class Il2CppEqualityComparer : IEqualityComparer where T : Il2CppSystem.Object { - public sealed class Il2CppEqualityComparer : IEqualityComparer where T : Il2CppSystem.Object + private static Il2CppEqualityComparer? _instance; + + public static Il2CppEqualityComparer Instance { - private static Il2CppEqualityComparer? _instance; - - public static Il2CppEqualityComparer Instance + get { - get - { - _instance ??= new Il2CppEqualityComparer(); - return _instance; - } - } - - private Il2CppEqualityComparer() - { - } - - public int GetHashCode(T value) - { - return RuntimeHelpers.GetHashCode(value); - } - - public bool Equals(T? left, T? right) - { - if (left == null || right == null) - { - return left == null && right == null; - } - - return left.Equals(right); + _instance ??= new Il2CppEqualityComparer(); + return _instance; } } + + private Il2CppEqualityComparer() + { + } + + public int GetHashCode(T value) + { + return RuntimeHelpers.GetHashCode(value); + } + + public bool Equals(T? left, T? right) + { + if (left == null || right == null) + { + return left == null && right == null; + } + + return left.Equals(right); + } } diff --git a/Reactor/IsExternalInit.cs b/Reactor/IsExternalInit.cs index 19ec6b5..80fb6dd 100644 --- a/Reactor/IsExternalInit.cs +++ b/Reactor/IsExternalInit.cs @@ -3,9 +3,8 @@ // ReSharper disable CheckNamespace -namespace System.Runtime.CompilerServices +namespace System.Runtime.CompilerServices; + +public static class IsExternalInit { - public static class IsExternalInit - { - } } diff --git a/Reactor/Logger.cs b/Reactor/Logger.cs index 8b6a9a8..2c6fc7b 100644 --- a/Reactor/Logger.cs +++ b/Reactor/Logger.cs @@ -1,28 +1,27 @@ using BepInEx.IL2CPP; using BepInEx.Logging; -namespace Reactor +namespace Reactor; + +public static class Logger where T : BasePlugin { - public static class Logger where T : BasePlugin - { - public static ManualLogSource Instance => PluginSingleton.Instance.Log; + public static ManualLogSource Instance => PluginSingleton.Instance.Log; - /// - public static void Fatal(object data) => Instance.LogFatal(data); + /// + public static void Fatal(object data) => Instance.LogFatal(data); - /// - public static void Error(object data) => Instance.LogError(data); + /// + public static void Error(object data) => Instance.LogError(data); - /// - public static void Warning(object data) => Instance.LogWarning(data); + /// + public static void Warning(object data) => Instance.LogWarning(data); - /// - public static void Message(object data) => Instance.LogMessage(data); + /// + public static void Message(object data) => Instance.LogMessage(data); - /// - public static void Info(object data) => Instance.LogInfo(data); + /// + public static void Info(object data) => Instance.LogInfo(data); - /// - public static void Debug(object data) => Instance.LogDebug(data); - } + /// + public static void Debug(object data) => Instance.LogDebug(data); } diff --git a/Reactor/Networking/CustomRpc.cs b/Reactor/Networking/CustomRpc.cs index e2e4fb0..db8194d 100644 --- a/Reactor/Networking/CustomRpc.cs +++ b/Reactor/Networking/CustomRpc.cs @@ -3,80 +3,79 @@ using BepInEx.IL2CPP; using Hazel; using InnerNet; -namespace Reactor.Networking +namespace Reactor.Networking; + +public abstract class CustomRpc : UnsafeCustomRpc where TPlugin : BasePlugin where TInnerNetObject : InnerNetObject { - public abstract class CustomRpc : UnsafeCustomRpc where TPlugin : BasePlugin where TInnerNetObject : InnerNetObject + protected CustomRpc(TPlugin plugin, uint id) : base(plugin, id) { - protected CustomRpc(TPlugin plugin, uint id) : base(plugin, id) - { - } - - public TPlugin Plugin => (TPlugin) UnsafePlugin; - public override Type InnerNetObjectType => typeof(TInnerNetObject); - - public abstract void Write(MessageWriter writer, TData? data); - public abstract TData Read(MessageReader reader); - public abstract void Handle(TInnerNetObject innerNetObject, TData? data); - - public override void UnsafeWrite(MessageWriter writer, object? data) - { - Write(writer, (TData?) data); - } - - public override object? UnsafeRead(MessageReader reader) - { - return Read(reader); - } - - public override void UnsafeHandle(InnerNetObject innerNetObject, object? data) - { - Handle((TInnerNetObject) innerNetObject, (TData?) data); - } - - public void Send(InnerNetObject netObject, TData data, bool immediately = false) - { - UnsafeSend(netObject, data, immediately); - } - - public void SendTo(InnerNetObject netObject, int targetId, TData data) - { - UnsafeSend(netObject, data, true, targetId); - } } - public abstract class CustomRpc : UnsafeCustomRpc where TPlugin : BasePlugin where TInnerNetObject : InnerNetObject + public TPlugin Plugin => (TPlugin) UnsafePlugin; + public override Type InnerNetObjectType => typeof(TInnerNetObject); + + public abstract void Write(MessageWriter writer, TData? data); + public abstract TData Read(MessageReader reader); + public abstract void Handle(TInnerNetObject innerNetObject, TData? data); + + public override void UnsafeWrite(MessageWriter writer, object? data) { - protected CustomRpc(TPlugin plugin, uint id) : base(plugin, id) - { - } + Write(writer, (TData?) data); + } - public TPlugin Plugin => (TPlugin) UnsafePlugin; - public override Type InnerNetObjectType => typeof(TInnerNetObject); + public override object? UnsafeRead(MessageReader reader) + { + return Read(reader); + } - public abstract void Handle(TInnerNetObject innerNetObject); + public override void UnsafeHandle(InnerNetObject innerNetObject, object? data) + { + Handle((TInnerNetObject) innerNetObject, (TData?) data); + } - public override void UnsafeWrite(MessageWriter writer, object? data) - { - } + public void Send(InnerNetObject netObject, TData data, bool immediately = false) + { + UnsafeSend(netObject, data, immediately); + } - public override object? UnsafeRead(MessageReader reader) - { - return null; - } - - public override void UnsafeHandle(InnerNetObject innerNetObject, object? data) - { - Handle((TInnerNetObject) innerNetObject); - } - - public void Send(InnerNetObject netObject, bool immediately = false) - { - UnsafeSend(netObject, immediately); - } - - public void SendTo(InnerNetObject netObject, int targetId) - { - UnsafeSend(netObject, null, true, targetId); - } + public void SendTo(InnerNetObject netObject, int targetId, TData data) + { + UnsafeSend(netObject, data, true, targetId); + } +} + +public abstract class CustomRpc : UnsafeCustomRpc where TPlugin : BasePlugin where TInnerNetObject : InnerNetObject +{ + protected CustomRpc(TPlugin plugin, uint id) : base(plugin, id) + { + } + + 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) + { + } + + public override object? UnsafeRead(MessageReader reader) + { + return null; + } + + public override void UnsafeHandle(InnerNetObject innerNetObject, object? data) + { + Handle((TInnerNetObject) innerNetObject); + } + + public void Send(InnerNetObject netObject, bool immediately = false) + { + UnsafeSend(netObject, immediately); + } + + public void SendTo(InnerNetObject netObject, int targetId) + { + UnsafeSend(netObject, null, true, targetId); } } diff --git a/Reactor/Networking/CustomRpcManager.cs b/Reactor/Networking/CustomRpcManager.cs index 815b199..a912604 100644 --- a/Reactor/Networking/CustomRpcManager.cs +++ b/Reactor/Networking/CustomRpcManager.cs @@ -6,113 +6,112 @@ using HarmonyLib; using Hazel; using InnerNet; -namespace Reactor.Networking +namespace Reactor.Networking; + +public enum RpcLocalHandling { - public enum RpcLocalHandling + None, + Before, + After, +} + +public class CustomRpcManager +{ + public const byte CallId = byte.MaxValue; + + private readonly List _list = new(); + private readonly Dictionary> _map = new(); + + 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() { - 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) { - 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); - - if (customRpc.IsSingleton) - { - 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; - } + _map[type] = new List(); } } - public static class Rpc where T : UnsafeCustomRpc + public UnsafeCustomRpc Register(UnsafeCustomRpc customRpc) { - private static T? _instance; - - public static T Instance + if (_list.Any(x => x.UnsafePlugin == customRpc.UnsafePlugin && x.Id == customRpc.Id)) { - get - { - if (_instance == null) - { - throw new Exception($"{typeof(T).FullName} isn't registered"); - } + throw new ArgumentException("Rpc with that id was already registered"); + } - return _instance; + customRpc.Manager = this; + _list.Add(customRpc); + _map[customRpc.InnerNetObjectType].Add(customRpc); + + if (customRpc.IsSingleton) + { + 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; } - internal set + return true; + } + } +} + +public static class Rpc where T : UnsafeCustomRpc +{ + private static T? _instance; + + public static T Instance + { + get + { + if (_instance == null) { - if (_instance != null) - { - throw new Exception($"{typeof(T).FullName} is already registered"); - } + throw new Exception($"{typeof(T).FullName} isn't registered"); + } - _instance = value; + return _instance; + } + + internal set + { + if (_instance != null) + { + throw new Exception($"{typeof(T).FullName} is already registered"); } + + _instance = value; } } } diff --git a/Reactor/Networking/MethodRpc/MethodRpc.cs b/Reactor/Networking/MethodRpc/MethodRpc.cs index 55ce594..7846c06 100644 --- a/Reactor/Networking/MethodRpc/MethodRpc.cs +++ b/Reactor/Networking/MethodRpc/MethodRpc.cs @@ -12,202 +12,201 @@ using MonoMod.RuntimeDetour; using MonoMod.Utils; using Reactor.Networking.Serialization; -namespace Reactor.Networking.MethodRpc +namespace Reactor.Networking.MethodRpc; + +public class MethodRpc : UnsafeCustomRpc { - public class MethodRpc : UnsafeCustomRpc + public delegate object HandleDelegate(InnerNetObject innerNetObject, object[] args); + + public MethodRpc(BasePlugin plugin, MethodInfo method, uint id, SendOption option, RpcLocalHandling localHandling, bool sendImmediately) : base(plugin, id) { - public delegate object HandleDelegate(InnerNetObject innerNetObject, object[] args); + Method = method; + LocalHandling = localHandling; + SendOption = option; + SendImmediately = sendImmediately; - public MethodRpc(BasePlugin plugin, MethodInfo method, uint id, SendOption option, RpcLocalHandling localHandling, bool sendImmediately) : base(plugin, id) + if (!method.IsStatic) { - Method = method; - LocalHandling = localHandling; - SendOption = option; - SendImmediately = sendImmediately; - - if (!method.IsStatic) - { - throw new NotImplementedException("Instance method rpc support is postponed until unhollower v0.5.0"); - } - - var parameters = method.GetParameters(); - - if (method.IsStatic && parameters.Length == 0) - { - throw new ArgumentException("Static method rpc requires at least one argument", nameof(method)); - } - - var innerNetObjectType = parameters.First().ParameterType; - - if (!typeof(InnerNetObject).IsAssignableFrom(innerNetObjectType)) - { - throw new ArgumentException("First argument of a static method rpc has to be an InnerNetObject", nameof(method)); - } - - InnerNetObjectType = innerNetObjectType; - - Handle = Hook(method, parameters); + throw new NotImplementedException("Instance method rpc support is postponed until unhollower v0.5.0"); } - public MethodInfo Method { get; } - public HandleDelegate Handle { get; } + var parameters = method.GetParameters(); - protected internal override bool IsSingleton => false; - - public override Type InnerNetObjectType { get; } - public override RpcLocalHandling LocalHandling { get; } - public override SendOption SendOption { get; } - public bool SendImmediately { get; } - - public override void UnsafeWrite(MessageWriter writer, object? data) + if (method.IsStatic && parameters.Length == 0) { - var args = (object[]) data!; - MessageSerializer.Serialize(writer, args); + throw new ArgumentException("Static method rpc requires at least one argument", nameof(method)); } - public override object UnsafeRead(MessageReader reader) + var innerNetObjectType = parameters.First().ParameterType; + + if (!typeof(InnerNetObject).IsAssignableFrom(innerNetObjectType)) { - var args = MessageSerializer.Deserialize(reader, this); - return args; + throw new ArgumentException("First argument of a static method rpc has to be an InnerNetObject", nameof(method)); } - public override void UnsafeHandle(InnerNetObject innerNetObject, object? data) + InnerNetObjectType = innerNetObjectType; + + Handle = Hook(method, parameters); + } + + public MethodInfo Method { get; } + public HandleDelegate Handle { get; } + + protected internal override bool IsSingleton => false; + + public override Type InnerNetObjectType { get; } + public override RpcLocalHandling LocalHandling { get; } + public override SendOption SendOption { get; } + public bool SendImmediately { get; } + + public override void UnsafeWrite(MessageWriter writer, object? data) + { + var args = (object[]) data!; + MessageSerializer.Serialize(writer, args); + } + + public override object UnsafeRead(MessageReader reader) + { + var args = MessageSerializer.Deserialize(reader, this); + return args; + } + + public override void UnsafeHandle(InnerNetObject innerNetObject, object? data) + { + var args = (object[]) data!; + var result = Handle(innerNetObject, args); + + if (result is IEnumerator enumerator) { - var args = (object[]) data!; - var result = Handle(innerNetObject, args); - - if (result is IEnumerator enumerator) - { - Coroutines.Start(enumerator); - } - } - - public void Send(InnerNetObject innerNetObject, object[] args) - { - UnsafeSend(innerNetObject, args, SendImmediately); - } - - private static readonly MethodInfo _sendMethod = AccessTools.Method(typeof(MethodRpc), nameof(Send)); - - /// - /// Hooks the rpc with a dynamic method that sends it - /// - private HandleDelegate Hook(MethodInfo method, ParameterInfo[] parameters) - { - var detour = new Detour(method, GenerateSender()); - - // Used as target when hooking, sends the method rpc - DynamicMethod GenerateSender() - { - var dynamicMethod = new DynamicMethod($"Sender<{method.GetID(simple: true)}>", method.ReturnType, parameters.Select(x => x.ParameterType).ToArray()); - - foreach (var parameter in parameters) - { - dynamicMethod.DefineParameter(parameter.Position, ParameterAttributes.None, parameter.Name); - } - - var il = dynamicMethod.GetILGenerator(); - - // :yeefuckinhaw: - // Black magic from stackoverflow, they also said that you shouldn't do that ;) - // Resort to Dictionary if this turns out to be unreliable - { - var handle = GCHandle.Alloc(this); - var ptr = GCHandle.ToIntPtr(handle); - - if (IntPtr.Size == 4) - { - il.Emit(OpCodes.Ldc_I4, ptr.ToInt32()); - } - else - { - il.Emit(OpCodes.Ldc_I8, ptr.ToInt64()); - } - - il.Emit(OpCodes.Conv_I); - - // TODO Figure out why this always throws NullReferenceException on mono - // il.Emit(OpCodes.Ldobj, typeof(MethodRpc)); - - // Workaround for ^, speed seems to be the same - il.Emit(OpCodes.Call, AccessTools.Method(typeof(GCHandle), nameof(GCHandle.FromIntPtr))); - var temp = il.DeclareLocal(typeof(GCHandle)); - il.Emit(OpCodes.Stloc, temp); - il.Emit(OpCodes.Ldloca, temp); - il.Emit(OpCodes.Call, AccessTools.PropertyGetter(typeof(GCHandle), nameof(GCHandle.Target))); - } - - il.Emit(OpCodes.Ldarg_0); - - il.Emit(OpCodes.Ldc_I4, parameters.Length - 1); - il.Emit(OpCodes.Newarr, typeof(object)); - - for (var i = 1; i < parameters.Length; i++) - { - var parameter = parameters[i]; - - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Ldc_I4, i - 1); - il.Emit(OpCodes.Ldarg, i); - - var parameterType = parameter.ParameterType; - if (parameterType.IsValueType) - { - il.Emit(OpCodes.Box, parameterType); - } - - il.Emit(OpCodes.Stelem_Ref); - } - - il.Emit(OpCodes.Call, _sendMethod); - - if (method.ReturnType != typeof(void)) - { - il.Emit(OpCodes.Ldnull); - } - - il.Emit(OpCodes.Ret); - - return dynamicMethod; - } - - // Proxy translating object array to trampoline method args, used by MethodRpc to invoke original handling - HandleDelegate GenerateHandler(DynamicMethod trampoline) - { - var dynamicMethod = new DynamicMethod($"Handler<{method.GetID(simple: true)}>", typeof(object), new[] { typeof(InnerNetObject), typeof(object[]) }); - dynamicMethod.DefineParameter(0, ParameterAttributes.None, "innerNetObject"); - dynamicMethod.DefineParameter(1, ParameterAttributes.None, "args"); - - var il = dynamicMethod.GetILGenerator(); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Castclass, InnerNetObjectType); - - for (var i = 1; i < parameters.Length; i++) - { - var parameter = parameters[i]; - - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldc_I4, i - 1); - il.Emit(OpCodes.Ldelem_Ref); - - var parameterType = parameter.ParameterType; - il.Emit(parameterType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, parameterType); - } - - il.Emit(OpCodes.Call, trampoline); - - if (method.ReturnType == typeof(void)) - { - il.Emit(OpCodes.Ldnull); - } - - il.Emit(OpCodes.Ret); - - return dynamicMethod.CreateDelegate(); - } - - return GenerateHandler((DynamicMethod) detour.GenerateTrampoline()); + Coroutines.Start(enumerator); } } + + public void Send(InnerNetObject innerNetObject, object[] args) + { + UnsafeSend(innerNetObject, args, SendImmediately); + } + + private static readonly MethodInfo _sendMethod = AccessTools.Method(typeof(MethodRpc), nameof(Send)); + + /// + /// Hooks the rpc with a dynamic method that sends it + /// + private HandleDelegate Hook(MethodInfo method, ParameterInfo[] parameters) + { + var detour = new Detour(method, GenerateSender()); + + // Used as target when hooking, sends the method rpc + DynamicMethod GenerateSender() + { + var dynamicMethod = new DynamicMethod($"Sender<{method.GetID(simple: true)}>", method.ReturnType, parameters.Select(x => x.ParameterType).ToArray()); + + foreach (var parameter in parameters) + { + dynamicMethod.DefineParameter(parameter.Position, ParameterAttributes.None, parameter.Name); + } + + var il = dynamicMethod.GetILGenerator(); + + // :yeefuckinhaw: + // Black magic from stackoverflow, they also said that you shouldn't do that ;) + // Resort to Dictionary if this turns out to be unreliable + { + var handle = GCHandle.Alloc(this); + var ptr = GCHandle.ToIntPtr(handle); + + if (IntPtr.Size == 4) + { + il.Emit(OpCodes.Ldc_I4, ptr.ToInt32()); + } + else + { + il.Emit(OpCodes.Ldc_I8, ptr.ToInt64()); + } + + il.Emit(OpCodes.Conv_I); + + // TODO Figure out why this always throws NullReferenceException on mono + // il.Emit(OpCodes.Ldobj, typeof(MethodRpc)); + + // Workaround for ^, speed seems to be the same + il.Emit(OpCodes.Call, AccessTools.Method(typeof(GCHandle), nameof(GCHandle.FromIntPtr))); + var temp = il.DeclareLocal(typeof(GCHandle)); + il.Emit(OpCodes.Stloc, temp); + il.Emit(OpCodes.Ldloca, temp); + il.Emit(OpCodes.Call, AccessTools.PropertyGetter(typeof(GCHandle), nameof(GCHandle.Target))); + } + + il.Emit(OpCodes.Ldarg_0); + + il.Emit(OpCodes.Ldc_I4, parameters.Length - 1); + il.Emit(OpCodes.Newarr, typeof(object)); + + for (var i = 1; i < parameters.Length; i++) + { + var parameter = parameters[i]; + + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Ldc_I4, i - 1); + il.Emit(OpCodes.Ldarg, i); + + var parameterType = parameter.ParameterType; + if (parameterType.IsValueType) + { + il.Emit(OpCodes.Box, parameterType); + } + + il.Emit(OpCodes.Stelem_Ref); + } + + il.Emit(OpCodes.Call, _sendMethod); + + if (method.ReturnType != typeof(void)) + { + il.Emit(OpCodes.Ldnull); + } + + il.Emit(OpCodes.Ret); + + return dynamicMethod; + } + + // Proxy translating object array to trampoline method args, used by MethodRpc to invoke original handling + HandleDelegate GenerateHandler(DynamicMethod trampoline) + { + var dynamicMethod = new DynamicMethod($"Handler<{method.GetID(simple: true)}>", typeof(object), new[] { typeof(InnerNetObject), typeof(object[]) }); + dynamicMethod.DefineParameter(0, ParameterAttributes.None, "innerNetObject"); + dynamicMethod.DefineParameter(1, ParameterAttributes.None, "args"); + + var il = dynamicMethod.GetILGenerator(); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Castclass, InnerNetObjectType); + + for (var i = 1; i < parameters.Length; i++) + { + var parameter = parameters[i]; + + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldc_I4, i - 1); + il.Emit(OpCodes.Ldelem_Ref); + + var parameterType = parameter.ParameterType; + il.Emit(parameterType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, parameterType); + } + + il.Emit(OpCodes.Call, trampoline); + + if (method.ReturnType == typeof(void)) + { + il.Emit(OpCodes.Ldnull); + } + + il.Emit(OpCodes.Ret); + + return dynamicMethod.CreateDelegate(); + } + + return GenerateHandler((DynamicMethod) detour.GenerateTrampoline()); + } } diff --git a/Reactor/Networking/MethodRpc/MethodRpcAttribute.cs b/Reactor/Networking/MethodRpc/MethodRpcAttribute.cs index d059236..da6e51b 100644 --- a/Reactor/Networking/MethodRpc/MethodRpcAttribute.cs +++ b/Reactor/Networking/MethodRpc/MethodRpcAttribute.cs @@ -5,49 +5,48 @@ using BepInEx.IL2CPP; using HarmonyLib; using Hazel; -namespace Reactor.Networking.MethodRpc +namespace Reactor.Networking.MethodRpc; + +[AttributeUsage(AttributeTargets.Method)] +public class MethodRpcAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method)] - public class MethodRpcAttribute : Attribute + public uint Id { get; } + public SendOption Option { get; set; } = SendOption.Reliable; + public RpcLocalHandling LocalHandling { get; set; } = RpcLocalHandling.Before; + public bool SendImmediately { get; set; } + + public MethodRpcAttribute(uint id) { - public uint Id { get; } - public SendOption Option { get; set; } = SendOption.Reliable; - public RpcLocalHandling LocalHandling { get; set; } = RpcLocalHandling.Before; - public bool SendImmediately { get; set; } + Id = id; + } - public MethodRpcAttribute(uint id) + public static void Register(Assembly assembly, BasePlugin plugin) + { + var methods = assembly.GetTypes() + .SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)); + + foreach (var method in methods) { - Id = id; - } - - public static void Register(Assembly assembly, BasePlugin plugin) - { - var methods = assembly.GetTypes() - .SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)); - - foreach (var method in methods) + var attribute = method.GetCustomAttribute(); + if (attribute == null) { - var attribute = method.GetCustomAttribute(); - if (attribute == null) - { - continue; - } + continue; + } - try - { - var customRpc = new MethodRpc(plugin, method, attribute.Id, attribute.Option, attribute.LocalHandling, attribute.SendImmediately); - PluginSingleton.Instance.CustomRpcManager.Register(customRpc); - } - catch (Exception e) - { - Logger.Warning($"Failed to register {method.FullDescription()}: {e}"); - } + try + { + var customRpc = new MethodRpc(plugin, method, attribute.Id, attribute.Option, attribute.LocalHandling, attribute.SendImmediately); + PluginSingleton.Instance.CustomRpcManager.Register(customRpc); + } + catch (Exception e) + { + Logger.Warning($"Failed to register {method.FullDescription()}: {e}"); } } + } - internal static void Initialize() - { - ChainloaderHooks.PluginLoad += plugin => Register(plugin.GetType().Assembly, plugin); - } + internal static void Initialize() + { + ChainloaderHooks.PluginLoad += plugin => Register(plugin.GetType().Assembly, plugin); } } diff --git a/Reactor/Networking/ModDeclaration.cs b/Reactor/Networking/ModDeclaration.cs index 51e2acd..c2c81ec 100644 --- a/Reactor/Networking/ModDeclaration.cs +++ b/Reactor/Networking/ModDeclaration.cs @@ -1,17 +1,16 @@ using Hazel; -namespace Reactor.Networking +namespace Reactor.Networking; + +public static class ModDeclaration { - public static class ModDeclaration + public static void Serialize(MessageWriter writer, Mod mod) { - public static void Serialize(MessageWriter writer, Mod mod) - { - writer.StartMessage(byte.MaxValue); - writer.Write((byte) ReactorMessageFlags.ModDeclaration); - writer.WritePacked(mod.NetId); - writer.Write(mod.Id); - writer.Write(mod.Version); - writer.Write((byte) mod.Side); - } + writer.StartMessage(byte.MaxValue); + writer.Write((byte) ReactorMessageFlags.ModDeclaration); + writer.WritePacked(mod.NetId); + writer.Write(mod.Id); + writer.Write(mod.Version); + writer.Write((byte) mod.Side); } } diff --git a/Reactor/Networking/ModList.cs b/Reactor/Networking/ModList.cs index cab2b6a..dc48222 100644 --- a/Reactor/Networking/ModList.cs +++ b/Reactor/Networking/ModList.cs @@ -2,43 +2,42 @@ using System.Collections.Generic; using System.Linq; using BepInEx.IL2CPP; -namespace Reactor.Networking +namespace Reactor.Networking; + +public static class ModList { - public static class ModList + private static Dictionary? _mapById; + private static Dictionary? _mapByNetId; + + public static ISet? Current { get; private set; } + + public static Mod GetById(string id) { - private static Dictionary? _mapById; - private static Dictionary? _mapByNetId; + return _mapById![id]; + } - public static ISet? Current { get; private set; } + public static Mod GetByNetId(uint netId) + { + return _mapByNetId![netId]; + } - public static Mod GetById(string id) - { - return _mapById![id]; - } + internal static ISet Update() + { + var i = (uint) 0; - public static Mod GetByNetId(uint netId) - { - return _mapByNetId![netId]; - } + Current = IL2CPPChainloader.Instance.Plugins.Values + .OrderByDescending(x => x.Metadata.GUID == ReactorPlugin.Id) + .Select(plugin => new Mod( + i++, + plugin.Metadata.GUID, + plugin.Metadata.Version.Clean(), + ReactorPluginSideAttribute.GetPluginSide(plugin.Instance.GetType()) + )) + .ToHashSet(); - internal static ISet Update() - { - var i = (uint) 0; + _mapById = Current.ToDictionary(mod => mod.Id, mod => mod); + _mapByNetId = Current.ToDictionary(mod => mod.NetId, mod => mod); - Current = IL2CPPChainloader.Instance.Plugins.Values - .OrderByDescending(x => x.Metadata.GUID == ReactorPlugin.Id) - .Select(plugin => new Mod( - i++, - plugin.Metadata.GUID, - plugin.Metadata.Version.Clean(), - ReactorPluginSideAttribute.GetPluginSide(plugin.Instance.GetType()) - )) - .ToHashSet(); - - _mapById = Current.ToDictionary(mod => mod.Id, mod => mod); - _mapByNetId = Current.ToDictionary(mod => mod.NetId, mod => mod); - - return Current; - } + return Current; } } diff --git a/Reactor/Networking/ModdedHandshakeC2S.cs b/Reactor/Networking/ModdedHandshakeC2S.cs index 3b4fb79..b39aa6d 100644 --- a/Reactor/Networking/ModdedHandshakeC2S.cs +++ b/Reactor/Networking/ModdedHandshakeC2S.cs @@ -1,13 +1,12 @@ using Hazel; -namespace Reactor.Networking +namespace Reactor.Networking; + +public static class ModdedHandshakeC2S { - public static class ModdedHandshakeC2S + public static void Serialize(MessageWriter writer, int modCount) { - public static void Serialize(MessageWriter writer, int modCount) - { - writer.Write((byte) ReactorProtocolVersion.Initial); - writer.WritePacked(modCount); - } + writer.Write((byte) ReactorProtocolVersion.Initial); + writer.WritePacked(modCount); } } diff --git a/Reactor/Networking/ModdedHandshakeS2C.cs b/Reactor/Networking/ModdedHandshakeS2C.cs index 58f89c2..b51b989 100644 --- a/Reactor/Networking/ModdedHandshakeS2C.cs +++ b/Reactor/Networking/ModdedHandshakeS2C.cs @@ -1,24 +1,23 @@ using Hazel; -namespace Reactor.Networking -{ - public static class ModdedHandshakeS2C - { - public static void Serialize(MessageWriter writer, string serverName, string serverVersion, int pluginCount) - { - writer.StartMessage(byte.MaxValue); - writer.Write((byte) ReactorMessageFlags.Handshake); - writer.Write(serverName); - writer.Write(serverVersion); - writer.WritePacked(pluginCount); - writer.EndMessage(); - } +namespace Reactor.Networking; - public static void Deserialize(MessageReader reader, out string serverName, out string serverVersion, out int pluginCount) - { - serverName = reader.ReadString(); - serverVersion = reader.ReadString(); - pluginCount = reader.ReadPackedInt32(); - } +public static class ModdedHandshakeS2C +{ + public static void Serialize(MessageWriter writer, string serverName, string serverVersion, int pluginCount) + { + writer.StartMessage(byte.MaxValue); + writer.Write((byte) ReactorMessageFlags.Handshake); + writer.Write(serverName); + writer.Write(serverVersion); + writer.WritePacked(pluginCount); + writer.EndMessage(); + } + + public static void Deserialize(MessageReader reader, out string serverName, out string serverVersion, out int pluginCount) + { + serverName = reader.ReadString(); + serverVersion = reader.ReadString(); + pluginCount = reader.ReadPackedInt32(); } } diff --git a/Reactor/Networking/Patches/ClientPatches.cs b/Reactor/Networking/Patches/ClientPatches.cs index 6f3aa43..17a9358 100644 --- a/Reactor/Networking/Patches/ClientPatches.cs +++ b/Reactor/Networking/Patches/ClientPatches.cs @@ -9,176 +9,175 @@ using Reactor.Extensions; using UnhollowerBaseLib; using UnityEngine; -namespace Reactor.Networking.Patches +namespace Reactor.Networking.Patches; + +internal static class ClientPatches { - internal static class ClientPatches + [HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.HandleMessage))] + public static class HandleMessagePatch { - [HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.HandleMessage))] - public static class HandleMessagePatch + public static bool Prefix(InnerNetClient __instance, [HarmonyArgument(0)] MessageReader reader) { - public static bool Prefix(InnerNetClient __instance, [HarmonyArgument(0)] MessageReader reader) + if (reader.Tag == byte.MaxValue) { - if (reader.Tag == byte.MaxValue) + var flag = (ReactorMessageFlags) reader.ReadByte(); + + switch (flag) { - var flag = (ReactorMessageFlags) reader.ReadByte(); - - switch (flag) + case ReactorMessageFlags.Handshake: { - case ReactorMessageFlags.Handshake: + ModdedHandshakeS2C.Deserialize(reader, out var serverName, out var serverVersion, out var pluginCount); + + Logger.Info($"Connected to a modded server ({serverName} {serverVersion}, {pluginCount} plugins), sending mod declarations"); + + var mods = ModList.Current!; + + var writer = MessageWriter.Get(SendOption.Reliable); + + var expected = 0; + var got = 0; + + void Send() { - ModdedHandshakeS2C.Deserialize(reader, out var serverName, out var serverVersion, out var pluginCount); + expected++; - Logger.Info($"Connected to a modded server ({serverName} {serverVersion}, {pluginCount} plugins), sending mod declarations"); - - var mods = ModList.Current!; - - var writer = MessageWriter.Get(SendOption.Reliable); - - var expected = 0; - var got = 0; - - void Send() + __instance.connection.Send(writer, () => { - expected++; + got++; - __instance.connection.Send(writer, () => + if (got >= expected) { - got++; - - if (got >= expected) - { - Logger.Debug("Received all acks"); - __instance.connection.State = ConnectionState.Connected; - } - }); - writer.Recycle(); - } - - foreach (var mod in mods) - { - ModDeclaration.Serialize(writer, mod); - - if (writer.Length >= 500) - { - writer.CancelMessage(); - - Send(); - - writer = MessageWriter.Get(SendOption.Reliable); - ModDeclaration.Serialize(writer, mod); + Logger.Debug("Received all acks"); + __instance.connection.State = ConnectionState.Connected; } + }); + writer.Recycle(); + } - writer.EndMessage(); + foreach (var mod in mods) + { + ModDeclaration.Serialize(writer, mod); + + if (writer.Length >= 500) + { + writer.CancelMessage(); + + Send(); + + writer = MessageWriter.Get(SendOption.Reliable); + ModDeclaration.Serialize(writer, mod); } - Send(); - - break; + writer.EndMessage(); } - case ReactorMessageFlags.PluginDeclaration: - { - // TODO - break; - } + Send(); - default: - throw new ArgumentOutOfRangeException(); + break; } - return false; - } - - return true; - } - } - - [HarmonyPatch(typeof(UdpConnection), nameof(UdpConnection.HandleSend))] - public static class SendHelloPatch - { - public static void Prefix(UdpConnection __instance, byte sendOption, ref Il2CppSystem.Action ackCallback) - { - if (sendOption != 8 || AmongUsClient.Instance == null || AmongUsClient.Instance.connection == null || !AmongUsClient.Instance.connection.Equals(__instance)) - { - return; - } - - ackCallback = (Action) (() => - { - if (__instance.State == ConnectionState.Connected) - return; - - Logger.Debug("Hello was acked, waiting for modded handshake response"); - - var coroutine = Coroutines.Start(Coroutine(__instance)); - - __instance.Disconnected = Il2CppSystem.Delegate.Combine( - (Il2CppSystem.EventHandler) (Action) ((_, _) => - { - Coroutines.Stop(coroutine); - }), - __instance.Disconnected - ).Cast>(); - }); - } - - private static IEnumerator Coroutine(UdpConnection connection) - { - yield return new WaitForSeconds(3); - - var client = AmongUsClient.Instance; - if (client != null && client.connection != null && client.connection.Equals(connection) && client.connection.State == ConnectionState.Connecting) - { - var reactorPlugin = PluginSingleton.Instance; - - if (reactorPlugin.AllowVanillaServers!.Value) + case ReactorMessageFlags.PluginDeclaration: { - if (reactorPlugin.CustomRpcManager.List.Any()) - { - Logger.Warning("Config option AllowVanillaServers was set to true, but there are custom rpcs registered!"); - } - else - { - connection.State = ConnectionState.Connected; - yield break; - } + // TODO + break; } - client.LastDisconnectReason = DisconnectReasons.Custom; - client.LastCustomDisconnect = "Server didn't respond to modded handshake"; - client.HandleDisconnect(client.LastDisconnectReason, client.LastCustomDisconnect); + default: + throw new ArgumentOutOfRangeException(); } + + return false; } + + return true; + } + } + + [HarmonyPatch(typeof(UdpConnection), nameof(UdpConnection.HandleSend))] + public static class SendHelloPatch + { + public static void Prefix(UdpConnection __instance, byte sendOption, ref Il2CppSystem.Action ackCallback) + { + if (sendOption != 8 || AmongUsClient.Instance == null || AmongUsClient.Instance.connection == null || !AmongUsClient.Instance.connection.Equals(__instance)) + { + return; + } + + ackCallback = (Action) (() => + { + if (__instance.State == ConnectionState.Connected) + return; + + Logger.Debug("Hello was acked, waiting for modded handshake response"); + + var coroutine = Coroutines.Start(Coroutine(__instance)); + + __instance.Disconnected = Il2CppSystem.Delegate.Combine( + (Il2CppSystem.EventHandler) (Action) ((_, _) => + { + Coroutines.Stop(coroutine); + }), + __instance.Disconnected + ).Cast>(); + }); } - [HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.GetConnectionData))] - public static class HandshakePatch + private static IEnumerator Coroutine(UdpConnection connection) { - public static void Prefix(ref bool useDtlsLayout) + yield return new WaitForSeconds(3); + + var client = AmongUsClient.Instance; + if (client != null && client.connection != null && client.connection.Equals(connection) && client.connection.State == ConnectionState.Connecting) { - // Due to reasons currently unknown, the useDtlsLayout parameter sometimes doesn't reflect whether DTLS - // is actually supposed to be enabled. This causes a bad handshake message and a quick disconnect. - // The field on AmongUsClient appears to be more reliable, so override this parameter with what it is supposed to be. - Logger.Info($"Currently using dtls: {useDtlsLayout}. Should use dtls: {AmongUsClient.Instance.useDtls}"); - useDtlsLayout = AmongUsClient.Instance.useDtls; - } + var reactorPlugin = PluginSingleton.Instance; - public static void Postfix(ref Il2CppStructArray __result) - { - var mods = ModList.Update(); + if (reactorPlugin.AllowVanillaServers!.Value) + { + if (reactorPlugin.CustomRpcManager.List.Any()) + { + Logger.Warning("Config option AllowVanillaServers was set to true, but there are custom rpcs registered!"); + } + else + { + connection.State = ConnectionState.Connected; + yield break; + } + } - var handshake = new MessageWriter(1000); - - handshake.Write(__result); - - ModdedHandshakeC2S.Serialize( - handshake, - mods.Count - ); - - __result = handshake.ToByteArray(true); - handshake.Recycle(); + client.LastDisconnectReason = DisconnectReasons.Custom; + client.LastCustomDisconnect = "Server didn't respond to modded handshake"; + client.HandleDisconnect(client.LastDisconnectReason, client.LastCustomDisconnect); } } } + + [HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.GetConnectionData))] + public static class HandshakePatch + { + public static void Prefix(ref bool useDtlsLayout) + { + // Due to reasons currently unknown, the useDtlsLayout parameter sometimes doesn't reflect whether DTLS + // is actually supposed to be enabled. This causes a bad handshake message and a quick disconnect. + // The field on AmongUsClient appears to be more reliable, so override this parameter with what it is supposed to be. + Logger.Info($"Currently using dtls: {useDtlsLayout}. Should use dtls: {AmongUsClient.Instance.useDtls}"); + useDtlsLayout = AmongUsClient.Instance.useDtls; + } + + public static void Postfix(ref Il2CppStructArray __result) + { + var mods = ModList.Update(); + + var handshake = new MessageWriter(1000); + + handshake.Write(__result); + + ModdedHandshakeC2S.Serialize( + handshake, + mods.Count + ); + + __result = handshake.ToByteArray(true); + handshake.Recycle(); + } + } } diff --git a/Reactor/Networking/Patches/ServerPatches.cs b/Reactor/Networking/Patches/ServerPatches.cs index 771f545..b75a980 100644 --- a/Reactor/Networking/Patches/ServerPatches.cs +++ b/Reactor/Networking/Patches/ServerPatches.cs @@ -3,20 +3,19 @@ using Hazel; using InnerNet; using UnityEngine; -namespace Reactor.Networking.Patches +namespace Reactor.Networking.Patches; + +internal static class ServerPatches { - internal static class ServerPatches + [HarmonyPatch(typeof(InnerNetServer), nameof(InnerNetServer.OnServerConnect))] + public static class HandshakeResponsePatch { - [HarmonyPatch(typeof(InnerNetServer), nameof(InnerNetServer.OnServerConnect))] - public static class HandshakeResponsePatch + public static void Postfix([HarmonyArgument(0)] NewConnectionEventArgs evt) { - public static void Postfix([HarmonyArgument(0)] NewConnectionEventArgs evt) - { - var writer = MessageWriter.Get(SendOption.Reliable); - ModdedHandshakeS2C.Serialize(writer, "Among Us", Application.version, 0); - evt.Connection.Send(writer); - writer.Recycle(); - } + var writer = MessageWriter.Get(SendOption.Reliable); + ModdedHandshakeS2C.Serialize(writer, "Among Us", Application.version, 0); + evt.Connection.Send(writer); + writer.Recycle(); } } } diff --git a/Reactor/Networking/PlayerCustomRpc.cs b/Reactor/Networking/PlayerCustomRpc.cs index ffe9161..c692be1 100644 --- a/Reactor/Networking/PlayerCustomRpc.cs +++ b/Reactor/Networking/PlayerCustomRpc.cs @@ -1,38 +1,37 @@ using BepInEx.IL2CPP; -namespace Reactor.Networking +namespace Reactor.Networking; + +public abstract class PlayerCustomRpc : CustomRpc where TPlugin : BasePlugin { - public abstract class PlayerCustomRpc : CustomRpc where TPlugin : BasePlugin + protected PlayerCustomRpc(TPlugin plugin, uint id) : base(plugin, id) { - 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 + public void Send(TData data, bool immediately = false) { - protected PlayerCustomRpc(TPlugin plugin, uint id) : base(plugin, id) - { - } + Send(PlayerControl.LocalPlayer, data, immediately); + } - public void Send(bool immediately = false) - { - Send(PlayerControl.LocalPlayer, immediately); - } + public void SendTo(int targetId, TData data) + { + SendTo(PlayerControl.LocalPlayer, targetId, data); + } +} - public void SendTo(int targetId) - { - SendTo(PlayerControl.LocalPlayer, targetId); - } +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/Serialization/InnerNetObjectConverter.cs b/Reactor/Networking/Serialization/InnerNetObjectConverter.cs index 3effd6f..c168a3b 100644 --- a/Reactor/Networking/Serialization/InnerNetObjectConverter.cs +++ b/Reactor/Networking/Serialization/InnerNetObjectConverter.cs @@ -4,36 +4,34 @@ using System.Reflection; using HarmonyLib; using Hazel; using InnerNet; -using MonoMod.Utils; -namespace Reactor.Networking.Serialization +namespace Reactor.Networking.Serialization; + +[MessageConverter] +public class InnerNetObjectConverter : MessageConverter { - [MessageConverter] - public class InnerNetObjectConverter : MessageConverter + private static readonly MethodInfo _readNetObject = AccessTools.Method(typeof(MessageExtensions), nameof(MessageExtensions.ReadNetObject)); + private static readonly Dictionary> _readNetObjectMap = new(); + + public static InnerNetObject ReadNetObject(MessageReader reader, Type t) { - private static readonly MethodInfo _readNetObject = AccessTools.Method(typeof(MessageExtensions), nameof(MessageExtensions.ReadNetObject)); - private static readonly Dictionary> _readNetObjectMap = new Dictionary>(); - - public static InnerNetObject ReadNetObject(MessageReader reader, Type t) + if (_readNetObjectMap.TryGetValue(t, out var value)) { - if (_readNetObjectMap.TryGetValue(t, out var value)) - { - return value(reader); - } - - var @delegate = _readNetObject.MakeGenericMethod(t).CreateDelegate>(); - _readNetObjectMap[t] = @delegate; - return @delegate(reader); + return value(reader); } - public override void Write(MessageWriter writer, InnerNetObject value) - { - MessageExtensions.WriteNetObject(writer, value); - } + var @delegate = _readNetObject.MakeGenericMethod(t).CreateDelegate>(); + _readNetObjectMap[t] = @delegate; + return @delegate(reader); + } - public override InnerNetObject Read(MessageReader reader, Type objectType) - { - return ReadNetObject(reader, objectType); - } + public override void Write(MessageWriter writer, InnerNetObject value) + { + MessageExtensions.WriteNetObject(writer, value); + } + + public override InnerNetObject Read(MessageReader reader, Type objectType) + { + return ReadNetObject(reader, objectType); } } diff --git a/Reactor/Networking/Serialization/MessageConverter.cs b/Reactor/Networking/Serialization/MessageConverter.cs index 54b28fd..2019464 100644 --- a/Reactor/Networking/Serialization/MessageConverter.cs +++ b/Reactor/Networking/Serialization/MessageConverter.cs @@ -1,29 +1,28 @@ using System; using Hazel; -namespace Reactor.Networking.Serialization +namespace Reactor.Networking.Serialization; + +public abstract class UnsafeMessageConverter { - public abstract class UnsafeMessageConverter - { - public abstract void UnsafeWrite(MessageWriter writer, object value); - public abstract object UnsafeRead(MessageReader reader, Type objectType); + public abstract void UnsafeWrite(MessageWriter writer, object value); + public abstract object UnsafeRead(MessageReader reader, Type objectType); - public abstract bool CanConvert(Type objectType); - } + public abstract bool CanConvert(Type objectType); +} - public abstract class MessageConverter : UnsafeMessageConverter - { - public abstract void Write(MessageWriter writer, T value); +public abstract class MessageConverter : UnsafeMessageConverter +{ + public abstract void Write(MessageWriter writer, T value); - public abstract T Read(MessageReader reader, Type objectType); + public abstract T Read(MessageReader reader, Type objectType); - public override bool CanConvert(Type objectType) - { - return typeof(T).IsAssignableFrom(objectType); - } + public override bool CanConvert(Type objectType) + { + return typeof(T).IsAssignableFrom(objectType); + } - public override void UnsafeWrite(MessageWriter writer, object value) => Write(writer, (T) value); + public override void UnsafeWrite(MessageWriter writer, object value) => Write(writer, (T) value); - public override object UnsafeRead(MessageReader reader, Type objectType) => Read(reader, objectType)!; - } + public override object UnsafeRead(MessageReader reader, Type objectType) => Read(reader, objectType)!; } diff --git a/Reactor/Networking/Serialization/MessageConverterAttribute.cs b/Reactor/Networking/Serialization/MessageConverterAttribute.cs index aa743e8..d6bb4db 100644 --- a/Reactor/Networking/Serialization/MessageConverterAttribute.cs +++ b/Reactor/Networking/Serialization/MessageConverterAttribute.cs @@ -2,40 +2,39 @@ using System; using System.Reflection; using HarmonyLib; -namespace Reactor.Networking.Serialization +namespace Reactor.Networking.Serialization; + +[AttributeUsage(AttributeTargets.Class)] +public class MessageConverterAttribute : Attribute { - [AttributeUsage(AttributeTargets.Class)] - public class MessageConverterAttribute : Attribute + public static void Register(Assembly assembly) { - public static void Register(Assembly assembly) + foreach (var type in assembly.GetTypes()) { - foreach (var type in assembly.GetTypes()) + var attribute = type.GetCustomAttribute(); + + if (attribute != null) { - var attribute = type.GetCustomAttribute(); - - if (attribute != null) + if (!type.IsSubclassOf(typeof(UnsafeMessageConverter))) { - if (!type.IsSubclassOf(typeof(UnsafeMessageConverter))) - { - throw new InvalidOperationException($"Type {type.FullDescription()} has {nameof(MessageConverterAttribute)} but doesn't extend {nameof(UnsafeMessageConverter)}."); - } + throw new InvalidOperationException($"Type {type.FullDescription()} has {nameof(MessageConverterAttribute)} but doesn't extend {nameof(UnsafeMessageConverter)}."); + } - try - { - var messageConverter = (UnsafeMessageConverter) Activator.CreateInstance(type); - MessageSerializer.Register(messageConverter); - } - catch (Exception e) - { - Logger.Warning($"Failed to register {type.FullDescription()}: {e}"); - } + try + { + var messageConverter = (UnsafeMessageConverter) Activator.CreateInstance(type); + MessageSerializer.Register(messageConverter); + } + catch (Exception e) + { + Logger.Warning($"Failed to register {type.FullDescription()}: {e}"); } } } + } - internal static void Initialize() - { - ChainloaderHooks.PluginLoad += plugin => Register(plugin.GetType().Assembly); - } + internal static void Initialize() + { + ChainloaderHooks.PluginLoad += plugin => Register(plugin.GetType().Assembly); } } diff --git a/Reactor/Networking/Serialization/MessageSerializer.cs b/Reactor/Networking/Serialization/MessageSerializer.cs index cb8d74f..e01cb08 100644 --- a/Reactor/Networking/Serialization/MessageSerializer.cs +++ b/Reactor/Networking/Serialization/MessageSerializer.cs @@ -5,152 +5,151 @@ using Hazel; using Reactor.Extensions; using UnityEngine; -namespace Reactor.Networking.Serialization +namespace Reactor.Networking.Serialization; + +public static class MessageSerializer { - public static class MessageSerializer + private static List MessageConverters { get; } = new(); + + private static Dictionary MessageConverterMap { get; } = new(); + + public static void Register(UnsafeMessageConverter messageConverter) { - private static List MessageConverters { get; } = new List(); + MessageConverters.Add(messageConverter); + MessageConverterMap.Clear(); + } - private static Dictionary MessageConverterMap { get; } = new Dictionary(); - - public static void Register(UnsafeMessageConverter messageConverter) + public static UnsafeMessageConverter? FindConverter(Type type) + { + if (MessageConverterMap.TryGetValue(type, out var value)) { - MessageConverters.Add(messageConverter); - MessageConverterMap.Clear(); + return value; } - public static UnsafeMessageConverter? FindConverter(Type type) + var converter = MessageConverters.SingleOrDefault(x => x.CanConvert(type)); + MessageConverterMap.Add(type, converter); + + return converter; + } + + public static void Serialize(MessageWriter writer, object[] args) + { + foreach (var arg in args) { - if (MessageConverterMap.TryGetValue(type, out var value)) - { - return value; - } - - var converter = MessageConverters.SingleOrDefault(x => x.CanConvert(type)); - MessageConverterMap.Add(type, converter); - - return converter; - } - - public static void Serialize(MessageWriter writer, object[] args) - { - foreach (var arg in args) - { - writer.Serialize(arg); - } - } - - public static void Serialize(this MessageWriter writer, object o) - { - switch (o) - { - case int i: - writer.WritePacked(i); - break; - case uint i: - writer.WritePacked(i); - break; - case byte i: - writer.Write(i); - break; - case float i: - writer.Write(i); - break; - case sbyte i: - writer.Write(i); - break; - case ushort i: - writer.Write(i); - break; - case bool i: - writer.Write(i); - break; - case Vector2 i: - writer.Write(i); - break; - case string i: - writer.Write(i); - break; - default: - var converter = FindConverter(o.GetType()); - if (converter != null) - { - converter.UnsafeWrite(writer, o); - break; - } - - throw new NotSupportedException("Couldn't serialize " + o.GetType()); - } - } - - public static object[] Deserialize(MessageReader reader, MethodRpc.MethodRpc methodRpc) - { - var parameters = methodRpc.Method.GetParameters(); - var args = new object[parameters.Length - 1]; - - for (var i = 1; i < parameters.Length; i++) - { - var parameter = parameters[i]; - args[i - 1] = reader.Deserialize(parameter.ParameterType); - } - - return args; - } - - public static object Deserialize(this MessageReader reader, Type t) - { - if (t == typeof(int)) - { - return reader.ReadPackedInt32(); - } - - if (t == typeof(uint)) - { - return reader.ReadPackedUInt32(); - } - - if (t == typeof(byte)) - { - return reader.ReadByte(); - } - - if (t == typeof(float)) - { - return reader.ReadSingle(); - } - - if (t == typeof(sbyte)) - { - return reader.ReadSByte(); - } - - if (t == typeof(ushort)) - { - return reader.ReadUInt16(); - } - - if (t == typeof(bool)) - { - return reader.ReadBoolean(); - } - - if (t == typeof(Vector2)) - { - return reader.ReadVector2(); - } - - if (t == typeof(string)) - { - return reader.ReadString(); - } - - var converter = FindConverter(t); - if (converter != null) - { - return converter.UnsafeRead(reader, t); - } - - throw new NotSupportedException("Couldn't deserialize " + t); + writer.Serialize(arg); } } + + public static void Serialize(this MessageWriter writer, object o) + { + switch (o) + { + case int i: + writer.WritePacked(i); + break; + case uint i: + writer.WritePacked(i); + break; + case byte i: + writer.Write(i); + break; + case float i: + writer.Write(i); + break; + case sbyte i: + writer.Write(i); + break; + case ushort i: + writer.Write(i); + break; + case bool i: + writer.Write(i); + break; + case Vector2 i: + writer.Write(i); + break; + case string i: + writer.Write(i); + break; + default: + var converter = FindConverter(o.GetType()); + if (converter != null) + { + converter.UnsafeWrite(writer, o); + break; + } + + throw new NotSupportedException("Couldn't serialize " + o.GetType()); + } + } + + public static object[] Deserialize(MessageReader reader, MethodRpc.MethodRpc methodRpc) + { + var parameters = methodRpc.Method.GetParameters(); + var args = new object[parameters.Length - 1]; + + for (var i = 1; i < parameters.Length; i++) + { + var parameter = parameters[i]; + args[i - 1] = reader.Deserialize(parameter.ParameterType); + } + + return args; + } + + public static object Deserialize(this MessageReader reader, Type t) + { + if (t == typeof(int)) + { + return reader.ReadPackedInt32(); + } + + if (t == typeof(uint)) + { + return reader.ReadPackedUInt32(); + } + + if (t == typeof(byte)) + { + return reader.ReadByte(); + } + + if (t == typeof(float)) + { + return reader.ReadSingle(); + } + + if (t == typeof(sbyte)) + { + return reader.ReadSByte(); + } + + if (t == typeof(ushort)) + { + return reader.ReadUInt16(); + } + + if (t == typeof(bool)) + { + return reader.ReadBoolean(); + } + + if (t == typeof(Vector2)) + { + return reader.ReadVector2(); + } + + if (t == typeof(string)) + { + return reader.ReadString(); + } + + var converter = FindConverter(t); + if (converter != null) + { + return converter.UnsafeRead(reader, t); + } + + throw new NotSupportedException("Couldn't deserialize " + t); + } } diff --git a/Reactor/Networking/UnsafeCustomRpc.cs b/Reactor/Networking/UnsafeCustomRpc.cs index 4be1a5a..97e843e 100644 --- a/Reactor/Networking/UnsafeCustomRpc.cs +++ b/Reactor/Networking/UnsafeCustomRpc.cs @@ -4,74 +4,73 @@ using BepInEx.IL2CPP; using Hazel; using InnerNet; -namespace Reactor.Networking +namespace Reactor.Networking; + +public abstract class UnsafeCustomRpc { - public abstract class UnsafeCustomRpc + internal CustomRpcManager? Manager { get; set; } + protected internal virtual bool IsSingleton => true; + + 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) { - internal CustomRpcManager? Manager { get; set; } - protected internal virtual bool IsSingleton => true; + UnsafePlugin = plugin; + PluginId = MetadataHelper.GetMetadata(plugin).GUID; + Id = id; + } - public uint Id { get; } - public BasePlugin UnsafePlugin { get; } - public string PluginId { get; } + public abstract void UnsafeWrite(MessageWriter writer, object? data); + public abstract object? UnsafeRead(MessageReader reader); + public abstract void UnsafeHandle(InnerNetObject innerNetObject, object? data); - public abstract Type InnerNetObjectType { get; } + public void UnsafeSend(InnerNetObject innerNetObject, object? data, bool immediately = false, int targetClientId = -1) + { + if (innerNetObject == null) throw new ArgumentNullException(nameof(innerNetObject)); - public virtual SendOption SendOption => SendOption.Reliable; - public abstract RpcLocalHandling LocalHandling { get; } - - protected UnsafeCustomRpc(BasePlugin plugin, uint id) + if (Manager == null) { - UnsafePlugin = plugin; - PluginId = MetadataHelper.GetMetadata(plugin).GUID; - Id = id; + throw new InvalidOperationException("Can't send unregistered CustomRpc"); } - 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 innerNetObject, object? data, bool immediately = false, int targetClientId = -1) + if (LocalHandling == RpcLocalHandling.Before) { - if (innerNetObject == null) throw new ArgumentNullException(nameof(innerNetObject)); + UnsafeHandle(innerNetObject, data); + } - if (Manager == null) - { - throw new InvalidOperationException("Can't send unregistered CustomRpc"); - } + var writer = immediately switch + { + false => AmongUsClient.Instance.StartRpc(innerNetObject.NetId, CustomRpcManager.CallId, SendOption), + true => AmongUsClient.Instance.StartRpcImmediately(innerNetObject.NetId, CustomRpcManager.CallId, SendOption, targetClientId), + }; - if (LocalHandling == RpcLocalHandling.Before) - { - UnsafeHandle(innerNetObject, data); - } + var pluginNetId = ModList.GetById(PluginId).NetId; + writer.WritePacked(pluginNetId); + writer.WritePacked(Id); - var writer = immediately switch - { - false => AmongUsClient.Instance.StartRpc(innerNetObject.NetId, CustomRpcManager.CallId, SendOption), - true => AmongUsClient.Instance.StartRpcImmediately(innerNetObject.NetId, CustomRpcManager.CallId, SendOption, targetClientId) - }; + writer.StartMessage(0); + UnsafeWrite(writer, data); + writer.EndMessage(); - var pluginNetId = ModList.GetById(PluginId).NetId; - writer.WritePacked(pluginNetId); - writer.WritePacked(Id); - - writer.StartMessage(0); - UnsafeWrite(writer, data); + if (immediately) + { + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + else + { writer.EndMessage(); + } - if (immediately) - { - AmongUsClient.Instance.FinishRpcImmediately(writer); - } - else - { - writer.EndMessage(); - } - - if (LocalHandling == RpcLocalHandling.After) - { - UnsafeHandle(innerNetObject, data); - } + if (LocalHandling == RpcLocalHandling.After) + { + UnsafeHandle(innerNetObject, data); } } } diff --git a/Reactor/Patches/BetterGuestPatch.cs b/Reactor/Patches/BetterGuestPatch.cs index 8c32db5..73cef30 100644 --- a/Reactor/Patches/BetterGuestPatch.cs +++ b/Reactor/Patches/BetterGuestPatch.cs @@ -1,19 +1,17 @@ using HarmonyLib; using InnerNet; -using UnityEngine; -namespace Reactor.Patches +namespace Reactor.Patches; + +internal static class BetterGuestPatch { - internal static class BetterGuestPatch + [HarmonyPatch(typeof(SaveManager), nameof(SaveManager.ChatModeType), MethodType.Getter)] + public static class ChatModeTypePatch { - [HarmonyPatch(typeof(SaveManager), nameof(SaveManager.ChatModeType), MethodType.Getter)] - public static class ChatModeTypePatch + public static bool Prefix(out QuickChatModes __result) { - public static bool Prefix(out QuickChatModes __result) - { - __result = QuickChatModes.FreeChatOrQuickChat; - return false; - } + __result = QuickChatModes.FreeChatOrQuickChat; + return false; } } } diff --git a/Reactor/Patches/CursorPosPatch.cs b/Reactor/Patches/CursorPosPatch.cs index 3ebe3af..33f6739 100644 --- a/Reactor/Patches/CursorPosPatch.cs +++ b/Reactor/Patches/CursorPosPatch.cs @@ -3,23 +3,22 @@ using HarmonyLib; using TMPro; using UnityEngine; -namespace Reactor.Patches -{ - /// - /// "Fixes" an issue where empty TextBoxes have wrong cursor positions - /// - [HarmonyPatch(typeof(TextMeshProExtensions), nameof(TextMeshProExtensions.CursorPos))] - internal static class CursorPosPatch - { - public static bool Prefix(TextMeshPro self, ref Vector2 __result) - { - if (self.textInfo == null || self.textInfo.lineCount == 0 || self.textInfo.lineInfo[0].characterCount <= 0) - { - __result = self.GetTextInfo(" ").lineInfo.First().lineExtents.max; - return false; - } +namespace Reactor.Patches; - return true; +/// +/// "Fixes" an issue where empty TextBoxes have wrong cursor positions +/// +[HarmonyPatch(typeof(TextMeshProExtensions), nameof(TextMeshProExtensions.CursorPos))] +internal static class CursorPosPatch +{ + public static bool Prefix(TextMeshPro self, ref Vector2 __result) + { + if (self.textInfo == null || self.textInfo.lineCount == 0 || self.textInfo.lineInfo[0].characterCount <= 0) + { + __result = self.GetTextInfo(" ").lineInfo.First().lineExtents.max; + return false; } + + return true; } } diff --git a/Reactor/Patches/CustomServersPatch.cs b/Reactor/Patches/CustomServersPatch.cs index 8f1a261..31eb84d 100644 --- a/Reactor/Patches/CustomServersPatch.cs +++ b/Reactor/Patches/CustomServersPatch.cs @@ -1,32 +1,31 @@ using HarmonyLib; -namespace Reactor.Patches -{ - [HarmonyPatch] - internal static class CustomServersPatch - { - [HarmonyPatch(typeof(AuthManager._CoConnect_d__4), nameof(AuthManager._CoConnect_d__4.MoveNext))] - [HarmonyPatch(typeof(AuthManager._CoWaitForNonce_d__6), nameof(AuthManager._CoWaitForNonce_d__6.MoveNext))] - [HarmonyPrefix] - public static bool DisableAuthServerPatch(out bool __result) - { - __result = false; - return false; - } +namespace Reactor.Patches; - [HarmonyPatch(typeof(AmongUsClient._CoJoinOnlinePublicGame_d__1), nameof(AmongUsClient._CoJoinOnlinePublicGame_d__1.MoveNext))] - [HarmonyPrefix] - public static void EnableUdpMatchmakingPatch(AmongUsClient._CoJoinOnlinePublicGame_d__1 __instance) +[HarmonyPatch] +internal static class CustomServersPatch +{ + [HarmonyPatch(typeof(AuthManager._CoConnect_d__4), nameof(AuthManager._CoConnect_d__4.MoveNext))] + [HarmonyPatch(typeof(AuthManager._CoWaitForNonce_d__6), nameof(AuthManager._CoWaitForNonce_d__6.MoveNext))] + [HarmonyPrefix] + public static bool DisableAuthServerPatch(out bool __result) + { + __result = false; + return false; + } + + [HarmonyPatch(typeof(AmongUsClient._CoJoinOnlinePublicGame_d__1), nameof(AmongUsClient._CoJoinOnlinePublicGame_d__1.MoveNext))] + [HarmonyPrefix] + public static void EnableUdpMatchmakingPatch(AmongUsClient._CoJoinOnlinePublicGame_d__1 __instance) + { + // Skip to state 1 which just calls CoJoinOnlineGameDirect + if (__instance.__1__state == 0 && !ServerManager.Instance.IsHttp) { - // Skip to state 1 which just calls CoJoinOnlineGameDirect - if (__instance.__1__state == 0 && !ServerManager.Instance.IsHttp) + __instance.__1__state = 1; + __instance.__8__1 = new AmongUsClient.__c__DisplayClass1_0 { - __instance.__1__state = 1; - __instance.__8__1 = new AmongUsClient.__c__DisplayClass1_0 - { - matchmakerToken = string.Empty, - }; - } + matchmakerToken = string.Empty, + }; } } } diff --git a/Reactor/Patches/FreeNamePatch.cs b/Reactor/Patches/FreeNamePatch.cs index b25c6fd..a34c566 100644 --- a/Reactor/Patches/FreeNamePatch.cs +++ b/Reactor/Patches/FreeNamePatch.cs @@ -7,66 +7,66 @@ using UnityEngine; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; -namespace Reactor.Patches +namespace Reactor.Patches; + +public static class FreeNamePatch { - public static class FreeNamePatch + [HarmonyPatch(typeof(AccountManager), nameof(AccountManager.CheckAndRegenerateName))] + internal static class ValidateRandomNamePatch { - [HarmonyPatch(typeof(AccountManager), nameof(AccountManager.CheckAndRegenerateName))] - internal static class ValidateRandomNamePatch + public static bool Prefix() { - public static bool Prefix() - { - return false; - } - } - - public static void Initialize() - { - SceneManager.add_sceneLoaded((Action) ((scene, _) => - { - if (!scene.name.Equals("MMOnline")) return; - if (!TryMoveObjects()) return; - - var editName = DestroyableSingleton.Instance.accountTab.editNameScreen; - var nameText = Object.Instantiate(editName.nameText.gameObject); - - nameText.transform.localPosition += Vector3.up * 2.2f; - - var textBox = nameText.GetComponent(); - textBox.outputText.alignment = TextAlignmentOptions.CenterGeoAligned; - textBox.outputText.transform.position = nameText.transform.position; - textBox.outputText.fontSize = 4f; - - textBox.OnChange.AddListener((Action) (() => { - SaveManager.PlayerName = textBox.text; - })); - textBox.OnEnter = textBox.OnFocusLost = textBox.OnChange; - - textBox.Pipe.GetComponent().fontSize = 4f; - })); - } - - private static bool TryMoveObjects() - { - var toMove = new List - { - "HostGameButton", - "FindGameButton", - "JoinGameButton" - }; - - var yStart = Vector3.up; - var yOffset = Vector3.down * 1.5f; - - var gameObjects = toMove.Select(x => GameObject.Find("NormalMenu/" + x)).ToList(); - if (gameObjects.Any(x => x == null)) return false; - - for (var i = 0; i < gameObjects.Count; i++) - { - gameObjects[i].transform.position = yStart + (yOffset * i); - } - - return true; + return false; } } + + public static void Initialize() + { + SceneManager.add_sceneLoaded((Action) ((scene, _) => + { + if (!scene.name.Equals("MMOnline")) return; + if (!TryMoveObjects()) return; + + var editName = DestroyableSingleton.Instance.accountTab.editNameScreen; + var nameText = Object.Instantiate(editName.nameText.gameObject); + + nameText.transform.localPosition += Vector3.up * 2.2f; + + var textBox = nameText.GetComponent(); + textBox.outputText.alignment = TextAlignmentOptions.CenterGeoAligned; + textBox.outputText.transform.position = nameText.transform.position; + textBox.outputText.fontSize = 4f; + + textBox.OnChange.AddListener((Action) (() => + { + SaveManager.PlayerName = textBox.text; + })); + textBox.OnEnter = textBox.OnFocusLost = textBox.OnChange; + + textBox.Pipe.GetComponent().fontSize = 4f; + })); + } + + private static bool TryMoveObjects() + { + var toMove = new List + { + "HostGameButton", + "FindGameButton", + "JoinGameButton", + }; + + var yStart = Vector3.up; + var yOffset = Vector3.down * 1.5f; + + var gameObjects = toMove.Select(x => GameObject.Find("NormalMenu/" + x)).ToList(); + if (gameObjects.Any(x => x == null)) return false; + + for (var i = 0; i < gameObjects.Count; i++) + { + gameObjects[i].transform.position = yStart + (yOffset * i); + } + + return true; + } } diff --git a/Reactor/Patches/PlayerIdPatch.cs b/Reactor/Patches/PlayerIdPatch.cs index c56f1f4..395acf8 100644 --- a/Reactor/Patches/PlayerIdPatch.cs +++ b/Reactor/Patches/PlayerIdPatch.cs @@ -1,26 +1,25 @@ using System.Linq; using HarmonyLib; -namespace Reactor.Patches +namespace Reactor.Patches; + +internal static class PlayerIdPatch { - internal static class PlayerIdPatch + [HarmonyPatch(typeof(GameData), nameof(GameData.GetAvailableId))] + public static class GetAvailableIdPatch { - [HarmonyPatch(typeof(GameData), nameof(GameData.GetAvailableId))] - public static class GetAvailableIdPatch + public static bool Prefix(GameData __instance, out sbyte __result) { - public static bool Prefix(GameData __instance, out sbyte __result) + sbyte i = 0; + + while (__instance.AllPlayers.ToArray().Any(p => p.PlayerId == i)) { - sbyte i = 0; - - while (__instance.AllPlayers.ToArray().Any(p => p.PlayerId == i)) - { - i++; - } - - __result = i; - - return false; + i++; } + + __result = i; + + return false; } } } diff --git a/Reactor/Patches/ReactorVersionShower.cs b/Reactor/Patches/ReactorVersionShower.cs index a68113b..957a69e 100644 --- a/Reactor/Patches/ReactorVersionShower.cs +++ b/Reactor/Patches/ReactorVersionShower.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using BepInEx; using BepInEx.IL2CPP; using HarmonyLib; @@ -8,68 +7,67 @@ using TMPro; using UnityEngine; using UnityEngine.SceneManagement; -namespace Reactor.Patches +namespace Reactor.Patches; + +public static class ReactorVersionShower { - public static class ReactorVersionShower + public static TextMeshPro? Text { get; private set; } + + public static event TextUpdatedHandler? TextUpdated; + + public delegate void TextUpdatedHandler(TextMeshPro text); + + internal static void Initialize() { - public static TextMeshPro? Text { get; private set; } - - public static event TextUpdatedHandler? TextUpdated; - - public delegate void TextUpdatedHandler(TextMeshPro text); - - internal static void Initialize() + SceneManager.add_sceneLoaded((Action) ((_, _) => { - SceneManager.add_sceneLoaded((Action) ((_, _) => - { - var original = UnityEngine.Object.FindObjectOfType(); - if (!original) - return; + var original = UnityEngine.Object.FindObjectOfType(); + if (!original) + return; - var gameObject = new GameObject("ReactorVersion " + Guid.NewGuid()); - gameObject.transform.parent = original.transform.parent; + var gameObject = new GameObject("ReactorVersion " + Guid.NewGuid()); + gameObject.transform.parent = original.transform.parent; - var aspectPosition = gameObject.AddComponent(); + var aspectPosition = gameObject.AddComponent(); - aspectPosition.Alignment = AspectPosition.EdgeAlignments.LeftTop; + aspectPosition.Alignment = AspectPosition.EdgeAlignments.LeftTop; - var originalAspectPosition = original.GetComponent(); - var originalPosition = originalAspectPosition.DistanceFromEdge; - originalPosition.y = 0.15f; - originalAspectPosition.DistanceFromEdge = originalPosition; - originalAspectPosition.AdjustPosition(); + var originalAspectPosition = original.GetComponent(); + var originalPosition = originalAspectPosition.DistanceFromEdge; + originalPosition.y = 0.15f; + originalAspectPosition.DistanceFromEdge = originalPosition; + originalAspectPosition.AdjustPosition(); - var position = originalPosition; - position.x += 10.075f - 0.1f; - position.y += 2.75f - 0.15f; - position.z -= 1; - aspectPosition.DistanceFromEdge = position; + var position = originalPosition; + position.x += 10.075f - 0.1f; + position.y += 2.75f - 0.15f; + position.z -= 1; + aspectPosition.DistanceFromEdge = position; - aspectPosition.AdjustPosition(); + aspectPosition.AdjustPosition(); - Text = gameObject.AddComponent(); - Text.fontSize = 2; + Text = gameObject.AddComponent(); + Text.fontSize = 2; - UpdateText(); - })); - } + UpdateText(); + })); + } - public static void UpdateText() + public static void UpdateText() + { + Text!.text = "Reactor " + typeof(ReactorPlugin).Assembly.GetCustomAttribute().InformationalVersion; + Text.text += "\nBepInEx " + Paths.BepInExVersion; + Text.text += "\nMods: " + IL2CPPChainloader.Instance.Plugins.Count; + TextUpdated?.Invoke(Text); + } + + [HarmonyPatch(typeof(FreeWeekendShower), nameof(FreeWeekendShower.Start))] + private static class FreeWeekendShowerPatch + { + public static bool Prefix(FreeWeekendShower __instance) { - Text!.text = "Reactor " + typeof(ReactorPlugin).Assembly.GetCustomAttribute().InformationalVersion; - Text.text += "\nBepInEx " + Paths.BepInExVersion; - Text.text += "\nMods: " + IL2CPPChainloader.Instance.Plugins.Count; - TextUpdated?.Invoke(Text); - } - - [HarmonyPatch(typeof(FreeWeekendShower), nameof(FreeWeekendShower.Start))] - private static class FreeWeekendShowerPatch - { - public static bool Prefix(FreeWeekendShower __instance) - { - __instance.Output.Destroy(); - return false; - } + __instance.Output.Destroy(); + return false; } } } diff --git a/Reactor/Patches/RegionInfoWatcher.cs b/Reactor/Patches/RegionInfoWatcher.cs index ccc4562..e9a02ee 100644 --- a/Reactor/Patches/RegionInfoWatcher.cs +++ b/Reactor/Patches/RegionInfoWatcher.cs @@ -6,83 +6,82 @@ using Reactor.Extensions; using UnityEngine; using Object = UnityEngine.Object; -namespace Reactor.Patches +namespace Reactor.Patches; + +internal class RegionInfoWatcher : IDisposable { - internal class RegionInfoWatcher : IDisposable + private FileSystemWatcher Watcher { get; } + + public bool IgnoreNext { get; set; } + + internal RegionInfoWatcher() { - private FileSystemWatcher Watcher { get; } + Watcher = new FileSystemWatcher( + string.IsNullOrEmpty(Application.persistentDataPath) ? Directory.GetCurrentDirectory() : Application.persistentDataPath, + "regionInfo.json" + ); - public bool IgnoreNext { get; set; } - - internal RegionInfoWatcher() + Watcher.Changed += (s, e) => { - Watcher = new FileSystemWatcher( - string.IsNullOrEmpty(Application.persistentDataPath) ? Directory.GetCurrentDirectory() : Application.persistentDataPath, - "regionInfo.json" - ); - - Watcher.Changed += (s, e) => + if (new FileInfo(e.Name).Length > 0) { - if (new FileInfo(e.Name).Length > 0) + if (IgnoreNext) { - if (IgnoreNext) + IgnoreNext = false; + return; + } + + Dispatcher.Instance.Enqueue(() => + { + ServerManager.Instance.LoadServers(); + + Object.FindObjectOfType()?.Start(); + if (Object.FindObjectOfType() is { } regionMenu) { - IgnoreNext = false; - return; + regionMenu.OnDisable(); + regionMenu.OnEnable(); } - Dispatcher.Instance.Enqueue(() => - { - ServerManager.Instance.LoadServers(); + Logger.Info("Region file reloaded"); + }); + } + }; - Object.FindObjectOfType()?.Start(); - if (Object.FindObjectOfType() is { } regionMenu) - { - regionMenu.OnDisable(); - regionMenu.OnEnable(); - } + Watcher.EnableRaisingEvents = true; + } - Logger.Info("Region file reloaded"); - }); - } - }; + public void Dispose() + { + Watcher.Dispose(); + } - Watcher.EnableRaisingEvents = true; + [HarmonyPatch] + private static class WritePatch + { + public static MethodBase TargetMethod() + { + var type = Type.GetType("FileIO, Assembly-CSharp", false) ?? Type.GetType("Innersloth.IO.FileIO, Assembly-CSharp", true); + return AccessTools.Method(type, "WriteAllText"); } - public void Dispose() + public static bool Prefix(string path, string contents) { - Watcher.Dispose(); - } - - [HarmonyPatch] - private static class WritePatch - { - public static MethodBase TargetMethod() + // Among Us' region loading code unfortunately contains a call + // to SaveServers, which will write out the region file. This + // will lead to a positive feedback loop when detecting writes, + // which is undesireable. So we check if the write makes a + // change to the file on disk and if it would write the same + // file again, stop AU from actually writing it. + if (ServerManager.Instance && path == ServerManager.Instance.serverInfoFileJson) { - var type = Type.GetType("FileIO, Assembly-CSharp", false) ?? Type.GetType("Innersloth.IO.FileIO, Assembly-CSharp", true); - return AccessTools.Method(type, "WriteAllText"); + var continueWrite = !File.Exists(path) || File.ReadAllText(path) != contents; + Logger.Debug($"Continue serverInfoFile write? {continueWrite}"); + // If we will write, ignore the next change action from the observer. + PluginSingleton.Instance.RegionInfoWatcher.IgnoreNext = continueWrite; + return continueWrite; } - - public static bool Prefix(string path, string contents) - { - // Among Us' region loading code unfortunately contains a call - // to SaveServers, which will write out the region file. This - // will lead to a positive feedback loop when detecting writes, - // which is undesireable. So we check if the write makes a - // change to the file on disk and if it would write the same - // file again, stop AU from actually writing it. - if (ServerManager.Instance && path == ServerManager.Instance.serverInfoFileJson) - { - var continueWrite = !File.Exists(path) || File.ReadAllText(path) != contents; - Logger.Debug($"Continue serverInfoFile write? {continueWrite}"); - // If we will write, ignore the next change action from the observer. - PluginSingleton.Instance.RegionInfoWatcher.IgnoreNext = continueWrite; - return continueWrite; - } - return true; - } + return true; } } } diff --git a/Reactor/Patches/ServerInfoFixes.cs b/Reactor/Patches/ServerInfoFixes.cs index 3b1c073..488f3d7 100644 --- a/Reactor/Patches/ServerInfoFixes.cs +++ b/Reactor/Patches/ServerInfoFixes.cs @@ -5,47 +5,46 @@ using System.Net.Sockets; using HarmonyLib; using InnerNet; -namespace Reactor.Patches +namespace Reactor.Patches; + +[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.Connect))] +public static class ConnectPatch { - [HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.Connect))] - public static class ConnectPatch + public static void Prefix(InnerNetClient __instance) { - public static void Prefix(InnerNetClient __instance) - { - Logger.Info($"Joining {__instance.networkAddress}:{__instance.networkPort}"); - } + Logger.Info($"Joining {__instance.networkAddress}:{__instance.networkPort}"); } +} - /// - /// Fixes hardcoded port and filters out IPv6 in DnsRegionInfo - /// - [HarmonyPatch(typeof(DnsRegionInfo), nameof(DnsRegionInfo.PopulateServers))] - public static class PopulateServersPatch +/// +/// Fixes hardcoded port and filters out IPv6 in DnsRegionInfo +/// +[HarmonyPatch(typeof(DnsRegionInfo), nameof(DnsRegionInfo.PopulateServers))] +public static class PopulateServersPatch +{ + public static bool Prefix(DnsRegionInfo __instance) { - public static bool Prefix(DnsRegionInfo __instance) + try { - try - { - var i = 0; - var servers = Dns.GetHostAddresses(__instance.Fqdn) - .Distinct() - .Where(ipAddress => ipAddress.AddressFamily == AddressFamily.InterNetwork) - .Select(ipAddress => new ServerInfo($"{__instance.Name}-{i++}", ipAddress.ToString(), __instance.Port, __instance.UseDtls)) - .ToArray(); + var i = 0; + var servers = Dns.GetHostAddresses(__instance.Fqdn) + .Distinct() + .Where(ipAddress => ipAddress.AddressFamily == AddressFamily.InterNetwork) + .Select(ipAddress => new ServerInfo($"{__instance.Name}-{i++}", ipAddress.ToString(), __instance.Port, __instance.UseDtls)) + .ToArray(); - __instance.cachedServers = servers; - Logger.Info($"Populated {__instance.Name} ({__instance.Fqdn}:{__instance.Port}) with {servers.Length} server(s) {{{servers.Select(x => x.ToString()).Join()}}}"); - } - catch (Exception e) + __instance.cachedServers = servers; + Logger.Info($"Populated {__instance.Name} ({__instance.Fqdn}:{__instance.Port}) with {servers.Length} server(s) {{{servers.Select(x => x.ToString()).Join()}}}"); + } + catch (Exception e) + { + Logger.Info($"Failed to populate {__instance.Name}: {e}"); + __instance.cachedServers = new[] { - Logger.Info($"Failed to populate {__instance.Name}: {e}"); - __instance.cachedServers = new[] - { - new ServerInfo(__instance.Name ?? string.Empty, __instance.DefaultIp, __instance.Port, __instance.UseDtls), - }; - } + new ServerInfo(__instance.Name ?? string.Empty, __instance.DefaultIp, __instance.Port, __instance.UseDtls), + }; + } - return false; - } + return false; } } diff --git a/Reactor/Patches/SplashSkip.cs b/Reactor/Patches/SplashSkip.cs index d4f4f3b..ce9bcd7 100644 --- a/Reactor/Patches/SplashSkip.cs +++ b/Reactor/Patches/SplashSkip.cs @@ -1,43 +1,42 @@ using System.Reflection; using HarmonyLib; -namespace Reactor.Patches +namespace Reactor.Patches; + +[HarmonyPatch(typeof(SplashManager), nameof(SplashManager.Start))] +internal static class SplashSkip { - [HarmonyPatch(typeof(SplashManager), nameof(SplashManager.Start))] - internal static class SplashSkip + private static void Prefix(SplashManager __instance) { - private static void Prefix(SplashManager __instance) + __instance.minimumSecondsBeforeSceneChange = 0; + } +} + +[HarmonyPatch(typeof(SplashManager), nameof(SplashManager.Update))] +internal static class WaitForEpicAuth +{ + private static readonly PropertyInfo? _localUserIdProperty = typeof(EpicManager).GetProperty("localUserId", BindingFlags.Static | BindingFlags.Public); + private static bool _loginFinished; + + private static bool Prefix(SplashManager __instance) + { + if (__instance.startedSceneLoad) return true; + + if (_localUserIdProperty != null && !_loginFinished) { - __instance.minimumSecondsBeforeSceneChange = 0; + return false; } + + return true; } - [HarmonyPatch(typeof(SplashManager), nameof(SplashManager.Update))] - internal static class WaitForEpicAuth + // EpicManager calls SaveManager.LoadPlayerPrefs(true) both on successful and unsuccessful EOS login + [HarmonyPatch(typeof(SaveManager), nameof(SaveManager.LoadPlayerPrefs))] + private static class LoadPlayerPrefsPatch { - private static readonly PropertyInfo? _localUserIdProperty = typeof(EpicManager).GetProperty("localUserId", BindingFlags.Static | BindingFlags.Public); - private static bool _loginFinished; - - private static bool Prefix(SplashManager __instance) + private static void Postfix(bool overrideLoad) { - if (__instance.startedSceneLoad) return true; - - if (_localUserIdProperty != null && !_loginFinished) - { - return false; - } - - return true; - } - - // EpicManager calls SaveManager.LoadPlayerPrefs(true) both on successful and unsuccessful EOS login - [HarmonyPatch(typeof(SaveManager), nameof(SaveManager.LoadPlayerPrefs))] - private static class LoadPlayerPrefsPatch - { - private static void Postfix(bool overrideLoad) - { - if (overrideLoad) _loginFinished = true; - } + if (overrideLoad) _loginFinished = true; } } } diff --git a/Reactor/Patches/SteamPatch.cs b/Reactor/Patches/SteamPatch.cs index 000fbc3..4d9a071 100644 --- a/Reactor/Patches/SteamPatch.cs +++ b/Reactor/Patches/SteamPatch.cs @@ -3,37 +3,36 @@ using System.IO; using System.Reflection; using HarmonyLib; -namespace Reactor.Patches +namespace Reactor.Patches; + +internal static class SteamPatch { - internal static class SteamPatch + [HarmonyPatch] + public static class RestartAppIfNecessaryPatch { - [HarmonyPatch] - public static class RestartAppIfNecessaryPatch + public const string TypeName = "Steamworks.SteamAPI, Assembly-CSharp-firstpass"; + public const string MethodName = "RestartAppIfNecessary"; + + public static bool Prepare() { - public const string TypeName = "Steamworks.SteamAPI, Assembly-CSharp-firstpass"; - public const string MethodName = "RestartAppIfNecessary"; + return Type.GetType(TypeName, false) != null; + } - public static bool Prepare() + public static MethodBase TargetMethod() + { + return AccessTools.Method(TypeName + ":" + MethodName); + } + + public static bool Prefix(out bool __result) + { + const string file = "steam_appid.txt"; + + if (!File.Exists(file)) { - return Type.GetType(TypeName, false) != null; + File.WriteAllText(file, "945360"); } - public static MethodBase TargetMethod() - { - return AccessTools.Method(TypeName + ":" + MethodName); - } - - public static bool Prefix(out bool __result) - { - const string file = "steam_appid.txt"; - - if (!File.Exists(file)) - { - File.WriteAllText(file, "945360"); - } - - return __result = false; - } + return __result = false; } } } diff --git a/Reactor/PluginSingleton.cs b/Reactor/PluginSingleton.cs index 0edfac0..aa08c90 100644 --- a/Reactor/PluginSingleton.cs +++ b/Reactor/PluginSingleton.cs @@ -2,22 +2,21 @@ using System.Linq; using System.Reflection; using BepInEx.IL2CPP; -namespace Reactor +namespace Reactor; + +public static class PluginSingleton where T : BasePlugin { - public static class PluginSingleton where T : BasePlugin + private static T? _instance; + + public static T Instance => _instance ??= IL2CPPChainloader.Instance.Plugins.Values.Select(x => x.Instance).OfType().Single(); + + internal static void Initialize() { - private static T? _instance; - - public static T Instance => _instance ??= IL2CPPChainloader.Instance.Plugins.Values.Select(x => x.Instance).OfType().Single(); - - internal static void Initialize() + ChainloaderHooks.PluginLoad += plugin => { - ChainloaderHooks.PluginLoad += plugin => - { - typeof(PluginSingleton<>).MakeGenericType(plugin.GetType())! - .GetField(nameof(_instance), BindingFlags.Static | BindingFlags.NonPublic)! - .SetValue(null, plugin); - }; - } + typeof(PluginSingleton<>).MakeGenericType(plugin.GetType())! + .GetField(nameof(_instance), BindingFlags.Static | BindingFlags.NonPublic)! + .SetValue(null, plugin); + }; } } diff --git a/Reactor/ReactorPlugin.cs b/Reactor/ReactorPlugin.cs index 5bfff6f..2d6b5a3 100644 --- a/Reactor/ReactorPlugin.cs +++ b/Reactor/ReactorPlugin.cs @@ -14,93 +14,92 @@ using UnhollowerBaseLib.Attributes; using UnityEngine; using UnityEngine.SceneManagement; -namespace Reactor +namespace Reactor; + +[BepInAutoPlugin("gg.reactor.api")] +[BepInProcess("Among Us.exe")] +public partial class ReactorPlugin : BasePlugin { - [BepInAutoPlugin("gg.reactor.api")] - [BepInProcess("Among Us.exe")] - public partial class ReactorPlugin : BasePlugin + public Harmony Harmony { get; } = new(Id); + public CustomRpcManager CustomRpcManager { get; } = new(); + + public ConfigEntry? AllowVanillaServers { get; private set; } + + internal RegionInfoWatcher RegionInfoWatcher { get; } = new(); + + public ReactorPlugin() { - public Harmony Harmony { get; } = new Harmony(Id); - public CustomRpcManager CustomRpcManager { get; } = new CustomRpcManager(); + PluginSingleton.Initialize(); + RegisterInIl2CppAttribute.Initialize(); + RegisterCustomRpcAttribute.Initialize(); + MessageConverterAttribute.Initialize(); + MethodRpcAttribute.Initialize(); - public ConfigEntry? AllowVanillaServers { get; private set; } + ChainloaderHooks.OnPluginLoad(this); + } - internal RegionInfoWatcher RegionInfoWatcher { get; } = new RegionInfoWatcher(); + public override void Load() + { + AllowVanillaServers = Config.Bind("Features", "Allow vanilla servers", false, "Whether reactor should ignore servers not responding to modded handshake. This config is ignored if any plugin uses custom rpcs!"); - public ReactorPlugin() + Harmony.PatchAll(); + + this.AddComponent().Plugin = this; + this.AddComponent(); + this.AddComponent(); + + ReactorVersionShower.Initialize(); + FreeNamePatch.Initialize(); + DefaultBundle.Load(); + + SceneManager.add_sceneLoaded((Action) ((scene, _) => { - PluginSingleton.Initialize(); - RegisterInIl2CppAttribute.Initialize(); - RegisterCustomRpcAttribute.Initialize(); - MessageConverterAttribute.Initialize(); - MethodRpcAttribute.Initialize(); - - ChainloaderHooks.OnPluginLoad(this); - } - - public override void Load() - { - AllowVanillaServers = Config.Bind("Features", "Allow vanilla servers", false, "Whether reactor should ignore servers not responding to modded handshake. This config is ignored if any plugin uses custom rpcs!"); - - Harmony.PatchAll(); - - this.AddComponent().Plugin = this; - this.AddComponent(); - this.AddComponent(); - - ReactorVersionShower.Initialize(); - FreeNamePatch.Initialize(); - DefaultBundle.Load(); - - SceneManager.add_sceneLoaded((Action) ((scene, _) => - { - if (scene.name == "MainMenu") - { - ModManager.Instance.ShowModStamp(); - } - })); - } - - public override bool Unload() - { - Harmony.UnpatchSelf(); - RegionInfoWatcher?.Dispose(); - - return base.Unload(); - } - - [RegisterInIl2Cpp] - public class ReactorComponent : MonoBehaviour - { - [HideFromIl2Cpp] - public ReactorPlugin? Plugin { get; internal set; } - - public ReactorComponent(IntPtr ptr) : base(ptr) + if (scene.name == "MainMenu") { + ModManager.Instance.ShowModStamp(); } + })); + } - private void Update() + public override bool Unload() + { + Harmony.UnpatchSelf(); + RegionInfoWatcher?.Dispose(); + + return base.Unload(); + } + + [RegisterInIl2Cpp] + public class ReactorComponent : MonoBehaviour + { + [HideFromIl2Cpp] + public ReactorPlugin? Plugin { get; internal set; } + + public ReactorComponent(IntPtr ptr) : base(ptr) + { + } + + private void Update() + { + if (Input.GetKeyDown(KeyCode.F5)) { - if (Input.GetKeyDown(KeyCode.F5)) + Plugin!.Log.LogInfo("Reloading all configs"); + + foreach (var pluginInfo in IL2CPPChainloader.Instance.Plugins.Values) { - Plugin!.Log.LogInfo("Reloading all configs"); - - foreach (var pluginInfo in IL2CPPChainloader.Instance.Plugins.Values) + var config = ((BasePlugin) pluginInfo.Instance).Config; + if (!config.Any()) { - var config = ((BasePlugin) pluginInfo.Instance).Config; - if (!config.Any()) - { - continue; - } + continue; + } - try - { - config.Reload(); - } - catch (Exception e) - { - Plugin.Log.LogWarning($"Exception occured during reload of {pluginInfo.Metadata.Name}: {e}"); - } + try + { + config.Reload(); + } + catch (Exception e) + { + Plugin.Log.LogWarning($"Exception occured during reload of {pluginInfo.Metadata.Name}: {e}"); } } } diff --git a/Reactor/ReactorPluginSideAttribute.cs b/Reactor/ReactorPluginSideAttribute.cs index 9b53cd3..ccbf36e 100644 --- a/Reactor/ReactorPluginSideAttribute.cs +++ b/Reactor/ReactorPluginSideAttribute.cs @@ -2,36 +2,35 @@ using System; using System.Linq; using System.Reflection; -namespace Reactor +namespace Reactor; + +/// +/// This attribute specifies plugin's side +/// +[AttributeUsage(AttributeTargets.Class)] +public class ReactorPluginSideAttribute : Attribute { - /// - /// This attribute specifies plugin's side - /// - [AttributeUsage(AttributeTargets.Class)] - public class ReactorPluginSideAttribute : Attribute + public PluginSide Side { get; } + + public ReactorPluginSideAttribute(PluginSide side) { - public PluginSide Side { get; } + Side = side; + } - public ReactorPluginSideAttribute(PluginSide side) + public static PluginSide GetPluginSide(Type type) + { + var attribute = type.GetCustomAttribute(); + if (attribute != null) { - Side = side; + return attribute.Side; } - public static PluginSide GetPluginSide(Type type) + var metadataAttribute = type.Assembly.GetCustomAttributes().SingleOrDefault(x => x.Key == "Reactor.PluginSide"); + if (metadataAttribute != null) { - var attribute = type.GetCustomAttribute(); - if (attribute != null) - { - return attribute.Side; - } - - var metadataAttribute = type.Assembly.GetCustomAttributes().SingleOrDefault(x => x.Key == "Reactor.PluginSide"); - if (metadataAttribute != null) - { - return Enum.Parse(metadataAttribute.Value, true); - } - - return PluginSide.Both; + return Enum.Parse(metadataAttribute.Value, true); } + + return PluginSide.Both; } } diff --git a/Reactor/RegisterCustomRpcAttribute.cs b/Reactor/RegisterCustomRpcAttribute.cs index c32f00a..e722e27 100644 --- a/Reactor/RegisterCustomRpcAttribute.cs +++ b/Reactor/RegisterCustomRpcAttribute.cs @@ -4,48 +4,47 @@ using BepInEx.IL2CPP; using HarmonyLib; using Reactor.Networking; -namespace Reactor +namespace Reactor; + +/// +/// Utility attribute for automatically registering CustomRpc +/// +[AttributeUsage(AttributeTargets.Class)] +public class RegisterCustomRpcAttribute : Attribute { - /// - /// Utility attribute for automatically registering CustomRpc - /// - [AttributeUsage(AttributeTargets.Class)] - public class RegisterCustomRpcAttribute : Attribute + public uint Id { get; } + + public RegisterCustomRpcAttribute(uint id) { - public uint Id { get; } + Id = id; + } - public RegisterCustomRpcAttribute(uint id) - { - Id = id; - } + [Obsolete("You don't need to call this anymore", true)] + public static void Register(BasePlugin plugin) + { + } - [Obsolete("You don't need to call this anymore", true)] - public static void Register(BasePlugin plugin) + public static void Register(Assembly assembly, BasePlugin plugin) + { + foreach (var type in assembly.GetTypes()) { - } + var attribute = type.GetCustomAttribute(); - public static void Register(Assembly assembly, BasePlugin plugin) - { - foreach (var type in assembly.GetTypes()) + if (attribute != null) { - var attribute = type.GetCustomAttribute(); - - if (attribute != null) + if (!type.IsSubclassOf(typeof(UnsafeCustomRpc))) { - if (!type.IsSubclassOf(typeof(UnsafeCustomRpc))) - { - throw new InvalidOperationException($"Type {type.FullDescription()} has {nameof(RegisterCustomRpcAttribute)} but doesn't extend {nameof(UnsafeCustomRpc)}."); - } - - var customRpc = (UnsafeCustomRpc) Activator.CreateInstance(type, plugin, attribute.Id); - PluginSingleton.Instance.CustomRpcManager.Register(customRpc); + throw new InvalidOperationException($"Type {type.FullDescription()} has {nameof(RegisterCustomRpcAttribute)} but doesn't extend {nameof(UnsafeCustomRpc)}."); } + + var customRpc = (UnsafeCustomRpc) Activator.CreateInstance(type, plugin, attribute.Id); + PluginSingleton.Instance.CustomRpcManager.Register(customRpc); } } + } - internal static void Initialize() - { - ChainloaderHooks.PluginLoad += plugin => Register(plugin.GetType().Assembly, plugin); - } + internal static void Initialize() + { + ChainloaderHooks.PluginLoad += plugin => Register(plugin.GetType().Assembly, plugin); } } diff --git a/Reactor/RegisterInIl2CppAttribute.cs b/Reactor/RegisterInIl2CppAttribute.cs index 7b8cbf3..5530fc5 100644 --- a/Reactor/RegisterInIl2CppAttribute.cs +++ b/Reactor/RegisterInIl2CppAttribute.cs @@ -3,69 +3,68 @@ using System.Reflection; using HarmonyLib; using UnhollowerRuntimeLib; -namespace Reactor +namespace Reactor; + +/// +/// Utility attribute for automatically calling +/// +[AttributeUsage(AttributeTargets.Class)] +public class RegisterInIl2CppAttribute : Attribute { - /// - /// Utility attribute for automatically calling - /// - [AttributeUsage(AttributeTargets.Class)] - public class RegisterInIl2CppAttribute : Attribute + public Type[] Interfaces { get; } + + public RegisterInIl2CppAttribute() { - public Type[] Interfaces { get; } + Interfaces = Type.EmptyTypes; + } - public RegisterInIl2CppAttribute() + public RegisterInIl2CppAttribute(params Type[] interfaces) + { + Interfaces = interfaces; + } + + [Obsolete("You don't need to call this anymore", true)] + public static void Register() + { + } + + private static void Register(Type type, Type[] interfaces) + { + var baseTypeAttribute = type.BaseType?.GetCustomAttribute(); + if (baseTypeAttribute != null) { - Interfaces = Type.EmptyTypes; + Register(type.BaseType!, baseTypeAttribute.Interfaces); } - public RegisterInIl2CppAttribute(params Type[] interfaces) + if (ClassInjector.IsTypeRegisteredInIl2Cpp(type)) { - Interfaces = interfaces; + return; } - [Obsolete("You don't need to call this anymore", true)] - public static void Register() + try { + ClassInjector.RegisterTypeInIl2Cpp(type, new RegisterTypeOptions { Interfaces = interfaces }); } - - private static void Register(Type type, Type[] interfaces) + catch (Exception e) { - var baseTypeAttribute = type.BaseType?.GetCustomAttribute(); - if (baseTypeAttribute != null) - { - Register(type.BaseType!, baseTypeAttribute.Interfaces); - } - - if (ClassInjector.IsTypeRegisteredInIl2Cpp(type)) - { - return; - } - - try - { - ClassInjector.RegisterTypeInIl2Cpp(type, new RegisterTypeOptions { Interfaces = interfaces }); - } - catch (Exception e) - { - Logger.Warning($"Failed to register {type.FullDescription()}: {e}"); - } - } - - public static void Register(Assembly assembly) - { - foreach (var type in assembly.GetTypes()) - { - var attribute = type.GetCustomAttribute(); - if (attribute != null) - { - Register(type, attribute.Interfaces); - } - } - } - - internal static void Initialize() - { - ChainloaderHooks.PluginLoad += plugin => Register(plugin.GetType().Assembly); + Logger.Warning($"Failed to register {type.FullDescription()}: {e}"); } } + + public static void Register(Assembly assembly) + { + foreach (var type in assembly.GetTypes()) + { + var attribute = type.GetCustomAttribute(); + if (attribute != null) + { + Register(type, attribute.Interfaces); + } + } + } + + internal static void Initialize() + { + ChainloaderHooks.PluginLoad += plugin => Register(plugin.GetType().Assembly); + } } diff --git a/Reactor/Unstrip/DefaultBundle.cs b/Reactor/Unstrip/DefaultBundle.cs index c955809..d2549a3 100644 --- a/Reactor/Unstrip/DefaultBundle.cs +++ b/Reactor/Unstrip/DefaultBundle.cs @@ -2,34 +2,33 @@ using Reactor.Extensions; using UnityEngine; using UnityEngine.UI; -namespace Reactor.Unstrip +namespace Reactor.Unstrip; + +internal static class DefaultBundle { - internal static class DefaultBundle + public static void Load() { - public static void Load() + using var stream = typeof(ReactorPlugin).Assembly.GetManifestResourceStream("Reactor.Assets.default.bundle")!; + var bundle = AssetBundle.LoadFromStream(stream.AsIl2Cpp()); + + var backupShader = bundle.LoadAsset("UI-Default"); + + if (!Graphic.defaultGraphicMaterial.shader || Graphic.defaultGraphicMaterial.shader.name != "UI/Default") { - using var stream = typeof(ReactorPlugin).Assembly.GetManifestResourceStream("Reactor.Assets.default.bundle")!; - var bundle = AssetBundle.LoadFromStream(stream.AsIl2Cpp()); - - var backupShader = bundle.LoadAsset("UI-Default"); - - if (!Graphic.defaultGraphicMaterial.shader || Graphic.defaultGraphicMaterial.shader.name != "UI/Default") - { - Graphic.defaultGraphicMaterial.shader = backupShader; - } - - GUIExtensions.StandardResources = new DefaultControls.Resources - { - background = bundle.LoadAsset("Background")!.DontUnload(), - checkmark = bundle.LoadAsset("Checkmark")!.DontUnload(), - dropdown = bundle.LoadAsset("DropdownArrow")!.DontUnload(), - knob = bundle.LoadAsset("Knob")!.DontUnload(), - mask = bundle.LoadAsset("UIMask")!.DontUnload(), - standard = bundle.LoadAsset("UISprite")!.DontUnload(), - inputField = bundle.LoadAsset("InputFieldBackground")!.DontUnload() - }; - - bundle.Unload(false); + Graphic.defaultGraphicMaterial.shader = backupShader; } + + GUIExtensions.StandardResources = new DefaultControls.Resources + { + background = bundle.LoadAsset("Background")!.DontUnload(), + checkmark = bundle.LoadAsset("Checkmark")!.DontUnload(), + dropdown = bundle.LoadAsset("DropdownArrow")!.DontUnload(), + knob = bundle.LoadAsset("Knob")!.DontUnload(), + mask = bundle.LoadAsset("UIMask")!.DontUnload(), + standard = bundle.LoadAsset("UISprite")!.DontUnload(), + inputField = bundle.LoadAsset("InputFieldBackground")!.DontUnload(), + }; + + bundle.Unload(false); } }