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();
|
||||
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ namespace Reactor
|
||||
RegisterInIl2CppAttribute.Initialize();
|
||||
RegisterCustomRpcAttribute.Initialize();
|
||||
MethodRpcAttribute.Initialize();
|
||||
ReaderWriterAttribute.Initialize();
|
||||
|
||||
ChainloaderHooks.OnPluginLoad(this);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user