diff --git a/MiraAPI/Modifiers/ModifierData.cs b/MiraAPI/Modifiers/ModifierData.cs
new file mode 100644
index 0000000..425e063
--- /dev/null
+++ b/MiraAPI/Modifiers/ModifierData.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace MiraAPI.Modifiers;
+
+///
+/// Modifier data for networking.
+///
+/// The Type of the modifier.
+/// Parameters for constructor.
+public readonly struct ModifierData(Type type, object[] args)
+{
+ ///
+ /// Gets the type of the modifier.
+ ///
+ public Type Type { get; } = type;
+
+ ///
+ /// Gets the parameters for the constructor.
+ ///
+ public object[] Args { get; } = args;
+}
diff --git a/MiraAPI/Modifiers/ModifierExtensions.cs b/MiraAPI/Modifiers/ModifierExtensions.cs
index 83dfd4c..d6ce5ff 100644
--- a/MiraAPI/Modifiers/ModifierExtensions.cs
+++ b/MiraAPI/Modifiers/ModifierExtensions.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using MiraAPI.Networking;
using Reactor.Networking.Attributes;
+using Reactor.Networking.Rpc;
using Reactor.Utilities;
namespace MiraAPI.Modifiers;
@@ -104,7 +105,7 @@ public static class ModifierExtensions
///
/// The player to add the modifier to.
/// The modifier ID.
- [MethodRpc((uint)MiraRpc.AddModifier)]
+ /// The arguments to initialize the modifier constructor with.
public static void RpcAddModifier(this PlayerControl target, uint modifierId, params object[] args)
{
var type = ModifierManager.GetModifierType(modifierId);
@@ -114,8 +115,7 @@ public static class ModifierExtensions
return;
}
- var modifier = ModifierFactory.CreateInstance(type, args);
- target.GetModifierComponent()?.AddModifier(modifier);
+ Rpc.Instance.Send(target, new ModifierData(type, args));
}
///
@@ -133,7 +133,6 @@ public static class ModifierExtensions
return;
}
- var modifier = ModifierFactory.CreateInstance(args);
- player.GetModifierComponent()!.AddModifier(modifier);
+ player.RpcAddModifier(id.Value, args);
}
}
diff --git a/MiraAPI/Networking/AddModifierRpc.cs b/MiraAPI/Networking/AddModifierRpc.cs
new file mode 100644
index 0000000..3546d4f
--- /dev/null
+++ b/MiraAPI/Networking/AddModifierRpc.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Hazel;
+using MiraAPI.Modifiers;
+using Reactor.Networking.Attributes;
+using Reactor.Networking.Rpc;
+using Reactor.Networking.Serialization;
+
+namespace MiraAPI.Networking;
+
+///
+/// Remote procedure call for adding a modifier.
+///
+/// Mira plugin.
+/// RPC ID.
+[RegisterCustomRpc((uint)MiraRpc.AddModifier)]
+public class AddModifierRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc(plugin, id)
+{
+ private static readonly Dictionary ParameterCache = [];
+
+ ///
+ public override RpcLocalHandling LocalHandling => RpcLocalHandling.Before;
+
+ ///
+ public override void Write(MessageWriter writer, ModifierData data)
+ {
+ var modId = ModifierManager.GetModifierId(data.Type);
+ writer.WritePacked((uint)modId!);
+ MessageSerializer.Serialize(writer, data.Args);
+ }
+
+ ///
+ public override ModifierData Read(MessageReader reader)
+ {
+ var modId = reader.ReadPackedUInt32();
+ var modifier = ModifierManager.GetModifierType(modId)!;
+
+ if (!ParameterCache.TryGetValue(modifier, out var paramTypes))
+ {
+ paramTypes = modifier.GetConstructors().OrderBy(x => x.GetParameters().Length).First().GetParameters();
+ ParameterCache[modifier] = paramTypes;
+ }
+
+ var objects = new object[paramTypes.Length];
+ foreach (var paramType in paramTypes)
+ {
+ objects[paramType.Position] = reader.Deserialize(paramType.ParameterType);
+ }
+
+ return new ModifierData(modifier, objects);
+ }
+
+ ///
+ public override void Handle(PlayerControl innerNetObject, ModifierData data)
+ {
+ var modifier = ModifierFactory.CreateInstance(data.Type, data.Args);
+ innerNetObject.GetModifierComponent()?.AddModifier(modifier);
+ }
+}