method Rpc

This commit is contained in:
Zirno authored and js6pak committed 2021-07-26 17:07:57 +02:00
1 parent 0f0d322c8c
commit eb7fce3350
5 files changed
+407

No files matched your search

@@ -0,0 +1,60 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using BepInEx.IL2CPP;
using Hazel;
using InnerNet;
namespace Reactor.Networking.MethodRpc
{
public class CustomMethodRpc : UnsafeCustomRpc
{
public static readonly List<CustomMethodRpc> AllCustomMethodRpcs = new();
internal static bool SkipNextSend;
public CustomMethodRpc(BasePlugin plugin, MethodInfo method, uint id, SendOption option, RpcLocalHandling localHandling) : base(plugin, id)
{
Method = method;
LocalHandling = localHandling;
SendOption = option;
AllCustomMethodRpcs.Add(this);
}
public MethodInfo Method { get; }
public override Type InnerNetObjectType { get; } = typeof(PlayerControl);
public override RpcLocalHandling LocalHandling { get; }
public override SendOption SendOption { get; }
public override void UnsafeWrite(MessageWriter writer, object data)
{
var args = (object[]) data;
RpcSerializer.SendMassage(writer,args);
}
public override object UnsafeRead(MessageReader reader)
{
var args = RpcSerializer.Deserialize(reader,Method.GetParameters().Select(x => x.ParameterType).ToArray());
return args;
}
public override void UnsafeHandle(InnerNetObject innerNetObject, object data)
{
SkipNextSend = true;
var result = Method.Invoke(null,(object[]) data);
if (Method.ReturnParameter.ParameterType == typeof(IEnumerator))
{
Coroutines.Start((IEnumerator) result);
}
}
public void Send(object[] args)
{
UnsafeSend(PlayerControl.LocalPlayer,args);
}
}
}
@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using BepInEx.IL2CPP;
using HarmonyLib;
using Hazel;
namespace Reactor.Networking.MethodRpc
{
[AttributeUsage(AttributeTargets.Method)]
public class MethodRpcAttribute : Attribute
{
public byte id;
public SendOption option;
public RpcLocalHandling localHandling;
public MethodRpcAttribute( byte id, SendOption option = SendOption.Reliable, RpcLocalHandling localHandling = RpcLocalHandling.Before)
{
this.id = id;
this.option = option;
this.localHandling = localHandling;
}
public static void Register(Assembly assembly, BasePlugin plugin)
{
Logger<ReactorPlugin>.Info($"Registering Method Rpc for {assembly.GetName()}");
Dictionary<int, MethodInfo> serializeMethods = new();
MethodInfo serializeMethod;
int index = 0;
while ((serializeMethod = RpcSerializationHandels.GetHandleFor(index)) != null)
{
serializeMethods.Add(index, serializeMethod);
Logger<ReactorPlugin>.Debug($"Registered Rpc Serialization Handle for {index} args");
index++;
}
var rpcMethods = assembly.GetTypes()
.SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
.Where(m => m.GetCustomAttributes(typeof(MethodRpcAttribute), false).Length > 0)
.ToArray();
foreach (var method in rpcMethods)
{
if (!method.IsStatic)
{
Logger<ReactorPlugin>.Warning("Cannot register non static custom method rpc");
continue;
}
var seializer = serializeMethods[method.GetParameters().Length];
if (seializer == null)
{
Logger<ReactorPlugin>.Error($"Unsupported Args count, max is {RpcSerializationHandels.GetMaxArgs()}");
continue;
}
var attribute = method.GetCustomAttribute<MethodRpcAttribute>();
if (attribute.localHandling == RpcLocalHandling.Before)
{
PluginSingleton<ReactorPlugin>.Instance.Harmony.Patch(method, new HarmonyMethod(seializer));
}
else if (attribute.localHandling == RpcLocalHandling.After)
{
PluginSingleton<ReactorPlugin>.Instance.Harmony.Patch(method, postfix: new HarmonyMethod(seializer));
}
var customRpc = new CustomMethodRpc(plugin, method, attribute.id, attribute.option, attribute.localHandling);
try
{
PluginSingleton<ReactorPlugin>.Instance.CustomRpcManager.Register(customRpc);
}
catch (Exception)
{
// ignored
}
}
}
internal static void Initialize()
{
ChainloaderHooks.PluginLoad += plugin => Register(plugin.GetType().Assembly, plugin);
}
[MethodRpc(123)]
static void Hello()
{
}
}
}
@@ -0,0 +1,73 @@
using System.Linq;
using System.Reflection;
using HarmonyLib;
using Reactor.Networking;
using Reactor.Networking.MethodRpc;
namespace Reactor.Networking
{
internal class RpcSerializationHandels
{
public static MethodInfo GetHandleFor(int count)
{
return typeof(RpcSerializationHandels).GetRuntimeMethod(nameof(Serialize),
Enumerable.Repeat(typeof(MethodBase),1).Concat(Enumerable.Repeat(typeof(object), count)).ToArray());
}
public static int GetMaxArgs()
{
return typeof(RpcSerializationHandels).GetMethods().OrderBy(x => x.GetParameters().Length).Last().GetParameters().Length;
}
public static bool RpcPrefix(MethodBase originalMethod, params object[] list)
{
if (CustomMethodRpc.SkipNextSend)
{
CustomMethodRpc.SkipNextSend = false;
return true;
}
CustomMethodRpc methodRpc =
CustomMethodRpc.AllCustomMethodRpcs.FirstOrDefault(x => x.Method == originalMethod);
typeof(CustomMethodRpc).GetMethod(nameof(CustomMethodRpc.Send))?.Invoke(methodRpc,new object[]{list});
return false;
}
public static bool Serialize(MethodBase __originalMethod)
{
return RpcPrefix(__originalMethod);
}
public static bool Serialize(MethodBase __originalMethod, [HarmonyArgument(0)] object arg0)
{
return RpcPrefix(__originalMethod,arg0);
}
public static bool Serialize(MethodBase __originalMethod, [HarmonyArgument(0)] object arg0,[HarmonyArgument(1)] object arg1)
{
return RpcPrefix(__originalMethod,new object[]{arg0,arg1});
}
public static bool Serialize(MethodBase __originalMethod, [HarmonyArgument(0)] object arg0 , [HarmonyArgument(1)] object arg1, [HarmonyArgument(2)] object arg2)
{
return RpcPrefix(__originalMethod,arg0,arg1,arg2);
}
public static bool Serialize(MethodBase __originalMethod, [HarmonyArgument(0)] object arg0 , [HarmonyArgument(1)] object arg1, [HarmonyArgument(2)] object arg2,[HarmonyArgument(3)] object arg3)
{
return RpcPrefix(__originalMethod,arg0,arg1,arg2,arg3);
}
public static bool Serialize(MethodBase __originalMethod, [HarmonyArgument(0)] object arg0 , [HarmonyArgument(1)] object arg1, [HarmonyArgument(2)] object arg2,[HarmonyArgument(3)] object arg3,[HarmonyArgument(4)] object arg4)
{
return RpcPrefix(__originalMethod,arg0,arg1,arg2,arg3,arg4);
}
public static bool Serialize(MethodBase __originalMethod, [HarmonyArgument(0)] object arg0 , [HarmonyArgument(1)] object arg1, [HarmonyArgument(2)] object arg2,[HarmonyArgument(3)] object arg3,[HarmonyArgument(4)] object arg4,[HarmonyArgument(5)] object arg5)
{
return RpcPrefix(__originalMethod,arg0,arg1,arg2,arg3,arg4,arg5);
}
}
}
@@ -0,0 +1,179 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Hazel;
using InnerNet;
using Reactor;
using Reactor.Extensions;
using Reactor.Networking.MethodRpc;
using UnityEngine;
namespace Reactor.Networking
{
public static class RpcSerializer
{
public static void SendMassage(MessageWriter writer, params object[] list)
{
Logger<ReactorPlugin>.Debug($"Serializing {list.Length} object");
foreach (var o in list)
{
if (o.GetType().IsValueType && !o.GetType().IsPrimitive)
{
var structFeilds = o.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (var feild in structFeilds)
{
writer.Write(feild.GetValue(o));
}
}
else
{
writer.Write(o);
}
}
}
public static void Write(this MessageWriter writer, object o)
{
switch (o)
{
case int i:
writer.WritePacked(i);
Logger<ReactorPlugin>.Debug($"Serialized int");
break;
case uint i:
writer.WritePacked(i);
Logger<ReactorPlugin>.Debug($"Serialized uint");
break;
case byte i:
writer.Write(i);
Logger<ReactorPlugin>.Debug($"Serialized byte");
break;
case float i:
writer.Write(i);
Logger<ReactorPlugin>.Debug($"Serialized float");
break;
case sbyte i:
writer.Write(i);
Logger<ReactorPlugin>.Debug($"Serialized sbyte");
break;
case ushort i:
writer.Write(i);
Logger<ReactorPlugin>.Debug($"Serialized ushort");
break;
case bool i:
writer.Write(i);
Logger<ReactorPlugin>.Debug($"Serialized bool");
break;
case Vector2 i:
writer.Write(i);
Logger<ReactorPlugin>.Debug($"Serialized Vector2");
break;
case string i:
writer.Write(i);
Logger<ReactorPlugin>.Debug($"Serialized string");
break;
default:
if (o.GetType().IsSubclassOf(typeof(InnerNetObject)))
{
Logger<ReactorPlugin>.Debug($"Serialized {nameof(InnerNetObject)}");
writer.WritePacked(((InnerNetObject)o).NetId);
}
else
{
Logger<ReactorPlugin>.Warning($"Tried serializing unsupported type {nameof(o)}");
}
break;
}
}
public static object[] Deserialize(MessageReader reader, Type[] list)
{
Logger<ReactorPlugin>.Debug($"Deserializing {list.Length} object");
List<object> args = new();
foreach (var t in list)
{
if (t.IsValueType && !t.IsPrimitive)
{
List<object> structArgs = new();
var feilds = t.GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (var feild in feilds)
{
structArgs.Add(reader.Read(feild.GetType()));
}
args.Add(Activator.CreateInstance(t, structArgs));
}
else
{
args.Add(reader.Read(t));
}
}
return args.ToArray();
}
public static object Read(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());
}
if (t.IsSubclassOf(typeof(InnerNetObject)))
{
return typeof(AmongUsClient).GetMethod(nameof(AmongUsClient.FindObjectByNetId)).MakeGenericMethod(t)
.Invoke(AmongUsClient.Instance, new object[]{reader.ReadPackedUInt32()});
}
Logger<ReactorPlugin>.Warning($"Tried deserializing unsupported type {t.BaseType.Name}");
return null;
}
}
}
+2
View File
@@ -6,6 +6,7 @@ using BepInEx.IL2CPP;
using HarmonyLib;
using Reactor.Extensions;
using Reactor.Networking;
using Reactor.Networking.MethodRpc;
using Reactor.Patches;
using Reactor.Unstrip;
using UnhollowerBaseLib.Attributes;
@@ -37,6 +38,7 @@ namespace Reactor
PluginSingleton<BasePlugin>.Initialize();
RegisterInIl2CppAttribute.Initialize();
RegisterCustomRpcAttribute.Initialize();
MethodRpcAttribute.Initialize();
ChainloaderHooks.OnPluginLoad(this);
}