diff --git a/AmongUs.props b/AmongUs.props
index 5c84ddf..624e8aa 100644
--- a/AmongUs.props
+++ b/AmongUs.props
@@ -10,7 +10,7 @@
- NuclearPowered/Mappings:0.1.0
+ NuclearPowered/Mappings:0.1.1
diff --git a/Reactor.Example/ExamplePlugin.cs b/Reactor.Example/ExamplePlugin.cs
index 3959961..f64d39e 100644
--- a/Reactor.Example/ExamplePlugin.cs
+++ b/Reactor.Example/ExamplePlugin.cs
@@ -38,8 +38,8 @@ namespace Reactor.Example
if (Input.GetKeyDown(KeyCode.F3) && AmongUsClient.Instance && PlayerControl.LocalPlayer)
{
Plugin.Log.LogWarning("Sending example rpc");
- PlayerControl.LocalPlayer.Send(new ExampleRpc.Data("Cześć :)"));
- PlayerControl.LocalPlayer.SendTo(AmongUsClient.Instance.HostId, new ExampleRpc.Data("host :O"));
+ Rpc.Instance.Send(new ExampleRpc.Data("Cześć :)"));
+ Rpc.Instance.SendTo(AmongUsClient.Instance.HostId, new ExampleRpc.Data("host :O"));
}
}
}
diff --git a/Reactor.Example/ExampleRpc.cs b/Reactor.Example/ExampleRpc.cs
index 178bbd6..f95bd45 100644
--- a/Reactor.Example/ExampleRpc.cs
+++ b/Reactor.Example/ExampleRpc.cs
@@ -3,7 +3,7 @@ using Hazel;
namespace Reactor.Example
{
[RegisterCustomRpc]
- public class ExampleRpc : CustomRpc
+ public class ExampleRpc : PlayerCustomRpc
{
public ExampleRpc(ExamplePlugin plugin) : base(plugin)
{
diff --git a/Reactor/CustomRpc.cs b/Reactor/CustomRpc.cs
index 7a27694..0e49c4a 100644
--- a/Reactor/CustomRpc.cs
+++ b/Reactor/CustomRpc.cs
@@ -23,11 +23,13 @@ namespace Reactor
{
public int? Id { get; internal set; }
+ internal CustomRpcManager Manager { get; set; }
public BasePlugin UnsafePlugin { get; }
public string PluginId { get; }
public abstract Type InnerNetObjectType { get; }
+ public virtual SendOption SendOption { get; } = SendOption.Reliable;
public abstract RpcLocalHandling LocalHandling { get; }
protected UnsafeCustomRpc(BasePlugin plugin)
@@ -39,6 +41,54 @@ namespace Reactor
public abstract void UnsafeWrite(MessageWriter writer, object data);
public abstract object UnsafeRead(MessageReader reader);
public abstract void UnsafeHandle(InnerNetObject innerNetObject, object data);
+
+ public void UnsafeSend(InnerNetObject netObject, object data, bool immediately = false, int targetClientId = -1)
+ {
+ if (netObject == null) throw new ArgumentNullException(nameof(netObject));
+ if (data == null) throw new ArgumentNullException(nameof(data));
+
+ if (Id == null)
+ {
+ throw new InvalidOperationException("Can't send unregistered CustomRpc");
+ }
+
+ if (LocalHandling == RpcLocalHandling.Before)
+ {
+ UnsafeHandle(netObject, data);
+ }
+
+ var writer = immediately switch
+ {
+ false => AmongUsClient.Instance.StartRpc(netObject.NetId, CustomRpcManager.CallId, SendOption),
+ true => AmongUsClient.Instance.StartRpcImmediately(netObject.NetId, CustomRpcManager.CallId, SendOption, targetClientId)
+ };
+
+ if (Manager.PluginIdMap.TryGetValue(PluginId, out var pluginId))
+ {
+ writer.WritePacked(pluginId);
+ }
+ else
+ {
+ writer.Write(PluginId);
+ }
+
+ writer.WritePacked(Id!.Value);
+ UnsafeWrite(writer, data);
+
+ if (immediately)
+ {
+ AmongUsClient.Instance.FinishRpcImmediately(writer);
+ }
+ else
+ {
+ writer.EndMessage();
+ }
+
+ if (LocalHandling == RpcLocalHandling.After)
+ {
+ UnsafeHandle(netObject, data);
+ }
+ }
}
public abstract class CustomRpc : UnsafeCustomRpc where TPlugin : BasePlugin where TInnerNetObject : InnerNetObject
@@ -68,6 +118,33 @@ namespace Reactor
{
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 PlayerCustomRpc : CustomRpc where TPlugin : BasePlugin
+ {
+ protected PlayerCustomRpc(TPlugin plugin) : base(plugin)
+ {
+ }
+
+ 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 class CustomRpcManager
@@ -114,72 +191,16 @@ namespace Reactor
public UnsafeCustomRpc Register(UnsafeCustomRpc customRpc)
{
+ customRpc.Manager = this;
customRpc.Id = List.Count(x => x.UnsafePlugin == customRpc.UnsafePlugin);
_list.Add(customRpc);
_map[customRpc.InnerNetObjectType].Add(customRpc);
+ typeof(Rpc<>).MakeGenericType(customRpc.GetType()).GetProperty("Instance")!.SetValue(null, customRpc);
+
return customRpc;
}
- public void Send(InnerNetObject netObject, object data, bool immediately = false)
- {
- UnsafeSend(netObject, List.Single(x => x.GetType() == typeof(TCustomRpc)), data, immediately);
- }
-
- public void SendTo(InnerNetObject netObject, int targetId, object data)
- {
- UnsafeSend(netObject, List.Single(x => x.GetType() == typeof(TCustomRpc)), data, true, targetId);
- }
-
- public void UnsafeSend(InnerNetObject netObject, UnsafeCustomRpc customRpc, object data, bool immediately = false, int targetClientId = -1)
- {
- if (netObject == null) throw new ArgumentNullException(nameof(netObject));
- if (customRpc == null) throw new ArgumentNullException(nameof(customRpc));
- if (data == null) throw new ArgumentNullException(nameof(data));
-
- if (customRpc.Id == null)
- {
- throw new InvalidOperationException("Can't send unregistered CustomRpc");
- }
-
- if (customRpc.LocalHandling == RpcLocalHandling.Before)
- {
- customRpc.UnsafeHandle(netObject, data);
- }
-
- var writer = immediately switch
- {
- false => AmongUsClient.Instance.StartRpc(netObject.NetId, CallId, SendOption.Reliable),
- true => AmongUsClient.Instance.StartRpcImmediately(netObject.NetId, CallId, SendOption.Reliable, targetClientId)
- };
-
- if (PluginIdMap.TryGetValue(customRpc.PluginId, out var pluginId))
- {
- writer.WritePacked(pluginId);
- }
- else
- {
- writer.Write(customRpc.PluginId);
- }
-
- writer.WritePacked(customRpc.Id!.Value);
- customRpc.UnsafeWrite(writer, data);
-
- if (immediately)
- {
- AmongUsClient.Instance.FinishRpcImmediately(writer);
- }
- else
- {
- writer.EndMessage();
- }
-
- if (customRpc.LocalHandling == RpcLocalHandling.After)
- {
- customRpc.UnsafeHandle(netObject, data);
- }
- }
-
[HarmonyPatch]
private static class HandleRpcPatch
{
@@ -225,4 +246,32 @@ namespace Reactor
}
}
}
+
+ public static class Rpc where T : UnsafeCustomRpc
+ {
+ private static T _instance;
+
+ public static T Instance
+ {
+ get
+ {
+ if (_instance == null)
+ {
+ throw new Exception($"{typeof(T).FullName} isn't registered");
+ }
+
+ return _instance;
+ }
+
+ internal set
+ {
+ if (_instance != null)
+ {
+ throw new Exception($"{typeof(T).FullName} is already registered");
+ }
+
+ _instance = value;
+ }
+ }
+ }
}
diff --git a/Reactor/Extensions/Extensions.cs b/Reactor/Extensions/Extensions.cs
index 62a7c66..1ac340c 100644
--- a/Reactor/Extensions/Extensions.cs
+++ b/Reactor/Extensions/Extensions.cs
@@ -122,14 +122,16 @@ namespace Reactor.Extensions
return type.GetMethods(AccessTools.all).Where(x => x.ReturnType == returnType && x.GetParameters().Select(x => x.ParameterType).SequenceEqual(parameterTypes));
}
- public static void Send(this InnerNetObject netObject, object data, bool immediately = false)
+ [Obsolete("Use Rpc.Instance.Send", true)]
+ public static void Send(this InnerNetObject netObject, object data, bool immediately = false) where TCustomRpc : UnsafeCustomRpc
{
- PluginSingleton.Instance.CustomRpcManager.Send(netObject, data, immediately);
+ Rpc.Instance.UnsafeSend(netObject, data, immediately);
}
- public static void SendTo(this InnerNetObject netObject, int targetId, object data)
+ [Obsolete("Use Rpc.Instance.SendTo", true)]
+ public static void SendTo(this InnerNetObject netObject, int targetId, object data) where TCustomRpc : UnsafeCustomRpc
{
- PluginSingleton.Instance.CustomRpcManager.SendTo(netObject, targetId, data);
+ Rpc.Instance.UnsafeSend(netObject, data, true, targetId);
}
}
}
diff --git a/Reactor/Extensions/GUIExtensions.cs b/Reactor/Extensions/GUIExtensions.cs
index cdc2340..ac97f5a 100644
--- a/Reactor/Extensions/GUIExtensions.cs
+++ b/Reactor/Extensions/GUIExtensions.cs
@@ -116,6 +116,11 @@ namespace Reactor.Extensions
{
Rect = Rect.ResetSize();
Rect = GUILayout.Window(Id, Rect, Func, Title, new Il2CppReferenceArray(0));
+
+ if (Rect.Contains(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y)))
+ {
+ Input.ResetInputAxes();
+ }
}
}
}
diff --git a/Reactor/Extensions/PlayerControlExtensions.cs b/Reactor/Extensions/PlayerControlExtensions.cs
new file mode 100644
index 0000000..9b4a5c7
--- /dev/null
+++ b/Reactor/Extensions/PlayerControlExtensions.cs
@@ -0,0 +1,17 @@
+using UnityEngine;
+
+namespace Reactor.Extensions
+{
+ public static class PlayerControlExtensions
+ {
+ public static Color32 ToPlayerColor(this PlayerColor color)
+ {
+ return Palette.PlayerColors[(byte) color];
+ }
+
+ public static Color32 ToShadowColor(this PlayerColor color)
+ {
+ return Palette.ShadowColors[(byte) color];
+ }
+ }
+}
diff --git a/Reactor/IsExternalInit.cs b/Reactor/IsExternalInit.cs
new file mode 100644
index 0000000..a9deb2a
--- /dev/null
+++ b/Reactor/IsExternalInit.cs
@@ -0,0 +1,11 @@
+// https://stackoverflow.com/questions/64749385/predefined-type-system-runtime-compilerservices-isexternalinit-is-not-defined?noredirect=1&lq=1
+// IsExternalInit is not included with netstandard2.1 even tho it could
+
+// ReSharper disable CheckNamespace
+
+namespace System.Runtime.CompilerServices
+{
+ internal static class IsExternalInit
+ {
+ }
+}
diff --git a/Reactor/PlayerColor.cs b/Reactor/PlayerColor.cs
new file mode 100644
index 0000000..240e400
--- /dev/null
+++ b/Reactor/PlayerColor.cs
@@ -0,0 +1,18 @@
+namespace Reactor
+{
+ public enum PlayerColor : byte
+ {
+ Red,
+ Blue,
+ Green,
+ Pink,
+ Orange,
+ Yellow,
+ Black,
+ White,
+ Purple,
+ Brown,
+ Cyan,
+ Lime
+ }
+}
diff --git a/Reactor/PluginSingleton.cs b/Reactor/PluginSingleton.cs
index ed0a702..4741877 100644
--- a/Reactor/PluginSingleton.cs
+++ b/Reactor/PluginSingleton.cs
@@ -4,7 +4,7 @@ using BepInEx.IL2CPP;
namespace Reactor
{
- public class PluginSingleton where T : BasePlugin
+ public static class PluginSingleton where T : BasePlugin
{
private static T _instance;
diff --git a/Reactor/ReactorPlugin.cs b/Reactor/ReactorPlugin.cs
index dc9e626..5c47099 100644
--- a/Reactor/ReactorPlugin.cs
+++ b/Reactor/ReactorPlugin.cs
@@ -24,6 +24,7 @@ namespace Reactor
public ConfigEntry ModdedHandshake;
+ private GameObject _gameObject;
private RegionInfoWatcher RegionInfoWatcher { get; } = new RegionInfoWatcher();
public override void Load()
@@ -32,9 +33,9 @@ namespace Reactor
ModdedHandshake = Config.Bind("Features", "Modded handshake", true);
- var gameObject = new GameObject(nameof(ReactorPlugin)).DontDestroy();
- gameObject.AddComponent().Plugin = this;
- gameObject.AddComponent();
+ _gameObject = new GameObject(nameof(ReactorPlugin)).DontDestroy();
+ _gameObject.AddComponent().Plugin = this;
+ _gameObject.AddComponent();
Harmony.PatchAll();
ReactorVersionShower.Initialize();
@@ -43,6 +44,8 @@ namespace Reactor
public override bool Unload()
{
+ Harmony.UnpatchSelf();
+ _gameObject.Destroy();
RegionInfoWatcher?.Dispose();
return base.Unload();
diff --git a/Reactor/RegisterInIl2CppAttribute.cs b/Reactor/RegisterInIl2CppAttribute.cs
index 87ec55c..3b046a9 100644
--- a/Reactor/RegisterInIl2CppAttribute.cs
+++ b/Reactor/RegisterInIl2CppAttribute.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Reflection;
using HarmonyLib;
using UnhollowerRuntimeLib;
@@ -16,24 +17,64 @@ namespace Reactor
Register(Assembly.GetCallingAssembly());
}
+ private static readonly AccessTools.FieldRef