Add ReaderWriter for custom types

This commit is contained in:
Zirno authored and js6pak committed 2021-07-26 17:07:57 +02:00
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();
List<Type> allArgs = new List<Type>();
foreach (var arg in methodParameters)
Parameters = new Type[methodParameters.Length];
for (var i = 0; i < methodParameters.Length; i++)
{
var arg = methodParameters[i];
var argType = 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();
StructBook.Add(argType, feilds);
StructBook.Add(argType, fields);
}
allArgs.Add(argType);
Parameters[i] = argType;
}
Parameters = allArgs.ToArray();
Invoker = RpcPrefixHandle.GenerateCaller(Method);
allMethodRPCsFast.Add(Method, this);
}
public MethodInfo Method { get; }
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 void UnsafeWrite(MessageWriter writer, object data)
@@ -76,6 +73,8 @@ namespace Reactor.Networking.MethodRpc
{
Coroutines.Start((IEnumerator) result);
}
SkipNextSend = false;
}
public void Send(object[] args)
@@ -37,7 +37,7 @@ namespace Reactor.Networking.MethodRpc
foreach (var method in rpcMethods)
{
if (!method.IsStatic)
{
Logger<ReactorPlugin>.Warning("Cannot register non static custom method rpc");
@@ -45,7 +45,7 @@ namespace Reactor.Networking.MethodRpc
}
var attribute = method.GetCustomAttribute<MethodRpcAttribute>();
var customRpc = new CustomMethodRpc(plugin, method, attribute.id, attribute.option,
attribute.localHandling);
PluginSingleton<ReactorPlugin>.Instance.Harmony.Patch(method, new HarmonyMethod(_rpcPrefixGenerator));
@@ -58,9 +58,8 @@ namespace Reactor.Networking.MethodRpc
// ignored
}
}
}
}
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)
{
if (CustomMethodRpc.SkipNextSend)
{
CustomMethodRpc.SkipNextSend = false;
return true;
}
if (CustomMethodRpc.SkipNextSend) return true;
var methodRpc = CustomMethodRpc.allMethodRPCsFast[originalMethod];
methodRpc?.Send(list);
+57 -51
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Hazel;
using InnerNet;
@@ -10,29 +11,6 @@ namespace Reactor.Networking.MethodRpc
{
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)
{
foreach (var o in list)
@@ -49,6 +27,7 @@ namespace Reactor.Networking.MethodRpc
{
writer.Write(o);
}
Logger<ReactorPlugin>.Debug($"Serialized {o.GetType()}");
}
}
@@ -58,51 +37,44 @@ namespace Reactor.Networking.MethodRpc
{
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);
writer.WriteNetObject((InnerNetObject) o);
}
else if (ReaderWriterManager.Instance.All.ContainsKey(o.GetType()))
{
ReaderWriterManager.Instance.All[o.GetType()].UnsafeWrite(writer, o);
}
else
{
Logger<ReactorPlugin>.Warning($"Tried serializing unsupported type {nameof(o)}");
Logger<ReactorPlugin>.Warning($"Tried serializing unsupported type {o.GetType()}");
}
break;
}
}
@@ -112,33 +84,34 @@ namespace Reactor.Networking.MethodRpc
{
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)
{
List<object> structArgs = new();
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);
}
var fields = methodRpc.StructBook[t];
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
{
var value = reader.Read(t);
Logger<ReactorPlugin>.Debug($"Read {value} of {t.Name} for {methodRpc.Method.Name}");
args.Add(value);
args[i] = value;
}
}
return args.ToArray();
return args;
}
@@ -191,12 +164,45 @@ namespace Reactor.Networking.MethodRpc
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}");
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
}
}
+1
View File
@@ -39,6 +39,7 @@ namespace Reactor
RegisterInIl2CppAttribute.Initialize();
RegisterCustomRpcAttribute.Initialize();
MethodRpcAttribute.Initialize();
ReaderWriterAttribute.Initialize();
ChainloaderHooks.OnPluginLoad(this);
}