mirror of
https://github.com/NuclearPowered/Reactor.git
synced 2026-10-19 15:51:54 +00:00
Enhancements and additions to Reactor Networking (#91)
* Update ExtraMessageExtensions.cs Added enum methods * Update MessageSerializer.cs Add enum serialisation * Oops documentation fix * Fix errors + add long serialisation * Correction: ulong not long * Specify format * Add long serialisation + improve enum serialisation * Add a shorthand method * Removed generic enum write and fix long write * Add generic converter support + read enum improvement * Remove leftover code * Better long serialisation * Serialise the array directly * Allow serialising color values * Update .gitignore * Update ExtraMessageExtensions.cs * Discard changes to .gitignore
This commit is contained in:
3 files changed
+189
-22
No files matched your search
@@ -38,8 +38,7 @@ public sealed class MessageConverterAttribute : Attribute
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var messageConverter = (UnsafeMessageConverter) Activator.CreateInstance(type)!;
|
MessageSerializer.Register(type);
|
||||||
MessageSerializer.Register(messageConverter);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -52,5 +51,6 @@ public sealed class MessageConverterAttribute : Attribute
|
|||||||
internal static void Initialize()
|
internal static void Initialize()
|
||||||
{
|
{
|
||||||
IL2CPPChainloader.Instance.PluginLoad += (_, assembly, _) => Register(assembly);
|
IL2CPPChainloader.Instance.PluginLoad += (_, assembly, _) => Register(assembly);
|
||||||
|
IL2CPPChainloader.Instance.Finished += MessageSerializer.ClearMaps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
using Hazel;
|
using Hazel;
|
||||||
using Hazel.Udp;
|
using Hazel.Udp;
|
||||||
|
using Reactor.Networking.Serialization;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Reactor.Networking.Extensions;
|
namespace Reactor.Networking.Extensions;
|
||||||
@@ -12,10 +14,11 @@ public static class ExtraMessageExtensions
|
|||||||
{
|
{
|
||||||
private const float MIN = -50f;
|
private const float MIN = -50f;
|
||||||
private const float MAX = 50f;
|
private const float MAX = 50f;
|
||||||
|
private const float DIFF = MAX - MIN;
|
||||||
|
|
||||||
private static float ReverseLerp(float t)
|
private static float ReverseLerp(float t)
|
||||||
{
|
{
|
||||||
return Mathf.Clamp((t - MIN) / (MAX - MIN), 0f, 1f);
|
return Mathf.Clamp01((t - MIN) / DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -32,6 +35,33 @@ public static class ExtraMessageExtensions
|
|||||||
writer.Write(y);
|
writer.Write(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an Enum value to the <paramref name="writer"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="MessageWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The <see cref="Enum"/> to write.</param>
|
||||||
|
public static void Write(this MessageWriter writer, Enum value) => writer.Serialize(Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a long value to the <paramref name="writer"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="MessageWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The <see cref="long"/> to write.</param>
|
||||||
|
public static void Write(this MessageWriter writer, long value) => writer.Write(BitConverter.GetBytes(value));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a color value to the <paramref name="writer"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="MessageWriter"/> to write to.</param>
|
||||||
|
/// <param name="value">The <see cref="Color32"/> to write.</param>
|
||||||
|
public static void Write(this MessageWriter writer, Color32 value)
|
||||||
|
{
|
||||||
|
writer.Write(value.r);
|
||||||
|
writer.Write(value.g);
|
||||||
|
writer.Write(value.b);
|
||||||
|
writer.Write(value.a);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a <see cref="Vector2"/> from the <paramref name="reader"/>.
|
/// Reads a <see cref="Vector2"/> from the <paramref name="reader"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -45,6 +75,43 @@ public static class ExtraMessageExtensions
|
|||||||
return new Vector2(Mathf.Lerp(MIN, MAX, x), Mathf.Lerp(MIN, MAX, y));
|
return new Vector2(Mathf.Lerp(MIN, MAX, x), Mathf.Lerp(MIN, MAX, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads an enum value and casts it to the specified type from a network message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
|
||||||
|
/// <typeparam name="T">The <see cref="Enum"/> type to convert to.</typeparam>
|
||||||
|
/// <returns>An <see cref="Enum"/> value from the <paramref name="reader"/>.</returns>
|
||||||
|
public static T ReadEnum<T>(this MessageReader reader) where T : struct, Enum => (T) reader.ReadEnum(typeof(T));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads an enum value from a network message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
|
||||||
|
/// <param name="enumType">The type of the enum.</param>
|
||||||
|
/// <returns>The resulting enum value from the <paramref name="reader"/>.</returns>
|
||||||
|
public static object ReadEnum(this MessageReader reader, Type enumType) => Enum.ToObject(enumType, reader.Deserialize(Enum.GetUnderlyingType(enumType)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a long value from a network message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
|
||||||
|
/// <returns>The resulting long value from the <paramref name="reader"/>.</returns>
|
||||||
|
public static long ReadInt64(this MessageReader reader) => BitConverter.ToInt64(reader.ReadBytes(8), 0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a color value from a network message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
|
||||||
|
/// <returns>The resulting Color32 value from the <paramref name="reader"/>.</returns>
|
||||||
|
public static Color32 ReadColor32(this MessageReader reader) => new(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a color value from a network message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
|
||||||
|
/// <returns>The resulting Color value from the <paramref name="reader"/>.</returns>
|
||||||
|
public static Color ReadColor(this MessageReader reader) => new(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a message on the <paramref name="connection"/> with an <paramref name="ackCallback"/>.
|
/// Sends a message on the <paramref name="connection"/> with an <paramref name="ackCallback"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -15,33 +15,83 @@ public static class MessageSerializer
|
|||||||
private static List<UnsafeMessageConverter> MessageConverters { get; } = new();
|
private static List<UnsafeMessageConverter> MessageConverters { get; } = new();
|
||||||
|
|
||||||
private static Dictionary<Type, UnsafeMessageConverter?> MessageConverterMap { get; } = new();
|
private static Dictionary<Type, UnsafeMessageConverter?> MessageConverterMap { get; } = new();
|
||||||
|
private static Dictionary<Type, Type> GenericConvertersMap { get; } = new();
|
||||||
|
|
||||||
|
internal static void ClearMaps()
|
||||||
|
{
|
||||||
|
MessageConverterMap.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a MessageConverter.
|
/// Registers a MessageConverter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="messageConverter">The MessageConverter to be registered.</param>
|
/// <param name="type">The Type of the MessageConverter to be registered.</param>
|
||||||
public static void Register(UnsafeMessageConverter messageConverter)
|
public static void Register(Type type)
|
||||||
{
|
{
|
||||||
MessageConverters.Add(messageConverter);
|
if (type.IsGenericTypeDefinition)
|
||||||
MessageConverterMap.Clear();
|
{
|
||||||
|
var baseType = type.BaseType!;
|
||||||
|
|
||||||
|
if (!baseType.Name.Contains("MessageConverter"))
|
||||||
|
throw new InvalidOperationException($"{type.Name} should directly inherit from MessageConverter<T>");
|
||||||
|
|
||||||
|
var generics = baseType.GetGenericArguments();
|
||||||
|
var param = generics[0];
|
||||||
|
|
||||||
|
GenericConvertersMap.Add(param.GetGenericTypeDefinition(), type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var messageConverter = (UnsafeMessageConverter) Activator.CreateInstance(type)!;
|
||||||
|
MessageConverters.Add(messageConverter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds a MessageConverter for the specified <paramref name="type"/>.
|
/// Finds a MessageConverter for the specified <paramref name="type"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The type of an object.</param>
|
/// <param name="type">The type of an object.</param>
|
||||||
/// <returns>A MessageConverted that can convert the specified <see cref="Type"/>.</returns>
|
/// <returns>A MessageConverter that can convert the specified <see cref="Type"/>.</returns>
|
||||||
public static UnsafeMessageConverter? FindConverter(Type type)
|
public static UnsafeMessageConverter? FindConverter(Type type)
|
||||||
{
|
{
|
||||||
if (MessageConverterMap.TryGetValue(type, out var value))
|
if (!MessageConverterMap.TryGetValue(type, out var value))
|
||||||
{
|
{
|
||||||
return value;
|
value = MessageConverters.SingleOrDefault(x => x.CanConvert(type));
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
MessageConverterMap.Add(type, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
var converter = MessageConverters.SingleOrDefault(x => x.CanConvert(type));
|
return value;
|
||||||
MessageConverterMap.Add(type, converter);
|
}
|
||||||
|
|
||||||
return converter;
|
/// <summary>
|
||||||
|
/// Finds and builds a MessageConverter for the specified <paramref name="type"/> using a registered generic converter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of an object.</param>
|
||||||
|
/// <returns>A MessageConverter that can convert the specified <see cref="Type"/>.</returns>
|
||||||
|
public static UnsafeMessageConverter? FindGenericConverter(Type type)
|
||||||
|
{
|
||||||
|
if (MessageConverterMap.TryGetValue(type, out var value))
|
||||||
|
return value;
|
||||||
|
|
||||||
|
if (!type.IsGenericType)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var typeDef = type.GetGenericTypeDefinition();
|
||||||
|
|
||||||
|
if (!GenericConvertersMap.TryGetValue(typeDef, out var builder))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var generic = builder.MakeGenericType(type.GetGenericArguments());
|
||||||
|
value = (UnsafeMessageConverter) Activator.CreateInstance(generic)!;
|
||||||
|
|
||||||
|
MessageConverters.Add(value);
|
||||||
|
MessageConverterMap.Add(type, value);
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -49,7 +99,7 @@ public static class MessageSerializer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="writer">The <see cref="MessageWriter"/> to write to.</param>
|
/// <param name="writer">The <see cref="MessageWriter"/> to write to.</param>
|
||||||
/// <param name="args">The args to be written.</param>
|
/// <param name="args">The args to be written.</param>
|
||||||
public static void Serialize(MessageWriter writer, object[] args)
|
public static void Serialize(this MessageWriter writer, params object[] args)
|
||||||
{
|
{
|
||||||
foreach (var arg in args)
|
foreach (var arg in args)
|
||||||
{
|
{
|
||||||
@@ -87,24 +137,48 @@ public static class MessageSerializer
|
|||||||
case bool i:
|
case bool i:
|
||||||
writer.Write(i);
|
writer.Write(i);
|
||||||
break;
|
break;
|
||||||
|
case ulong i:
|
||||||
|
writer.Write(i);
|
||||||
|
break;
|
||||||
|
case long i:
|
||||||
|
ExtraMessageExtensions.Write(writer, i); // For some reason this insists on referring the to float write method, so this is me taking precautions
|
||||||
|
break;
|
||||||
case Vector2 i:
|
case Vector2 i:
|
||||||
writer.Write(i);
|
writer.Write(i);
|
||||||
break;
|
break;
|
||||||
case string i:
|
case string i:
|
||||||
writer.Write(i);
|
writer.Write(i);
|
||||||
break;
|
break;
|
||||||
|
case Color i:
|
||||||
|
writer.Write(i);
|
||||||
|
break;
|
||||||
|
case Color32 i:
|
||||||
|
writer.Write(i);
|
||||||
|
break;
|
||||||
|
case Enum i:
|
||||||
|
writer.Write(i);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
var converter = FindConverter(@object.GetType());
|
var type = @object.GetType();
|
||||||
if (converter != null)
|
var converter = FindGenericConverter(type) ?? FindConverter(type);
|
||||||
{
|
|
||||||
converter.UnsafeWrite(writer, @object);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new NotSupportedException("Couldn't serialize " + @object.GetType());
|
if (converter != null)
|
||||||
|
converter.UnsafeWrite(writer, @object);
|
||||||
|
else
|
||||||
|
throw new NotSupportedException("Couldn't serialize " + type.Name);
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deserializes a generic <typeparamref name="T"/> value from the <paramref name="reader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
|
||||||
|
/// <typeparam name="T">The type to be read.</typeparam>
|
||||||
|
/// <returns>A generic <typeparamref name="T"/> value from the <paramref name="reader"/>.</returns>
|
||||||
|
public static T Deserialize<T>(this MessageReader reader) => (T) reader.Deserialize(typeof(T));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deserializes an <see cref="object"/> of <paramref name="objectType"/> from the <paramref name="reader"/>.
|
/// Deserializes an <see cref="object"/> of <paramref name="objectType"/> from the <paramref name="reader"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -158,7 +232,33 @@ public static class MessageSerializer
|
|||||||
return reader.ReadString();
|
return reader.ReadString();
|
||||||
}
|
}
|
||||||
|
|
||||||
var converter = FindConverter(objectType);
|
if (objectType == typeof(ulong))
|
||||||
|
{
|
||||||
|
return reader.ReadUInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objectType == typeof(long))
|
||||||
|
{
|
||||||
|
return reader.ReadInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objectType == typeof(Color))
|
||||||
|
{
|
||||||
|
return reader.ReadColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objectType == typeof(Color32))
|
||||||
|
{
|
||||||
|
return reader.ReadColor32();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objectType.IsEnum)
|
||||||
|
{
|
||||||
|
return reader.ReadEnum(objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
var converter = FindGenericConverter(objectType) ?? FindConverter(objectType);
|
||||||
|
|
||||||
if (converter != null)
|
if (converter != null)
|
||||||
{
|
{
|
||||||
return converter.UnsafeRead(reader, objectType);
|
return converter.UnsafeRead(reader, objectType);
|
||||||
|
|||||||
Reference in new issue
Block a user