Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions Reactor/Networking/Attributes/MethodRpcAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@ public sealed class MethodRpcAttribute : Attribute
/// </summary>
public RpcLocalHandling LocalHandling { get; set; } = RpcLocalHandling.Before;

/// <summary>
/// Gets or sets a value indicating whether the rpc should be sent immediately.
/// </summary>
[Obsolete("Non-immediate RPCs were removed in 2025.5.20. All RPCs are immediate. This property will be removed in a future version.")]
public bool SendImmediately { get; set; } = true;

/// <summary>
/// Initializes a new instance of the <see cref="MethodRpcAttribute"/> class.
/// </summary>
Expand All @@ -56,8 +50,7 @@ public MethodRpcAttribute(uint id)
/// <param name="plugin">The plugin to register the rpc to.</param>
public static void Register(Assembly assembly, BasePlugin plugin)
{
if (_registeredAssemblies.Contains(assembly)) return;
_registeredAssemblies.Add(assembly);
if (!_registeredAssemblies.Add(assembly)) return;

var methods = assembly.GetTypes()
.SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public));
Expand Down
106 changes: 104 additions & 2 deletions Reactor/Networking/Extensions/ExtraMessageExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.IO;
using Hazel;
using Hazel.Udp;
using Reactor.Networking.Serialization;
Expand All @@ -21,6 +22,34 @@ private static float ReverseLerp(float t)
return Mathf.Clamp01((t - MIN) / DIFF);
}

/// <summary>
/// Writes a packed 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 WritePacked(this MessageWriter writer, long value)
{
// From what I can tell from the publicly available source of Hazel, they just cast the int value to a uint??
// Seems like they never heard of ZigZag encoding
writer.WritePacked((ulong) ((value << 1) ^ (value >> 63)));
}

/// <summary>
/// Writes a packed ulong value to the <paramref name="writer"/>.
/// </summary>
/// <param name="writer">The <see cref="MessageWriter"/> to write to.</param>
/// <param name="value">The <see cref="ulong"/> to write.</param>
public static void WritePacked(this MessageWriter writer, ulong value)
{
while (value >= 0x80)
{
writer.Write((byte) (value | 0x80));
value >>= 7;
}

writer.Write((byte) value);
}

/// <summary>
/// Writes a <see cref="Vector2"/> to the <paramref name="writer"/>.
/// </summary>
Expand All @@ -47,7 +76,17 @@ public static void Write(this MessageWriter writer, Vector2 value)
/// </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));
public static void Write(this MessageWriter writer, long value)
Comment thread
AlchlcDvl marked this conversation as resolved.
{
writer.Write((byte) value);
writer.Write((byte) (value >> 8));
writer.Write((byte) (value >> 16));
writer.Write((byte) (value >> 24));
writer.Write((byte) (value >> 32));
writer.Write((byte) (value >> 40));
writer.Write((byte) (value >> 48));
writer.Write((byte) (value >> 56));
}

/// <summary>
/// Writes a color value to the <paramref name="writer"/>.
Expand All @@ -62,6 +101,58 @@ public static void Write(this MessageWriter writer, Color32 value)
writer.Write(value.a);
}

/// <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="Color"/> to write.</param>
public static void Write(this MessageWriter writer, Color value)
{
writer.Write(value.r);
writer.Write(value.g);
writer.Write(value.b);
writer.Write(value.a);
}

/// <summary>
/// Reads a packed <see cref="long"/> from the <paramref name="reader"/>.
/// </summary>
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
/// <returns>A <see cref="long"/> from the <paramref name="reader"/>.</returns>
public static long ReadPackedInt64(this MessageReader reader)
{
// See comment in WritePacked(long)
var val = reader.ReadPackedUInt64();
return (long) (val >> 1) ^ -(long) (val & 1);
}

/// <summary>
/// Reads a packed <see cref="ulong"/> from the <paramref name="reader"/>.
/// </summary>
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
/// <returns>A <see cref="ulong"/> from the <paramref name="reader"/>.</returns>
public static ulong ReadPackedUInt64(this MessageReader reader)
{
var result = 0ul;
var shift = 0;

while (true)
{
var b = reader.ReadByte();
result |= (ulong) (b & 0x7F) << shift;

if ((b & 0x80) == 0)
break;

shift += 7;

if (shift >= 70)
throw new InvalidDataException("VarInt too long");
}

return result;
}

/// <summary>
/// Reads a <see cref="Vector2"/> from the <paramref name="reader"/>.
/// </summary>
Expand Down Expand Up @@ -96,7 +187,18 @@ public static Vector2 ReadVector2(this MessageReader reader)
/// </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);
public static long ReadInt64(this MessageReader reader)
{
var uval = (long) reader.ReadByte();
uval |= (long) reader.ReadByte() << 8;
uval |= (long) reader.ReadByte() << 16;
uval |= (long) reader.ReadByte() << 24;
uval |= (long) reader.ReadByte() << 32;
uval |= (long) reader.ReadByte() << 40;
uval |= (long) reader.ReadByte() << 48;
uval |= (long) reader.ReadByte() << 56;
return uval;
}

/// <summary>
/// Reads a color value from a network message.
Expand Down
14 changes: 6 additions & 8 deletions Reactor/Networking/Rpc/CustomRpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,10 @@ public override void UnsafeHandle(InnerNetObject innerNetObject, object? data)
/// </summary>
/// <param name="innerNetObject">The <see cref="InnerNetObject"/> to send the rpc on.</param>
/// <param name="data">The data to send.</param>
/// <param name="immediately">Whether to send it immediately.</param>
/// <param name="ackCallback">The callback to invoke when this packet is acknowledged.</param>
public void Send(InnerNetObject innerNetObject, TData data, bool immediately = false, Action? ackCallback = null)
public void Send(InnerNetObject innerNetObject, TData data, Action? ackCallback = null)
{
UnsafeSend(innerNetObject, data, immediately, ackCallback: ackCallback);
UnsafeSend(innerNetObject, data, ackCallback: ackCallback);
}

/// <summary>
Expand All @@ -72,7 +71,7 @@ public void Send(InnerNetObject innerNetObject, TData data, bool immediately = f
/// <param name="ackCallback">The callback to invoke when this packet is acknowledged.</param>
public void SendTo(InnerNetObject innerNetObject, int targetClientId, TData data, Action? ackCallback = null)
{
UnsafeSend(innerNetObject, data, true, targetClientId, ackCallback);
UnsafeSend(innerNetObject, data, targetClientId, ackCallback);
}
}

Expand Down Expand Up @@ -121,11 +120,10 @@ public override void UnsafeHandle(InnerNetObject innerNetObject, object? data)
/// Sends this custom rpc on the specified <paramref name="innerNetObject"/>.
/// </summary>
/// <param name="innerNetObject">The <see cref="InnerNetObject"/> to send the rpc on.</param>
/// <param name="immediately">Whether to send it immediately.</param>
/// <param name="ackCallback">The callback to invoke when this packet is acknowledged.</param>
public void Send(InnerNetObject innerNetObject, bool immediately = false, Action? ackCallback = null)
public void Send(InnerNetObject innerNetObject, Action? ackCallback = null)
{
UnsafeSend(innerNetObject, immediately, ackCallback: ackCallback);
UnsafeSend(innerNetObject, null, ackCallback: ackCallback);
}

/// <summary>
Expand All @@ -136,6 +134,6 @@ public void Send(InnerNetObject innerNetObject, bool immediately = false, Action
/// <param name="ackCallback">The callback to invoke when this packet is acknowledged.</param>
public void SendTo(InnerNetObject innerNetObject, int targetClientId, Action? ackCallback = null)
{
UnsafeSend(innerNetObject, null, true, targetClientId, ackCallback);
UnsafeSend(innerNetObject, null, targetClientId, ackCallback);
}
}
22 changes: 0 additions & 22 deletions Reactor/Networking/Rpc/MethodRpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,22 +69,6 @@ public MethodRpc(BasePlugin plugin, MethodInfo method, uint id, SendOption optio
_handle = Hook(method, parameters, method.IsStatic);
}

/// <summary>
/// Initializes a new instance of the <see cref="MethodRpc"/> class.
/// </summary>
/// <param name="plugin">The plugin that the rpc is attached to.</param>
/// <param name="method">The method of the method rpc.</param>
/// <param name="id">The id of the rpc.</param>
/// <param name="option">The send option of the rpc.</param>
/// <param name="localHandling">The local handling method of the rpc.</param>
/// <param name="sendImmediately">The value indicating whether the rpc should be sent immediately.</param>
[Obsolete("Non-immediate RPCs were removed in 2025.5.20. All RPCs are immediate. Remove sendImmediately from the parameter list.")]
public MethodRpc(BasePlugin plugin, MethodInfo method, uint id, SendOption option, RpcLocalHandling localHandling, bool sendImmediately)
: this(plugin, method, id, option, localHandling)
{
SendImmediately = sendImmediately;
}

/// <summary>
/// Gets the method of the method rpc.
/// </summary>
Expand All @@ -102,12 +86,6 @@ public MethodRpc(BasePlugin plugin, MethodInfo method, uint id, SendOption optio
/// <inheritdoc />
public override SendOption SendOption { get; }

/// <summary>
/// Gets a value indicating whether the method rpc should be sent immediately.
/// </summary>
[Obsolete("Non-immediate RPCs were removed in 2025.5.20. All RPCs are immediate. This property will be removed in a future version.")]
public bool SendImmediately { get; } = true;

/// <inheritdoc />
public override void UnsafeWrite(MessageWriter writer, object? data)
{
Expand Down
10 changes: 4 additions & 6 deletions Reactor/Networking/Rpc/PlayerCustomRpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ protected PlayerCustomRpc(TPlugin plugin, uint id) : base(plugin, id)
/// Sends this custom rpc on the local player with the specified <paramref name="data"/>.
/// </summary>
/// <param name="data">The data to send.</param>
/// <param name="immediately">Whether to send it immediately.</param>
/// <param name="ackCallback">The callback to invoke when this packet is acknowledged.</param>
public void Send(TData data, bool immediately = false, Action? ackCallback = null)
public void Send(TData data, Action? ackCallback = null)
{
Send(PlayerControl.LocalPlayer, data, immediately, ackCallback);
Send(PlayerControl.LocalPlayer, data, ackCallback);
}

/// <summary>
Expand Down Expand Up @@ -52,11 +51,10 @@ protected PlayerCustomRpc(TPlugin plugin, uint id) : base(plugin, id)
/// <summary>
/// Sends this custom rpc on the local player.
/// </summary>
/// <param name="immediately">Whether to send it immediately.</param>
/// <param name="ackCallback">The callback to invoke when this packet is acknowledged.</param>
public void Send(bool immediately = false, Action? ackCallback = null)
public void Send(Action? ackCallback = null)
{
Send(PlayerControl.LocalPlayer, immediately, ackCallback);
Send(PlayerControl.LocalPlayer, ackCallback);
}

/// <summary>
Expand Down
8 changes: 1 addition & 7 deletions Reactor/Networking/Rpc/UnsafeCustomRpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,9 @@ protected UnsafeCustomRpc(BasePlugin plugin, uint id)
/// </summary>
/// <param name="innerNetObject">The <see cref="InnerNetObject"/> to send the rpc on.</param>
/// <param name="data">The data to send.</param>
/// <param name="immediately">Whether to send it immediately.</param>
/// <param name="targetClientId">Target client id, defaults to broadcast.</param>
/// <param name="ackCallback">The callback to invoke when this packet is acknowledged.</param>
public void UnsafeSend(InnerNetObject innerNetObject, object? data, bool immediately = false, int targetClientId = -1, Action? ackCallback = null)
public void UnsafeSend(InnerNetObject innerNetObject, object? data, int targetClientId = -1, Action? ackCallback = null)
{
ArgumentNullException.ThrowIfNull(innerNetObject);

Expand All @@ -108,11 +107,6 @@ public void UnsafeSend(InnerNetObject innerNetObject, object? data, bool immedia
UnsafeHandle(innerNetObject, data);
}

if (immediately == false)
{
Warning("Non-immediate RPCs were removed in 2025.5.20! Reactor will now always send immediately!");
}

var writer = AmongUsClient.Instance.StartRpcImmediately(
innerNetObject.NetId,
CustomRpcManager.CallId,
Expand Down
21 changes: 21 additions & 0 deletions Reactor/Networking/Serialization/INetSerializable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Hazel;

namespace Reactor.Networking.Serialization;

/// <summary>
/// Provides a read-write method pair so that data types can define how to read and write themselves.
/// </summary>
public interface INetSerializable
{
/// <summary>
/// Writes the instance to the provided writer.
/// </summary>
/// <param name="writer">The <see cref="MessageWriter"/> to write to.</param>
void WriteTo(MessageWriter writer);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not Serialize and Deserialize?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made more intuitive sense to name them WriteTo and ReadFrom to me


/// <summary>
/// Reads the instance's properties from the provided reader.
/// </summary>
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
void ReadFrom(MessageReader reader);
}
Loading
Loading