mirror of
https://github.com/NuclearPowered/Reactor.git
synced 2026-10-19 15:51:54 +00:00
Add ReaderWriter for custom types
This commit is contained in:
1 parent
c6d2ff686b
commit
41413eea20
7 files changed
+152
-70
No files matched your search
@@ -27,32 +27,29 @@ namespace Reactor.Networking.MethodRpc
|
|||||||
|
|
||||||
var methodParameters = method.GetParameters();
|
var methodParameters = method.GetParameters();
|
||||||
|
|
||||||
List<Type> allArgs = new List<Type>();
|
Parameters = new Type[methodParameters.Length];
|
||||||
foreach (var arg in methodParameters)
|
for (var i = 0; i < methodParameters.Length; i++)
|
||||||
{
|
{
|
||||||
|
var arg = methodParameters[i];
|
||||||
var argType = arg.ParameterType;
|
var argType = arg.ParameterType;
|
||||||
if (argType.IsValueType && !argType.IsPrimitive && !StructBook.ContainsKey(arg.ParameterType))
|
if (argType.IsValueType && !argType.IsPrimitive && !StructBook.ContainsKey(arg.ParameterType))
|
||||||
{
|
{
|
||||||
var feilds = argType.GetFields(BindingFlags.Instance | BindingFlags.Public)
|
var fields = argType.GetFields(BindingFlags.Instance | BindingFlags.Public)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
StructBook.Add(argType, feilds);
|
StructBook.Add(argType, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
allArgs.Add(argType);
|
Parameters[i] = argType;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Parameters = allArgs.ToArray();
|
|
||||||
|
|
||||||
Invoker = RpcPrefixHandle.GenerateCaller(Method);
|
Invoker = RpcPrefixHandle.GenerateCaller(Method);
|
||||||
|
|
||||||
allMethodRPCsFast.Add(Method, this);
|
allMethodRPCsFast.Add(Method, this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodInfo Method { get; }
|
public MethodInfo Method { get; }
|
||||||
public override Type InnerNetObjectType { get; } = typeof(PlayerControl);
|
public override Type InnerNetObjectType { get; } = typeof(PlayerControl);
|
||||||
public override RpcLocalHandling LocalHandling { get; } = RpcLocalHandling.None;
|
public override RpcLocalHandling LocalHandling { get; }
|
||||||
public override SendOption SendOption { get; }
|
public override SendOption SendOption { get; }
|
||||||
|
|
||||||
public override void UnsafeWrite(MessageWriter writer, object data)
|
public override void UnsafeWrite(MessageWriter writer, object data)
|
||||||
@@ -76,6 +73,8 @@ namespace Reactor.Networking.MethodRpc
|
|||||||
{
|
{
|
||||||
Coroutines.Start((IEnumerator) result);
|
Coroutines.Start((IEnumerator) result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SkipNextSend = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Send(object[] args)
|
public void Send(object[] args)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace Reactor.Networking.MethodRpc
|
|||||||
|
|
||||||
foreach (var method in rpcMethods)
|
foreach (var method in rpcMethods)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!method.IsStatic)
|
if (!method.IsStatic)
|
||||||
{
|
{
|
||||||
Logger<ReactorPlugin>.Warning("Cannot register non static custom method rpc");
|
Logger<ReactorPlugin>.Warning("Cannot register non static custom method rpc");
|
||||||
@@ -45,7 +45,7 @@ namespace Reactor.Networking.MethodRpc
|
|||||||
}
|
}
|
||||||
|
|
||||||
var attribute = method.GetCustomAttribute<MethodRpcAttribute>();
|
var attribute = method.GetCustomAttribute<MethodRpcAttribute>();
|
||||||
|
|
||||||
var customRpc = new CustomMethodRpc(plugin, method, attribute.id, attribute.option,
|
var customRpc = new CustomMethodRpc(plugin, method, attribute.id, attribute.option,
|
||||||
attribute.localHandling);
|
attribute.localHandling);
|
||||||
PluginSingleton<ReactorPlugin>.Instance.Harmony.Patch(method, new HarmonyMethod(_rpcPrefixGenerator));
|
PluginSingleton<ReactorPlugin>.Instance.Harmony.Patch(method, new HarmonyMethod(_rpcPrefixGenerator));
|
||||||
@@ -58,9 +58,8 @@ namespace Reactor.Networking.MethodRpc
|
|||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
internal static void Initialize()
|
internal static void Initialize()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Hazel;
|
||||||
|
|
||||||
|
namespace Reactor.Networking.MethodRpc
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class ReaderWriterManager
|
||||||
|
{
|
||||||
|
public static ReaderWriterManager Instance { get; } = new();
|
||||||
|
|
||||||
|
private readonly Dictionary<Type, UnsafeReaderWriter> _readerWriters = new();
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<Type, UnsafeReaderWriter> All => _readerWriters;
|
||||||
|
|
||||||
|
public void Register(UnsafeReaderWriter readerWriter)
|
||||||
|
{
|
||||||
|
Logger<ReactorPlugin>.Instance.LogInfo($"Registered ReaderWriter for {readerWriter.Type}");
|
||||||
|
if(_readerWriters.ContainsKey(readerWriter.Type)) return;
|
||||||
|
|
||||||
|
_readerWriters.Add(readerWriter.Type, readerWriter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class UnsafeReaderWriter
|
||||||
|
{
|
||||||
|
public abstract Type Type { get; }
|
||||||
|
public abstract void UnsafeWrite(MessageWriter writer, object dateTime);
|
||||||
|
|
||||||
|
public abstract object UnsafeRead(MessageReader reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class ReaderWriter<T> : UnsafeReaderWriter
|
||||||
|
{
|
||||||
|
public abstract void Write(MessageWriter writer, T o);
|
||||||
|
|
||||||
|
public abstract T Read(MessageReader reader);
|
||||||
|
|
||||||
|
public override Type Type { get; } = typeof(T);
|
||||||
|
|
||||||
|
public override void UnsafeWrite(MessageWriter writer, object o) => Write(writer, (T) o);
|
||||||
|
|
||||||
|
public override object UnsafeRead(MessageReader reader) => Read(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using BepInEx.IL2CPP;
|
||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
namespace Reactor.Networking.MethodRpc
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class ReaderWriterAttribute : System.Attribute
|
||||||
|
{
|
||||||
|
|
||||||
|
public static void Register(Assembly assembly, BasePlugin plugin)
|
||||||
|
{
|
||||||
|
foreach (var type in assembly.GetTypes())
|
||||||
|
{
|
||||||
|
var attribute = type.GetCustomAttribute<ReaderWriterAttribute>();
|
||||||
|
|
||||||
|
if (attribute != null)
|
||||||
|
{
|
||||||
|
if (!type.IsSubclassOf(typeof(UnsafeReaderWriter)))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Type {type.FullDescription()} has {nameof(ReaderWriterAttribute)} but doesn't extend {nameof(UnsafeReaderWriter)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var customRpc = (UnsafeReaderWriter) Activator.CreateInstance(type);
|
||||||
|
ReaderWriterManager.Instance.Register(customRpc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Initialize()
|
||||||
|
{
|
||||||
|
ChainloaderHooks.PluginLoad += plugin => Register(plugin.GetType().Assembly, plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,11 +14,7 @@ namespace Reactor.Networking.MethodRpc
|
|||||||
|
|
||||||
public static bool RpcPrefix(MethodBase originalMethod, params object[] list)
|
public static bool RpcPrefix(MethodBase originalMethod, params object[] list)
|
||||||
{
|
{
|
||||||
if (CustomMethodRpc.SkipNextSend)
|
if (CustomMethodRpc.SkipNextSend) return true;
|
||||||
{
|
|
||||||
CustomMethodRpc.SkipNextSend = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var methodRpc = CustomMethodRpc.allMethodRPCsFast[originalMethod];
|
var methodRpc = CustomMethodRpc.allMethodRPCsFast[originalMethod];
|
||||||
methodRpc?.Send(list);
|
methodRpc?.Send(list);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Hazel;
|
using Hazel;
|
||||||
using InnerNet;
|
using InnerNet;
|
||||||
@@ -10,29 +11,6 @@ namespace Reactor.Networking.MethodRpc
|
|||||||
{
|
{
|
||||||
public static class RpcSerializer
|
public static class RpcSerializer
|
||||||
{
|
{
|
||||||
#region GetFindObjectByNetIdInvoker
|
|
||||||
|
|
||||||
private static readonly MethodInfo _findObjectByNetId =
|
|
||||||
typeof(RpcSerializer).GetMethod(nameof(FindObjectByNetId), BindingFlags.Static | BindingFlags.NonPublic);
|
|
||||||
|
|
||||||
private static Dictionary<Type, Func<object[], object>> _findObjectByNetIdInvokers = new();
|
|
||||||
static Func<object[], object> GetFindObjectByNetIdInvoker(Type type)
|
|
||||||
{
|
|
||||||
if (_findObjectByNetIdInvokers.ContainsKey(type)) return _findObjectByNetIdInvokers[type];
|
|
||||||
|
|
||||||
var invoker = RpcPrefixHandle.GenerateCaller(_findObjectByNetId.MakeGenericMethod(type));
|
|
||||||
_findObjectByNetIdInvokers.Add(type, invoker);
|
|
||||||
return invoker;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static InnerNetObject FindObjectByNetId<T>(uint id) where T : InnerNetObject
|
|
||||||
{
|
|
||||||
return AmongUsClient.Instance.FindObjectByNetId<T>(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
public static void Serialize(MessageWriter writer,CustomMethodRpc methodRpc, params object[] list)
|
public static void Serialize(MessageWriter writer,CustomMethodRpc methodRpc, params object[] list)
|
||||||
{
|
{
|
||||||
foreach (var o in list)
|
foreach (var o in list)
|
||||||
@@ -49,6 +27,7 @@ namespace Reactor.Networking.MethodRpc
|
|||||||
{
|
{
|
||||||
writer.Write(o);
|
writer.Write(o);
|
||||||
}
|
}
|
||||||
|
Logger<ReactorPlugin>.Debug($"Serialized {o.GetType()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,51 +37,44 @@ namespace Reactor.Networking.MethodRpc
|
|||||||
{
|
{
|
||||||
case int i:
|
case int i:
|
||||||
writer.WritePacked(i);
|
writer.WritePacked(i);
|
||||||
Logger<ReactorPlugin>.Debug($"Serialized int");
|
|
||||||
break;
|
break;
|
||||||
case uint i:
|
case uint i:
|
||||||
writer.WritePacked(i);
|
writer.WritePacked(i);
|
||||||
Logger<ReactorPlugin>.Debug($"Serialized uint");
|
|
||||||
break;
|
break;
|
||||||
case byte i:
|
case byte i:
|
||||||
writer.Write(i);
|
writer.Write(i);
|
||||||
Logger<ReactorPlugin>.Debug($"Serialized byte");
|
|
||||||
break;
|
break;
|
||||||
case float i:
|
case float i:
|
||||||
writer.Write(i);
|
writer.Write(i);
|
||||||
Logger<ReactorPlugin>.Debug($"Serialized float");
|
|
||||||
break;
|
break;
|
||||||
case sbyte i:
|
case sbyte i:
|
||||||
writer.Write(i);
|
writer.Write(i);
|
||||||
Logger<ReactorPlugin>.Debug($"Serialized sbyte");
|
|
||||||
break;
|
break;
|
||||||
case ushort i:
|
case ushort i:
|
||||||
writer.Write(i);
|
writer.Write(i);
|
||||||
Logger<ReactorPlugin>.Debug($"Serialized ushort");
|
|
||||||
break;
|
break;
|
||||||
case bool i:
|
case bool i:
|
||||||
writer.Write(i);
|
writer.Write(i);
|
||||||
Logger<ReactorPlugin>.Debug($"Serialized bool");
|
|
||||||
break;
|
break;
|
||||||
case Vector2 i:
|
case Vector2 i:
|
||||||
writer.Write(i);
|
writer.Write(i);
|
||||||
Logger<ReactorPlugin>.Debug($"Serialized Vector2");
|
|
||||||
break;
|
break;
|
||||||
case string i:
|
case string i:
|
||||||
writer.Write(i);
|
writer.Write(i);
|
||||||
Logger<ReactorPlugin>.Debug($"Serialized string");
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (o.GetType().IsSubclassOf(typeof(InnerNetObject)))
|
if (o.GetType().IsSubclassOf(typeof(InnerNetObject)))
|
||||||
{
|
{
|
||||||
Logger<ReactorPlugin>.Debug($"Serialized {nameof(InnerNetObject)}");
|
writer.WriteNetObject((InnerNetObject) o);
|
||||||
writer.WritePacked(((InnerNetObject)o).NetId);
|
}
|
||||||
|
else if (ReaderWriterManager.Instance.All.ContainsKey(o.GetType()))
|
||||||
|
{
|
||||||
|
ReaderWriterManager.Instance.All[o.GetType()].UnsafeWrite(writer, o);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger<ReactorPlugin>.Warning($"Tried serializing unsupported type {nameof(o)}");
|
Logger<ReactorPlugin>.Warning($"Tried serializing unsupported type {o.GetType()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,33 +84,34 @@ namespace Reactor.Networking.MethodRpc
|
|||||||
{
|
{
|
||||||
Logger<ReactorPlugin>.Debug($"Deserializing {methodRpc.Parameters.Length} object");
|
Logger<ReactorPlugin>.Debug($"Deserializing {methodRpc.Parameters.Length} object");
|
||||||
|
|
||||||
List<object> args = new();
|
object[] args = new object[methodRpc.Parameters.Length];
|
||||||
|
|
||||||
foreach (var t in methodRpc.Parameters)
|
for (int i = 0; i < args.Length; i++)
|
||||||
{
|
{
|
||||||
|
Type t = methodRpc.Parameters[i];
|
||||||
if (t.IsValueType && !t.IsPrimitive)
|
if (t.IsValueType && !t.IsPrimitive)
|
||||||
{
|
{
|
||||||
List<object> structArgs = new();
|
var fields = methodRpc.StructBook[t];
|
||||||
var feilds = methodRpc.StructBook[t];
|
|
||||||
foreach (var feild in feilds)
|
|
||||||
{
|
|
||||||
var value = reader.Read(feild.FieldType);
|
|
||||||
Logger<ReactorPlugin>.Debug($"Read {value} of {feild.FieldType.Name} for {methodRpc.Method.Name}");
|
|
||||||
structArgs.Add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
args.Add(Activator.CreateInstance(t,args: structArgs.ToArray())); //Todo: Improve somehow
|
object[] structArgs = new object[fields.Length];
|
||||||
|
for (int n = 0; n < structArgs.Length; n++)
|
||||||
|
{
|
||||||
|
structArgs[n] = reader.Read(fields[n].FieldType);
|
||||||
|
Logger<ReactorPlugin>.Debug($"Deserialized {fields[n].FieldType} from {t}");
|
||||||
|
}
|
||||||
|
t.GetType().GetConstructors().ToList().ForEach(x=>Logger<ReactorPlugin>.Info($"Gw {x.GetParameters().Length}"));
|
||||||
|
|
||||||
|
args[i] = Activator.CreateInstance(t,structArgs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var value = reader.Read(t);
|
var value = reader.Read(t);
|
||||||
Logger<ReactorPlugin>.Debug($"Read {value} of {t.Name} for {methodRpc.Method.Name}");
|
Logger<ReactorPlugin>.Debug($"Read {value} of {t.Name} for {methodRpc.Method.Name}");
|
||||||
|
args[i] = value;
|
||||||
args.Add(value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return args.ToArray();
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -191,12 +164,45 @@ namespace Reactor.Networking.MethodRpc
|
|||||||
|
|
||||||
if (t.IsSubclassOf(typeof(InnerNetObject)))
|
if (t.IsSubclassOf(typeof(InnerNetObject)))
|
||||||
{
|
{
|
||||||
return GetFindObjectByNetIdInvoker(t)(new object[]{reader.ReadPackedUInt32()});
|
return reader.ReadNetObject(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReaderWriterManager.Instance.All.ContainsKey(t.BaseType!))
|
||||||
|
{
|
||||||
|
return ReaderWriterManager.Instance.All[t.BaseType].UnsafeRead(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger<ReactorPlugin>.Warning($"Tried deserializing unsupported type {t.BaseType.Name}");
|
Logger<ReactorPlugin>.Warning($"Tried deserializing unsupported type {t.BaseType.Name}");
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region InnerNetObject
|
||||||
|
|
||||||
|
private static readonly MethodInfo _findObjectByNetId =
|
||||||
|
typeof(RpcSerializer).GetMethod(nameof(FindObjectByNetId), BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
private static Dictionary<Type, Func<object[], object>> _findObjectByNetIdInvokers = new();
|
||||||
|
static Func<object[], object> GetFindObjectByNetIdInvoker(Type type)
|
||||||
|
{
|
||||||
|
if (_findObjectByNetIdInvokers.ContainsKey(type)) return _findObjectByNetIdInvokers[type];
|
||||||
|
|
||||||
|
var invoker = RpcPrefixHandle.GenerateCaller(_findObjectByNetId.MakeGenericMethod(type));
|
||||||
|
_findObjectByNetIdInvokers.Add(type, invoker);
|
||||||
|
return invoker;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InnerNetObject FindObjectByNetId<T>(uint id) where T : InnerNetObject
|
||||||
|
{
|
||||||
|
return AmongUsClient.Instance.FindObjectByNetId<T>(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteNetObject(this MessageWriter writer, InnerNetObject o) => writer.WritePacked(o.NetId);
|
||||||
|
|
||||||
|
public static InnerNetObject ReadNetObject(this MessageReader reader, Type t) =>
|
||||||
|
(InnerNetObject) GetFindObjectByNetIdInvoker(t)(new object[] {reader.ReadPackedUInt32()});
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,6 +39,7 @@ namespace Reactor
|
|||||||
RegisterInIl2CppAttribute.Initialize();
|
RegisterInIl2CppAttribute.Initialize();
|
||||||
RegisterCustomRpcAttribute.Initialize();
|
RegisterCustomRpcAttribute.Initialize();
|
||||||
MethodRpcAttribute.Initialize();
|
MethodRpcAttribute.Initialize();
|
||||||
|
ReaderWriterAttribute.Initialize();
|
||||||
|
|
||||||
ChainloaderHooks.OnPluginLoad(this);
|
ChainloaderHooks.OnPluginLoad(this);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user