From 9485099ab94510e66b6051a7cb6537d874a964f1 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 2 Feb 2025 16:09:06 -0500
Subject: [PATCH 01/14] RPC add modifier with arguments
---
.../Buttons/Freezer/FreezeButton.cs | 1 +
MiraAPI.Example/Buttons/MeetingButton.cs | 2 +-
.../OptionTypes/ModdedEnumOption.cs | 1 -
MiraAPI/Modifiers/ModifierExtensions.cs | 139 ++++++++++++++++++
MiraAPI/Modifiers/ModifierFactory.cs | 83 +++++++++++
.../Patches/Modifiers/EndGameDidWinPatch.cs | 2 +-
MiraAPI/Patches/PlayerControlPatches.cs | 2 +-
MiraAPI/Patches/VentPatches.cs | 2 +-
MiraAPI/Utilities/Extensions.cs | 125 ----------------
9 files changed, 227 insertions(+), 130 deletions(-)
create mode 100644 MiraAPI/Modifiers/ModifierExtensions.cs
create mode 100644 MiraAPI/Modifiers/ModifierFactory.cs
diff --git a/MiraAPI.Example/Buttons/Freezer/FreezeButton.cs b/MiraAPI.Example/Buttons/Freezer/FreezeButton.cs
index 8db98c7..86feece 100644
--- a/MiraAPI.Example/Buttons/Freezer/FreezeButton.cs
+++ b/MiraAPI.Example/Buttons/Freezer/FreezeButton.cs
@@ -3,6 +3,7 @@ using MiraAPI.Example.Options.Roles;
using MiraAPI.Example.Roles;
using MiraAPI.GameOptions;
using MiraAPI.Hud;
+using MiraAPI.Modifiers;
using MiraAPI.Utilities;
using MiraAPI.Utilities.Assets;
using UnityEngine;
diff --git a/MiraAPI.Example/Buttons/MeetingButton.cs b/MiraAPI.Example/Buttons/MeetingButton.cs
index 85b8ff1..742c7e0 100644
--- a/MiraAPI.Example/Buttons/MeetingButton.cs
+++ b/MiraAPI.Example/Buttons/MeetingButton.cs
@@ -1,6 +1,6 @@
using MiraAPI.Example.Modifiers;
using MiraAPI.Hud;
-using MiraAPI.Utilities;
+using MiraAPI.Modifiers;
using MiraAPI.Utilities.Assets;
using UnityEngine;
diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs
index e917cdc..80bd497 100644
--- a/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs
+++ b/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs
@@ -1,5 +1,4 @@
using System;
-using System.Globalization;
using System.Linq;
using System.Text;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
diff --git a/MiraAPI/Modifiers/ModifierExtensions.cs b/MiraAPI/Modifiers/ModifierExtensions.cs
new file mode 100644
index 0000000..83dfd4c
--- /dev/null
+++ b/MiraAPI/Modifiers/ModifierExtensions.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using MiraAPI.Networking;
+using Reactor.Networking.Attributes;
+using Reactor.Utilities;
+
+namespace MiraAPI.Modifiers;
+
+///
+/// Extension methods for modifiers.
+///
+public static class ModifierExtensions
+{
+ internal static Dictionary ModifierComponents { get; } = [];
+
+ ///
+ /// Gets the ModifierComponent for a player.
+ ///
+ /// The PlayerControl object.
+ /// A ModifierComponent if there is one, null otherwise.
+ public static ModifierComponent? GetModifierComponent(this PlayerControl player)
+ {
+ if (ModifierComponents.TryGetValue(player, out var component))
+ {
+ return component;
+ }
+
+ component = player.GetComponent();
+ if (component == null)
+ {
+ return null;
+ }
+
+ ModifierComponents[player] = component;
+ return component;
+ }
+
+ ///
+ /// Gets a modifier by its type, or null if the player doesn't have it.
+ ///
+ /// The PlayerControl object.
+ /// The Type of the Modifier.
+ /// The Modifier if it is found, null otherwise.
+ public static T? GetModifier(this PlayerControl? player) where T : BaseModifier
+ {
+ return player?.GetModifierComponent()?.ActiveModifiers.Find(x => x is T) as T;
+ }
+
+ ///
+ /// Checks if a player has a modifier.
+ ///
+ /// The PlayerControl object.
+ /// The Type of the Modifier.
+ /// True if the Modifier is present, false otherwise.
+ public static bool HasModifier(this PlayerControl? player) where T : BaseModifier
+ {
+ return player?.GetModifierComponent() != null &&
+ player.GetModifierComponent()!.HasModifier();
+ }
+
+ ///
+ /// Checks if a player has a modifier by its ID.
+ ///
+ /// The PlayerControl object.
+ /// The Modifier ID.
+ /// True if the Modifier is present, false otherwise.
+ public static bool HasModifier(this PlayerControl? player, uint id)
+ {
+ return player?.GetModifierComponent() != null &&
+ player.GetModifierComponent()!.HasModifier(id);
+ }
+
+ ///
+ /// Remote Procedure Call to remove a modifier from a player.
+ ///
+ /// The player to remove the modifier from.
+ /// The ID of the modifier.
+ [MethodRpc((uint)MiraRpc.RemoveModifier)]
+ public static void RpcRemoveModifier(this PlayerControl target, uint modifierId)
+ {
+ target.GetModifierComponent()?.RemoveModifier(modifierId);
+ }
+
+ ///
+ /// Remote Procedure Call to remove a modifier from a player.
+ ///
+ /// The player to remove the modifier from.
+ /// The Type of the Modifier.
+ public static void RpcRemoveModifier(this PlayerControl player) where T : BaseModifier
+ {
+ var id = ModifierManager.GetModifierId(typeof(T));
+
+ if (id == null)
+ {
+ Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
+ return;
+ }
+
+ player.RpcRemoveModifier(id.Value);
+ }
+
+ ///
+ /// Remote Procedure Call to add a modifier to a player.
+ ///
+ /// The player to add the modifier to.
+ /// The modifier ID.
+ [MethodRpc((uint)MiraRpc.AddModifier)]
+ public static void RpcAddModifier(this PlayerControl target, uint modifierId, params object[] args)
+ {
+ var type = ModifierManager.GetModifierType(modifierId);
+ if (type == null)
+ {
+ Logger.Error($"Cannot add modifier with id {modifierId} because it is not registered.");
+ return;
+ }
+
+ var modifier = ModifierFactory.CreateInstance(type, args);
+ target.GetModifierComponent()?.AddModifier(modifier);
+ }
+
+ ///
+ /// Remote Procedure Call to add a modifier to a player.
+ ///
+ /// The player to add the modifier to.
+ /// The arguments to initialize the modifier constructor with.
+ /// The modifier Type.
+ public static void RpcAddModifier(this PlayerControl player, params object[] args) where T : BaseModifier
+ {
+ var id = ModifierManager.GetModifierId(typeof(T));
+ if (id == null)
+ {
+ Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
+ return;
+ }
+
+ var modifier = ModifierFactory.CreateInstance(args);
+ player.GetModifierComponent()!.AddModifier(modifier);
+ }
+}
diff --git a/MiraAPI/Modifiers/ModifierFactory.cs b/MiraAPI/Modifiers/ModifierFactory.cs
new file mode 100644
index 0000000..e1b018c
--- /dev/null
+++ b/MiraAPI/Modifiers/ModifierFactory.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace MiraAPI.Modifiers;
+
+public static class ModifierFactory
+{
+ private static Func? _constructor;
+
+ private static Func CreateConstructor(Type type)
+ {
+ var constructorInfo = type.GetConstructors()
+ .OrderByDescending(c => c.GetParameters().Length)
+ .FirstOrDefault() ?? throw new InvalidOperationException($"Type {type} does not have a public constructor.");
+ var parameters = constructorInfo.GetParameters();
+
+ var argsParam = Expression.Parameter(typeof(object[]), "args");
+ var constructorParams = new Expression[parameters.Length];
+
+ for (var i = 0; i < parameters.Length; i++)
+ {
+ var paramType = parameters[i].ParameterType;
+ var paramAccess = Expression.ArrayIndex(argsParam, Expression.Constant(i));
+ var convertedParam = Expression.Convert(paramAccess, paramType);
+ constructorParams[i] = convertedParam;
+ }
+
+ var newExpr = Expression.New(constructorInfo, constructorParams);
+ var lambda = Expression.Lambda>(newExpr, argsParam);
+
+ return lambda.Compile();
+ }
+
+ public static BaseModifier CreateInstance(Type type, params object[] args)
+ {
+ _constructor ??= CreateConstructor(type);
+ return _constructor(args);
+ }
+}
+
+///
+/// Factory for creating instances of a modifier. More efficient than using reflection.
+///
+/// The modifier type.
+public static class ModifierFactory where T : BaseModifier
+{
+ private static readonly Func Constructor = CreateConstructor();
+
+ private static Func CreateConstructor()
+ {
+ var constructorInfo = typeof(T).GetConstructors()
+ .OrderByDescending(c => c.GetParameters().Length)
+ .FirstOrDefault() ?? throw new InvalidOperationException($"Type {typeof(T)} does not have a public constructor.");
+ var parameters = constructorInfo.GetParameters();
+
+ var argsParam = Expression.Parameter(typeof(object[]), "args");
+ var constructorParams = new Expression[parameters.Length];
+
+ for (var i = 0; i < parameters.Length; i++)
+ {
+ var paramType = parameters[i].ParameterType;
+ var paramAccess = Expression.ArrayIndex(argsParam, Expression.Constant(i));
+ var convertedParam = Expression.Convert(paramAccess, paramType);
+ constructorParams[i] = convertedParam;
+ }
+
+ var newExpr = Expression.New(constructorInfo, constructorParams);
+ var lambda = Expression.Lambda>(newExpr, argsParam);
+
+ return lambda.Compile();
+ }
+
+ ///
+ /// Creates an instance of the modifier.
+ ///
+ /// Parameters for the constructor.
+ /// An instance of the modifier.
+ public static T CreateInstance(params object[] args)
+ {
+ return Constructor(args);
+ }
+}
diff --git a/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs b/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs
index d7a99d5..17356db 100644
--- a/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs
+++ b/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs
@@ -1,7 +1,7 @@
using System.Linq;
using HarmonyLib;
+using MiraAPI.Modifiers;
using MiraAPI.Modifiers.Types;
-using MiraAPI.Utilities;
namespace MiraAPI.Patches.Modifiers;
diff --git a/MiraAPI/Patches/PlayerControlPatches.cs b/MiraAPI/Patches/PlayerControlPatches.cs
index bc98a51..e0d647d 100644
--- a/MiraAPI/Patches/PlayerControlPatches.cs
+++ b/MiraAPI/Patches/PlayerControlPatches.cs
@@ -86,6 +86,6 @@ public static class PlayerControlPatches
[HarmonyPatch(nameof(PlayerControl.OnDestroy))]
public static void PlayerControlOnDestroyPrefix(PlayerControl __instance)
{
- Utilities.Extensions.ModifierComponents.Remove(__instance);
+ ModifierExtensions.ModifierComponents.Remove(__instance);
}
}
diff --git a/MiraAPI/Patches/VentPatches.cs b/MiraAPI/Patches/VentPatches.cs
index 66c9aae..a41c690 100644
--- a/MiraAPI/Patches/VentPatches.cs
+++ b/MiraAPI/Patches/VentPatches.cs
@@ -1,6 +1,6 @@
using HarmonyLib;
+using MiraAPI.Modifiers;
using MiraAPI.Roles;
-using MiraAPI.Utilities;
using UnityEngine;
namespace MiraAPI.Patches;
diff --git a/MiraAPI/Utilities/Extensions.cs b/MiraAPI/Utilities/Extensions.cs
index 032cff3..d177d60 100644
--- a/MiraAPI/Utilities/Extensions.cs
+++ b/MiraAPI/Utilities/Extensions.cs
@@ -3,10 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using HarmonyLib;
using MiraAPI.GameOptions;
-using MiraAPI.Modifiers;
using MiraAPI.Networking;
using MiraAPI.Roles;
-using Reactor.Networking.Attributes;
using Reactor.Utilities;
using UnityEngine;
@@ -130,30 +128,6 @@ public static class Extensions
opt => opt.OptionBehaviour && opt.OptionBehaviour == optionBehaviour);
}
- internal static Dictionary ModifierComponents { get; } = [];
-
- ///
- /// Gets the ModifierComponent for a player.
- ///
- /// The PlayerControl object.
- /// A ModifierComponent if there is one, null otherwise.
- public static ModifierComponent? GetModifierComponent(this PlayerControl player)
- {
- if (ModifierComponents.TryGetValue(player, out var component))
- {
- return component;
- }
-
- component = player.GetComponent();
- if (component == null)
- {
- return null;
- }
-
- ModifierComponents[player] = component;
- return component;
- }
-
///
/// Randomizes a list.
///
@@ -174,105 +148,6 @@ public static class Extensions
return randomizedList;
}
- ///
- /// Gets a modifier by its type, or null if the player doesn't have it.
- ///
- /// The PlayerControl object.
- /// The Type of the Modifier.
- /// The Modifier if it is found, null otherwise.
- public static T? GetModifier(this PlayerControl? player) where T : BaseModifier
- {
- return player?.GetModifierComponent()?.ActiveModifiers.Find(x => x is T) as T;
- }
-
- ///
- /// Checks if a player has a modifier.
- ///
- /// The PlayerControl object.
- /// The Type of the Modifier.
- /// True if the Modifier is present, false otherwise.
- public static bool HasModifier(this PlayerControl? player) where T : BaseModifier
- {
- return player?.GetModifierComponent() != null &&
- player.GetModifierComponent()!.HasModifier();
- }
-
- ///
- /// Checks if a player has a modifier by its ID.
- ///
- /// The PlayerControl object.
- /// The Modifier ID.
- /// True if the Modifier is present, false otherwise.
- public static bool HasModifier(this PlayerControl? player, uint id)
- {
- return player?.GetModifierComponent() != null &&
- player.GetModifierComponent()!.HasModifier(id);
- }
-
- ///
- /// Remote Procedure Call to remove a modifier from a player.
- ///
- /// The player to remove the modifier from.
- /// The ID of the modifier.
- [MethodRpc((uint)MiraRpc.RemoveModifier)]
- public static void RpcRemoveModifier(this PlayerControl target, uint modifierId)
- {
- target.GetModifierComponent()?.RemoveModifier(modifierId);
- }
-
- ///
- /// Remote Procedure Call to remove a modifier from a player.
- ///
- /// The player to remove the modifier from.
- /// The Type of the Modifier.
- public static void RpcRemoveModifier(this PlayerControl player) where T : BaseModifier
- {
- var id = ModifierManager.GetModifierId(typeof(T));
-
- if (id == null)
- {
- Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
- return;
- }
-
- player.RpcRemoveModifier(id.Value);
- }
-
- ///
- /// Remote Procedure Call to add a modifier to a player.
- ///
- /// The player to add the modifier to.
- /// The modifier ID.
- [MethodRpc((uint)MiraRpc.AddModifier)]
- public static void RpcAddModifier(this PlayerControl target, uint modifierId)
- {
- var type = ModifierManager.GetModifierType(modifierId);
- if (type == null)
- {
- Logger.Error($"Cannot add modifier with id {modifierId} because it is not registered.");
- return;
- }
-
- target.GetModifierComponent()?.AddModifier(type);
- }
-
- ///
- /// Remote Procedure Call to add a modifier to a player.
- ///
- /// The player to add the modifier to.
- /// The modifier Type.
- public static void RpcAddModifier(this PlayerControl player) where T : BaseModifier
- {
- var id = ModifierManager.GetModifierId(typeof(T));
- if (id == null)
- {
- Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
- return;
- }
-
- player.RpcAddModifier(id.Value);
- }
-
///
/// Darkens a color by a specified amount.
///
From ce81d8c1ff8be72e41ce26415f0667364cd63e03 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 2 Feb 2025 20:36:14 -0500
Subject: [PATCH 02/14] it works?
---
MiraAPI/Modifiers/ModifierData.cs | 21 +++++++++
MiraAPI/Modifiers/ModifierExtensions.cs | 9 ++--
MiraAPI/Networking/AddModifierRpc.cs | 61 +++++++++++++++++++++++++
3 files changed, 86 insertions(+), 5 deletions(-)
create mode 100644 MiraAPI/Modifiers/ModifierData.cs
create mode 100644 MiraAPI/Networking/AddModifierRpc.cs
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);
+ }
+}
From 8e2535ada25339845470623541afe08386bfc326 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 2 Feb 2025 20:42:23 -0500
Subject: [PATCH 03/14] yes it works
---
MiraAPI.Example/Buttons/TestButton.cs | 27 +++++++++++++++++++++
MiraAPI.Example/Modifiers/ModifierParams.cs | 16 ++++++++++++
2 files changed, 43 insertions(+)
create mode 100644 MiraAPI.Example/Buttons/TestButton.cs
create mode 100644 MiraAPI.Example/Modifiers/ModifierParams.cs
diff --git a/MiraAPI.Example/Buttons/TestButton.cs b/MiraAPI.Example/Buttons/TestButton.cs
new file mode 100644
index 0000000..8062c81
--- /dev/null
+++ b/MiraAPI.Example/Buttons/TestButton.cs
@@ -0,0 +1,27 @@
+using MiraAPI.Example.Modifiers;
+using MiraAPI.Hud;
+using MiraAPI.Modifiers;
+using MiraAPI.Utilities.Assets;
+using Reactor.Utilities.Extensions;
+using UnityEngine;
+
+namespace MiraAPI.Example.Buttons;
+
+[RegisterButton]
+public class TestButton : CustomActionButton
+{
+ public override string Name => "Test Button";
+ public override float Cooldown => 0f;
+ public override LoadableAsset Sprite => ExampleAssets.ExampleButton;
+
+ protected override void OnClick()
+ {
+ var randomPlayer = PlayerControl.AllPlayerControls.ToArray().Random();
+ PlayerControl.LocalPlayer.RpcAddModifier("test", 1, randomPlayer);
+ }
+
+ public override bool Enabled(RoleBehaviour? role)
+ {
+ return true;
+ }
+}
diff --git a/MiraAPI.Example/Modifiers/ModifierParams.cs b/MiraAPI.Example/Modifiers/ModifierParams.cs
new file mode 100644
index 0000000..cde7d3b
--- /dev/null
+++ b/MiraAPI.Example/Modifiers/ModifierParams.cs
@@ -0,0 +1,16 @@
+using MiraAPI.Modifiers;
+using Reactor.Utilities;
+
+namespace MiraAPI.Example.Modifiers;
+
+[RegisterModifier]
+public class ModifierParams : BaseModifier
+{
+ public override string ModifierName => "ModifierParams";
+
+ public ModifierParams(string param1, int param2, PlayerControl playerControl)
+ {
+ Logger.Error($"Param1: {param1}, Param2: {param2}");
+ Logger.Error($"Player: {playerControl.PlayerId}");
+ }
+}
From 0ebec6d0f1ba220950db3932ee93b3d7a1df42d0 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 23 Feb 2025 20:28:24 -0500
Subject: [PATCH 04/14] fix testing thing
---
MiraAPI.Example/Buttons/TestButton.cs | 1 -
MiraAPI.Example/Modifiers/ModifierParams.cs | 1 -
2 files changed, 2 deletions(-)
diff --git a/MiraAPI.Example/Buttons/TestButton.cs b/MiraAPI.Example/Buttons/TestButton.cs
index 8062c81..feb7992 100644
--- a/MiraAPI.Example/Buttons/TestButton.cs
+++ b/MiraAPI.Example/Buttons/TestButton.cs
@@ -7,7 +7,6 @@ using UnityEngine;
namespace MiraAPI.Example.Buttons;
-[RegisterButton]
public class TestButton : CustomActionButton
{
public override string Name => "Test Button";
diff --git a/MiraAPI.Example/Modifiers/ModifierParams.cs b/MiraAPI.Example/Modifiers/ModifierParams.cs
index cde7d3b..e92bbda 100644
--- a/MiraAPI.Example/Modifiers/ModifierParams.cs
+++ b/MiraAPI.Example/Modifiers/ModifierParams.cs
@@ -3,7 +3,6 @@ using Reactor.Utilities;
namespace MiraAPI.Example.Modifiers;
-[RegisterModifier]
public class ModifierParams : BaseModifier
{
public override string ModifierName => "ModifierParams";
From 1c6fa9a84dae0b057b32fcbeca83d7b1bdd9aff8 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 24 Feb 2025 21:51:02 -0500
Subject: [PATCH 05/14] major modifier overhaul
---
MiraAPI/Modifiers/BaseModifier.cs | 23 +-
MiraAPI/Modifiers/ModifierComponent.cs | 270 ++++++++++-----
MiraAPI/Modifiers/ModifierData.cs | 10 +-
MiraAPI/Modifiers/ModifierExtensions.cs | 313 ++++++++++++++----
MiraAPI/Modifiers/ModifierFactory.cs | 43 ++-
MiraAPI/Modifiers/ModifierManager.cs | 8 +-
MiraAPI/Modifiers/Types/TimedModifier.cs | 2 +-
MiraAPI/Networking/AddModifierRpc.cs | 42 ++-
.../Patches/Freeplay/TaskAddButtonPatches.cs | 2 +-
MiraAPI/Patches/Freeplay/TaskAdderPatches.cs | 9 +-
MiraAPI/Patches/PlayerControlPatches.cs | 2 +-
MiraAPI/Patches/Roles/TaskPanelPatch.cs | 2 +-
MiraAPI/Utilities/ModifierExtensions.cs | 252 --------------
13 files changed, 531 insertions(+), 447 deletions(-)
delete mode 100644 MiraAPI/Utilities/ModifierExtensions.cs
diff --git a/MiraAPI/Modifiers/BaseModifier.cs b/MiraAPI/Modifiers/BaseModifier.cs
index 9f6aa93..8834454 100644
--- a/MiraAPI/Modifiers/BaseModifier.cs
+++ b/MiraAPI/Modifiers/BaseModifier.cs
@@ -1,4 +1,6 @@
-namespace MiraAPI.Modifiers;
+using System;
+
+namespace MiraAPI.Modifiers;
///
/// Base class for all modifiers.
@@ -15,11 +17,6 @@ public abstract class BaseModifier
///
public ModifierComponent? ModifierComponent { get; internal set; }
- ///
- /// Gets the modifier id.
- ///
- public uint ModifierId { get; internal set; }
-
///
/// Gets the modifier name.
///
@@ -40,6 +37,20 @@ public abstract class BaseModifier
///
public virtual bool Unique => true;
+ ///
+ /// Gets a value indicating whether the modifier has been initialized.
+ ///
+ public bool Initialized { get; internal set; }
+
+ ///
+ /// Get the ID of the modifier.
+ ///
+ /// The ID of the modifier.
+ public uint GetId()
+ {
+ return ModifierManager.GetModifierId(GetType()) ?? throw new InvalidOperationException("Modifier is not registered.");
+ }
+
///
/// Gets the HUD information for this modifier. Defaults to the modifier name. Does nothing if is true.
///
diff --git a/MiraAPI/Modifiers/ModifierComponent.cs b/MiraAPI/Modifiers/ModifierComponent.cs
index 2b00652..6cd3d5e 100644
--- a/MiraAPI/Modifiers/ModifierComponent.cs
+++ b/MiraAPI/Modifiers/ModifierComponent.cs
@@ -67,6 +67,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
foreach (var modifier in _toAdd)
{
Modifiers.Add(modifier);
+ modifier.Initialized = true;
modifier.OnActivate();
if (modifier is TimedModifier { AutoStart: true } timer)
@@ -123,46 +124,153 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
}
///
- /// Gets a collection of modifiers by their type, or null if the player doesn't have one.
+ /// Gets a collection of modifiers by type.
///
+ /// The predicate to check the modifier by.
/// The Type of the Modifier.
/// The Modifier if it is found, null otherwise.
- public IEnumerable GetModifiersByType() where T : BaseModifier
+ [HideFromIl2Cpp]
+ public IEnumerable GetModifiersByType(Func? predicate=null) where T : BaseModifier
{
- return ActiveModifiers.OfType();
+ return ActiveModifiers.OfType().Where(x => predicate == null || predicate(x));
}
///
- /// Gets a modifier by its type, or null if the player doesn't have it.
+ /// Gets a collection of modifiers by type.
///
- /// The Type of the Modifier.
+ /// The modifier type.
+ /// The predicate to check the modifier by.
/// The Modifier if it is found, null otherwise.
- public T? GetModifier() where T : BaseModifier
+ [HideFromIl2Cpp]
+ public IEnumerable GetModifiersByType(Type type, Func? predicate=null)
{
- return GetModifiersByType().FirstOrDefault();
+ return ActiveModifiers.Where(x => x.GetType() == type && (predicate == null || predicate(x)));
+ }
+
+ ///
+ /// Gets a collection of modifiers by ID.
+ ///
+ /// The Modifier ID.
+ /// The predicate to check the modifier by.
+ /// The Modifier if it is found, null otherwise.
+ [HideFromIl2Cpp]
+ public IEnumerable GetModifiersByType(uint id, Func? predicate=null)
+ {
+ var type = ModifierManager.GetModifierType(id) ?? throw new InvalidOperationException(
+ $"Cannot get modifier with id {id} because it is not registered.");
+
+ return GetModifiersByType(type, predicate);
}
///
/// Tries to get a modifier by its type.
///
/// The modifier or null.
+ /// The predicate to check the modifier by.
/// The Type of the Modifier.
/// True if the modifier was found, false otherwise.
- public bool TryGetModifier(out T? modifier) where T : BaseModifier
+ [HideFromIl2Cpp]
+ public bool TryGetModifier(out T? modifier, Func? predicate = null) where T : BaseModifier
{
- modifier = GetModifier();
+ modifier = GetModifier(predicate);
return modifier != null;
}
+ ///
+ /// Tries to get a modifier by its type.
+ ///
+ /// The modifier type.
+ /// The modifier or null.
+ /// The predicate to check the modifier by.
+ /// True if the modifier was found, false otherwise.
+ [HideFromIl2Cpp]
+ public bool TryGetModifier(Type type, out BaseModifier? modifier, Func? predicate = null)
+ {
+ modifier = GetModifier(type, predicate);
+ return modifier != null;
+ }
+
+ ///
+ /// Tries to get a modifier by its ID.
+ ///
+ /// The modifier ID.
+ /// The modifier or null.
+ /// The predicate to check the modifier by.
+ /// True if the modifier was found, false otherwise.
+ [HideFromIl2Cpp]
+ public bool TryGetModifier(uint id, out BaseModifier? modifier, Func? predicate = null)
+ {
+ var type = ModifierManager.GetModifierType(id) ?? throw new InvalidOperationException(
+ $"Cannot get modifier with id {id} because it is not registered.");
+
+ return TryGetModifier(type, out modifier, predicate);
+ }
+
+ ///
+ /// Gets a modifier by its type, or null if the player doesn't have it.
+ ///
+ /// The predicate to check the modifier by.
+ /// The Type of the Modifier.
+ /// The Modifier if it is found, null otherwise.
+ [HideFromIl2Cpp]
+ public T? GetModifier(Func? predicate = null) where T : BaseModifier
+ {
+ return GetModifiersByType(predicate).FirstOrDefault();
+ }
+
+ ///
+ /// Gets a modifier by its type, or null if the player doesn't have it.
+ ///
+ /// The modifier type.
+ /// The predicate to check the modifier by.
+ /// The Modifier if it is found, null otherwise.
+ [HideFromIl2Cpp]
+ public BaseModifier? GetModifier(Type type, Func? predicate = null)
+ {
+ return GetModifiersByType(type).FirstOrDefault(predicate ?? (_ => true));
+ }
+
+ ///
+ /// Gets a modifier by its type, or null if the player doesn't have it.
+ ///
+ /// The modifier ID.
+ /// The predicate to check the modifier by.
+ /// The Modifier if it is found, null otherwise.
+ [HideFromIl2Cpp]
+ public BaseModifier? GetModifier(uint id, Func? predicate = null)
+ {
+ var type = ModifierManager.GetModifierType(id) ?? throw new InvalidOperationException(
+ $"Cannot get modifier with id {id} because it is not registered.");
+
+ return GetModifier(type, predicate);
+ }
+
+ ///
+ /// Removes a modifier from the player.
+ ///
+ /// The modifier type.
+ /// The predicate to check the modifier by.
+ [HideFromIl2Cpp]
+ public void RemoveModifier(Func? predicate = null) where T : BaseModifier
+ {
+ RemoveModifier(typeof(T), x => predicate == null || predicate((T)x));
+ }
+
///
/// Removes a modifier from the player.
///
/// The modifier type.
+ /// The predicate to check the modifier by.
[HideFromIl2Cpp]
- public void RemoveModifier(Type type)
+ public void RemoveModifier(Type type, Func? predicate = null)
{
- var modifier = Modifiers.Find(x => x.GetType() == type);
+ var modifiers = Modifiers.Where(x => x.GetType() == type && (predicate == null || predicate(x))).ToList();
+ if (modifiers.Count > 1)
+ {
+ throw new InvalidOperationException($"Cannot remove modifier {type.Name} because there are multiple instances of that modifier.");
+ }
+ var modifier = modifiers.FirstOrDefault();
if (modifier is null)
{
Logger.Error($"Cannot remove modifier {type.Name} because it is not active.");
@@ -172,32 +280,17 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
RemoveModifier(modifier);
}
- ///
- /// Removes a modifier from the player.
- ///
- /// The modifier type.
- [HideFromIl2Cpp]
- public void RemoveModifier() where T : BaseModifier
- {
- RemoveModifier(typeof(T));
- }
-
///
/// Removes a modifier from the player.
///
/// The modifier ID.
+ /// The predicate to check the modifier by.
[HideFromIl2Cpp]
- public void RemoveModifier(uint modifierId)
+ public void RemoveModifier(uint modifierId, Func? predicate = null)
{
- var modifier = Modifiers.Find(x => x.ModifierId == modifierId);
-
- if (modifier is null)
- {
- Logger.Error($"Cannot remove modifier with id {modifierId} because it is not active.");
- return;
- }
-
- RemoveModifier(modifier);
+ var type = ModifierManager.GetModifierType(modifierId) ?? throw new InvalidOperationException(
+ $"Cannot remove modifier with id {modifierId} because it is not registered.");
+ RemoveModifier(type, predicate);
}
///
@@ -216,6 +309,18 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
_toRemove.Add(modifier);
}
+ ///
+ /// Adds a modifier to the player.
+ ///
+ /// The arguments to initialize the modifier constructor with.
+ /// The Type of the modifier.
+ /// The new modifier.
+ [HideFromIl2Cpp]
+ public T? AddModifier(params object[] args) where T : BaseModifier
+ {
+ return AddModifier(typeof(T), args) as T;
+ }
+
///
/// Adds a modifier to the player.
///
@@ -224,24 +329,22 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
[HideFromIl2Cpp]
public BaseModifier? AddModifier(BaseModifier modifier)
{
- if (Modifiers.Contains(modifier))
+ var id = modifier.GetId();
+ if (modifier.Unique && Modifiers.Find(x => x.GetId() == id) != null)
{
- Logger.Error($"Player already has modifier with id {modifier.ModifierId}!");
+ Logger.Error($"Player already has modifier with id {id}!");
return null;
}
- var modifierId = ModifierManager.GetModifierId(modifier.GetType());
-
- if (modifierId == null)
+ if (Modifiers.Contains(modifier))
{
- Logger.Error($"Cannot add modifier {modifier.GetType().Name} because it has no ID!");
+ Logger.Error($"Player already has this modifier!");
return null;
}
_toAdd.Add(modifier);
modifier.Player = _player;
modifier.ModifierComponent = this;
- modifier.ModifierId = modifierId.Value;
return modifier;
}
@@ -249,66 +352,79 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
/// Adds a modifier to the player.
///
/// The modifier type.
+ /// The arguments to initialize the modifier constructor with.
/// The modifier that was added.
[HideFromIl2Cpp]
- public BaseModifier? AddModifier(Type type)
+ public BaseModifier? AddModifier(Type type, params object[] args)
{
- var modifierId = ModifierManager.GetModifierId(type);
- if (modifierId == null)
+ BaseModifier? modifier;
+ if (args.Length > 0)
{
- Logger.Error($"Cannot add modifier {type.Name} because it is not registered.");
- return null;
+ modifier = ModifierFactory.CreateInstance(type, args);
+ }
+ else
+ {
+ modifier = Activator.CreateInstance(type) as BaseModifier;
+ if (modifier == null)
+ {
+ throw new InvalidOperationException($"Cannot add modifier {type.Name} because it is not a valid modifier.");
+ }
}
- if (Modifiers.Find(x => x.ModifierId == modifierId && x.Unique) != null)
- {
- Logger.Error($"Player already has modifier with id {modifierId}!");
- return null;
- }
-
- if (Activator.CreateInstance(type) is not BaseModifier modifier)
- {
- Logger.Error($"Cannot add modifier {type.Name} because it is null.");
- return null;
- }
-
- AddModifier(modifier);
-
- return modifier;
+ return AddModifier(modifier);
}
///
/// Adds a modifier to the player.
///
- /// The Type of the modifier.
- /// The new modifier.
+ /// The ID of the modifier.
+ /// The arguments to initialize the modifier constructor with.
+ /// The modifier if it was created, or null if it failed.
[HideFromIl2Cpp]
- public T? AddModifier() where T : BaseModifier
+ public BaseModifier? AddModifier(uint id, params object[] args)
{
- return AddModifier(typeof(T)) as T;
+ var type = ModifierManager.GetModifierType(id) ?? throw new InvalidOperationException(
+ $"Cannot add modifier with id {id} because it is not registered.");
+
+ return AddModifier(type, args);
}
///
- /// Checks if a player has an active or queued modifier by its ID.
- ///
- /// The Modifier ID.
- /// The predicate to check the modifier.
- /// True if the Modifier is present, false otherwise.
- public bool HasModifier(uint id, Func? predicate=null)
- {
- return ActiveModifiers.Exists(x => x.ModifierId == id && (predicate == null || predicate(x))) ||
- _toAdd.Exists(x => x.ModifierId == id && (predicate == null || predicate(x)));
- }
-
- ///
- /// Checks if a player has an active or queued modifier by its type.
+ /// Checks if a player has an active modifier by its type.
///
/// The predicate to check the modifier.
/// The Type of the Modifier.
/// True if the Modifier is present, false otherwise.
+ [HideFromIl2Cpp]
public bool HasModifier(Func? predicate=null) where T : BaseModifier
{
- return ModifierManager.GetModifierId(typeof(T)) is { } id &&
- HasModifier(id, (Func?)predicate);
+ return ActiveModifiers.Exists(x => x is T modifier && (predicate == null || predicate(modifier)));
+ }
+
+ ///
+ /// Checks if a player has an active modifier by its type.
+ ///
+ /// The modifier type.
+ /// The predicate to check the modifier.
+ /// True if the Modifier is present, false otherwise.
+ [HideFromIl2Cpp]
+ public bool HasModifier(Type type, Func? predicate=null)
+ {
+ return ActiveModifiers.Exists(x => x.GetType() == type && (predicate == null || predicate(x)));
+ }
+
+ ///
+ /// Checks if a player has an active modifier by its ID.
+ ///
+ /// The Modifier ID.
+ /// The predicate to check the modifier.
+ /// True if the Modifier is present, false otherwise.
+ [HideFromIl2Cpp]
+ public bool HasModifier(uint id, Func? predicate=null)
+ {
+ var type = ModifierManager.GetModifierType(id) ?? throw new InvalidOperationException(
+ $"Cannot get modifier with id {id} because it is not registered.");
+
+ return HasModifier(type, predicate);
}
}
diff --git a/MiraAPI/Modifiers/ModifierData.cs b/MiraAPI/Modifiers/ModifierData.cs
index 425e063..7260834 100644
--- a/MiraAPI/Modifiers/ModifierData.cs
+++ b/MiraAPI/Modifiers/ModifierData.cs
@@ -1,18 +1,16 @@
-using System;
-
-namespace MiraAPI.Modifiers;
+namespace MiraAPI.Modifiers;
///
/// Modifier data for networking.
///
-/// The Type of the modifier.
+/// The ID of the modifier.
/// Parameters for constructor.
-public readonly struct ModifierData(Type type, object[] args)
+public readonly struct ModifierData(uint id, object[] args)
{
///
/// Gets the type of the modifier.
///
- public Type Type { get; } = type;
+ public uint Id { get; } = id;
///
/// Gets the parameters for the constructor.
diff --git a/MiraAPI/Modifiers/ModifierExtensions.cs b/MiraAPI/Modifiers/ModifierExtensions.cs
index d6ce5ff..226b16b 100644
--- a/MiraAPI/Modifiers/ModifierExtensions.cs
+++ b/MiraAPI/Modifiers/ModifierExtensions.cs
@@ -8,11 +8,81 @@ using Reactor.Utilities;
namespace MiraAPI.Modifiers;
///
-/// Extension methods for modifiers.
+/// Extensions for modifiers.
///
public static class ModifierExtensions
{
- internal static Dictionary ModifierComponents { get; } = [];
+ ///
+ /// Gets the dictionary to cache ModifierComponents.
+ ///
+ public static Dictionary ModifierComponents { get; } = [];
+
+ ///
+ /// Remote Procedure Call to add a modifier to a player.
+ ///
+ /// The player to add the modifier to.
+ /// The modifier ID.
+ /// The arguments to initialize the modifier constructor with.
+ public static void RpcAddModifier(this PlayerControl target, uint modifierId, params object[] args)
+ {
+ _ = ModifierManager.GetModifierType(modifierId) ?? throw new InvalidOperationException(
+ $"Modifier with ID {modifierId} is not registered.");
+
+ Rpc.Instance.Send(target, new ModifierData(modifierId, args));
+ }
+
+ ///
+ /// Remote Procedure Call to add a modifier to a player.
+ ///
+ /// The player to add the modifier to.
+ /// The type of the modifier.
+ /// The arguments to initialize the modifier constructor with.
+ public static void RpcAddModifier(this PlayerControl player, Type type, params object[] args)
+ {
+ var id = ModifierManager.GetModifierId(type) ?? throw new InvalidOperationException(
+ $"Modifier {type.Name} is not registered.");
+
+ player.RpcAddModifier(id, args);
+ }
+
+ ///
+ /// Remote Procedure Call to add a modifier to a player.
+ ///
+ /// The player to add the modifier to.
+ /// The arguments to initialize the modifier constructor with.
+ /// The modifier Type.
+ public static void RpcAddModifier(this PlayerControl player, params object[] args) where T : BaseModifier
+ {
+ player.RpcAddModifier(typeof(T), args);
+ }
+
+ ///
+ /// Remote Procedure Call to remove a modifier from a player.
+ ///
+ /// The player to remove the modifier from.
+ /// The ID of the modifier.
+ [MethodRpc((uint)MiraRpc.RemoveModifier)]
+ public static void RpcRemoveModifier(this PlayerControl target, uint modifierId)
+ {
+ target.RemoveModifier(modifierId);
+ }
+
+ ///
+ /// Remote Procedure Call to remove a modifier from a player.
+ ///
+ /// The player to remove the modifier from.
+ /// The Type of the Modifier.
+ public static void RpcRemoveModifier(this PlayerControl player) where T : BaseModifier
+ {
+ var id = ModifierManager.GetModifierId(typeof(T));
+ if (id == null)
+ {
+ Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
+ return;
+ }
+
+ player.RpcRemoveModifier(id.Value);
+ }
///
/// Gets the ModifierComponent for a player.
@@ -37,102 +107,217 @@ public static class ModifierExtensions
}
///
- /// Gets a modifier by its type, or null if the player doesn't have it.
+ /// Checks if the player has a specific modifier.
///
- /// The PlayerControl object.
- /// The Type of the Modifier.
- /// The Modifier if it is found, null otherwise.
- public static T? GetModifier(this PlayerControl? player) where T : BaseModifier
+ /// The type of the modifier.
+ /// The PlayerControl instance.
+ /// Optional predicate to filter the modifiers.
+ /// True if the player has the modifier, false otherwise.
+ public static bool HasModifier(this PlayerControl player, Func? predicate = null) where T : BaseModifier
{
- return player?.GetModifierComponent()?.ActiveModifiers.Find(x => x is T) as T;
+ return player.GetModifierComponent()!.HasModifier(predicate);
}
///
- /// Checks if a player has a modifier.
+ /// Checks if the player has a specific modifier by type.
///
- /// The PlayerControl object.
- /// The Type of the Modifier.
- /// True if the Modifier is present, false otherwise.
- public static bool HasModifier(this PlayerControl? player) where T : BaseModifier
+ /// The PlayerControl instance.
+ /// The type of the modifier.
+ /// Optional predicate to filter the modifiers.
+ /// True if the player has the modifier, false otherwise.
+ public static bool HasModifier(this PlayerControl player, Type type, Func? predicate = null)
{
- return player?.GetModifierComponent() != null &&
- player.GetModifierComponent()!.HasModifier();
+ return player.GetModifierComponent()!.HasModifier(type, predicate);
}
///
- /// Checks if a player has a modifier by its ID.
+ /// Checks if the player has a specific modifier by ID.
///
- /// The PlayerControl object.
- /// The Modifier ID.
- /// True if the Modifier is present, false otherwise.
- public static bool HasModifier(this PlayerControl? player, uint id)
+ /// The PlayerControl instance.
+ /// The ID of the modifier.
+ /// Optional predicate to filter the modifiers.
+ /// True if the player has the modifier, false otherwise.
+ public static bool HasModifier(this PlayerControl player, uint id, Func? predicate = null)
{
- return player?.GetModifierComponent() != null &&
- player.GetModifierComponent()!.HasModifier(id);
+ return player.GetModifierComponent()!.HasModifier(id, predicate);
}
///
- /// Remote Procedure Call to remove a modifier from a player.
+ /// Gets a specific modifier from the player.
///
- /// The player to remove the modifier from.
+ /// The type of the modifier.
+ /// The PlayerControl instance.
+ /// Optional predicate to filter the modifiers.
+ /// The modifier if found, null otherwise.
+ public static T? GetModifier(this PlayerControl player, Func? predicate = null) where T : BaseModifier
+ {
+ return player.GetModifierComponent()!.GetModifier(predicate);
+ }
+
+ ///
+ /// Gets a specific modifier from the player by type.
+ ///
+ /// The PlayerControl instance.
+ /// The type of the modifier.
+ /// Optional predicate to filter the modifiers.
+ /// The modifier if found, null otherwise.
+ public static BaseModifier? GetModifier(
+ this PlayerControl player,
+ Type type,
+ Func? predicate = null)
+ {
+ return player.GetModifierComponent()!.GetModifier(type, predicate);
+ }
+
+ ///
+ /// Gets a specific modifier from the player by ID.
+ ///
+ /// The PlayerControl instance.
+ /// The ID of the modifier.
+ /// Optional predicate to filter the modifiers.
+ /// The modifier if found, null otherwise.
+ public static BaseModifier? GetModifier(
+ this PlayerControl player,
+ uint id,
+ Func? predicate = null)
+ {
+ return player.GetModifierComponent()!.GetModifier(id, predicate);
+ }
+
+ ///
+ /// Gets all modifiers of a specific type from the player.
+ ///
+ /// The type of the modifiers.
+ /// The PlayerControl instance.
+ /// Optional predicate to filter the modifiers.
+ /// An enumerable of modifiers.
+ public static IEnumerable GetModifiersByType(this PlayerControl player, Func? predicate = null)
+ where T : BaseModifier
+ {
+ return player.GetModifierComponent()!.GetModifiersByType(predicate);
+ }
+
+ ///
+ /// Gets all modifiers of a specific type from the player.
+ ///
+ /// The PlayerControl instance.
+ /// The type of the modifiers.
+ /// Optional predicate to filter the modifiers.
+ /// An enumerable of modifiers.
+ public static IEnumerable GetModifiersByType(
+ this PlayerControl player,
+ Type type,
+ Func? predicate = null)
+ {
+ return player.GetModifierComponent()!.GetModifiersByType(type, predicate);
+ }
+
+ ///
+ /// Gets all modifiers of a specific type from the player by ID.
+ ///
+ /// The PlayerControl instance.
+ /// The ID of the modifiers.
+ /// Optional predicate to filter the modifiers.
+ /// An enumerable of modifiers.
+ public static IEnumerable GetModifiersByType(
+ this PlayerControl player,
+ uint id,
+ Func? predicate = null)
+ {
+ return player.GetModifierComponent()!.GetModifiersByType(id, predicate);
+ }
+
+ ///
+ /// Removes a specific modifier from the player.
+ ///
+ /// The type of the modifier.
+ /// The PlayerControl instance.
+ /// Optional predicate to filter the modifiers.
+ public static void RemoveModifier(this PlayerControl player, Func? predicate = null)
+ where T : BaseModifier
+ {
+ player.GetModifierComponent()!.RemoveModifier(predicate);
+ }
+
+ ///
+ /// Removes a specific modifier from the player by type.
+ ///
+ /// The PlayerControl instance.
+ /// The type of the modifier.
+ /// Optional predicate to filter the modifiers.
+ public static void RemoveModifier(this PlayerControl player, Type type, Func? predicate = null)
+ {
+ player.GetModifierComponent()!.RemoveModifier(type, predicate);
+ }
+
+ ///
+ /// Removes a specific modifier from the player by ID.
+ ///
+ /// The PlayerControl instance.
/// The ID of the modifier.
- [MethodRpc((uint)MiraRpc.RemoveModifier)]
- public static void RpcRemoveModifier(this PlayerControl target, uint modifierId)
+ /// Optional predicate to filter the modifiers.
+ public static void RemoveModifier(
+ this PlayerControl player,
+ uint modifierId,
+ Func? predicate = null)
{
- target.GetModifierComponent()?.RemoveModifier(modifierId);
+ player.GetModifierComponent()!.RemoveModifier(modifierId, predicate);
}
///
- /// Remote Procedure Call to remove a modifier from a player.
+ /// Removes a specific modifier from the player.
///
- /// The player to remove the modifier from.
- /// The Type of the Modifier.
- public static void RpcRemoveModifier(this PlayerControl player) where T : BaseModifier
+ /// The PlayerControl instance.
+ /// The modifier to remove.
+ public static void RemoveModifier(this PlayerControl player, BaseModifier modifier)
{
- var id = ModifierManager.GetModifierId(typeof(T));
-
- if (id == null)
- {
- Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
- return;
- }
-
- player.RpcRemoveModifier(id.Value);
+ player.GetModifierComponent()!.RemoveModifier(modifier);
}
///
- /// Remote Procedure Call to add a modifier to a player.
+ /// Adds a specific modifier to the player.
///
- /// The player to add the modifier to.
- /// The modifier ID.
+ /// The type of the modifier.
+ /// The PlayerControl instance.
/// The arguments to initialize the modifier constructor with.
- public static void RpcAddModifier(this PlayerControl target, uint modifierId, params object[] args)
+ /// The added modifier.
+ public static T? AddModifier(this PlayerControl player, params object[] args) where T : BaseModifier
{
- var type = ModifierManager.GetModifierType(modifierId);
- if (type == null)
- {
- Logger.Error($"Cannot add modifier with id {modifierId} because it is not registered.");
- return;
- }
-
- Rpc.Instance.Send(target, new ModifierData(type, args));
+ return player.GetModifierComponent()!.AddModifier(args);
}
///
- /// Remote Procedure Call to add a modifier to a player.
+ /// Adds a specific modifier to the player.
///
- /// The player to add the modifier to.
- /// The arguments to initialize the modifier constructor with.
- /// The modifier Type.
- public static void RpcAddModifier(this PlayerControl player, params object[] args) where T : BaseModifier
+ /// The PlayerControl instance.
+ /// The modifier to add.
+ /// The added modifier.
+ public static BaseModifier? AddModifier(this PlayerControl player, BaseModifier modifier)
{
- var id = ModifierManager.GetModifierId(typeof(T));
- if (id == null)
- {
- Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
- return;
- }
+ return player.GetModifierComponent()!.AddModifier(modifier);
+ }
- player.RpcAddModifier(id.Value, args);
+ ///
+ /// Adds a specific modifier to the player by type.
+ ///
+ /// The PlayerControl instance.
+ /// The type of the modifier.
+ /// The arguments to initialize the modifier constructor with.
+ /// The added modifier.
+ public static BaseModifier? AddModifier(this PlayerControl player, Type type, params object[] args)
+ {
+ return player.GetModifierComponent()!.AddModifier(type, args);
+ }
+
+ ///
+ /// Adds a specific modifier to the player by ID.
+ ///
+ /// The PlayerControl instance.
+ /// The ID of the modifier.
+ /// The arguments to initialize the modifier constructor with.
+ /// The added modifier.
+ public static BaseModifier? AddModifier(this PlayerControl player, uint id, params object[] args)
+ {
+ return player.GetModifierComponent()!.AddModifier(id, args);
}
}
diff --git a/MiraAPI/Modifiers/ModifierFactory.cs b/MiraAPI/Modifiers/ModifierFactory.cs
index e1b018c..d145b82 100644
--- a/MiraAPI/Modifiers/ModifierFactory.cs
+++ b/MiraAPI/Modifiers/ModifierFactory.cs
@@ -1,18 +1,28 @@
using System;
-using System.Linq;
using System.Linq.Expressions;
namespace MiraAPI.Modifiers;
+///
+/// Factory for creating instances of a modifier. More efficient than using reflection.
+///
public static class ModifierFactory
{
private static Func? _constructor;
- private static Func CreateConstructor(Type type)
+ private static Func CreateConstructor(Type type, params object[] args)
{
- var constructorInfo = type.GetConstructors()
- .OrderByDescending(c => c.GetParameters().Length)
- .FirstOrDefault() ?? throw new InvalidOperationException($"Type {type} does not have a public constructor.");
+ var constructorInfo = Array.Find(
+ type.GetConstructors(),
+ x =>
+ {
+ var parameters = x.GetParameters();
+ return parameters.Length == args.Length && Array.TrueForAll(
+ parameters,
+ t => t.ParameterType.IsInstanceOfType(args[t.Position]));
+ }) ?? throw new InvalidOperationException(
+ $"Could not find a constructor for type {type} with the specified arguments.");
+
var parameters = constructorInfo.GetParameters();
var argsParam = Expression.Parameter(typeof(object[]), "args");
@@ -32,9 +42,15 @@ public static class ModifierFactory
return lambda.Compile();
}
+ ///
+ /// Creates a modifier with the specified type and arguments.
+ ///
+ /// Modifier type.
+ /// Arguments.
+ /// An instance of the modifier.
public static BaseModifier CreateInstance(Type type, params object[] args)
{
- _constructor ??= CreateConstructor(type);
+ _constructor ??= CreateConstructor(type, args);
return _constructor(args);
}
}
@@ -47,11 +63,18 @@ public static class ModifierFactory where T : BaseModifier
{
private static readonly Func Constructor = CreateConstructor();
- private static Func CreateConstructor()
+ private static Func CreateConstructor(params object[] args)
{
- var constructorInfo = typeof(T).GetConstructors()
- .OrderByDescending(c => c.GetParameters().Length)
- .FirstOrDefault() ?? throw new InvalidOperationException($"Type {typeof(T)} does not have a public constructor.");
+ var constructorInfo = Array.Find(
+ typeof(T).GetConstructors(),
+ x =>
+ {
+ var parameters = x.GetParameters();
+ return parameters.Length == args.Length && Array.TrueForAll(
+ parameters,
+ t => t.ParameterType.IsInstanceOfType(args[t.Position]));
+ }) ?? throw new InvalidOperationException($"Could not find a constructor for type {typeof(T)} with the specified arguments.");
+
var parameters = constructorInfo.GetParameters();
var argsParam = Expression.Parameter(typeof(object[]), "args");
diff --git a/MiraAPI/Modifiers/ModifierManager.cs b/MiraAPI/Modifiers/ModifierManager.cs
index d4d4004..65341a0 100644
--- a/MiraAPI/Modifiers/ModifierManager.cs
+++ b/MiraAPI/Modifiers/ModifierManager.cs
@@ -48,7 +48,12 @@ public static class ModifierManager
/// The ID of the modifier.
public static uint? GetModifierId(Type type)
{
- return TypeToIdModifierMap.GetValueOrDefault(type);
+ if (!TypeToIdModifierMap.TryGetValue(type, out var id))
+ {
+ return null;
+ }
+
+ return id;
}
internal static bool RegisterModifier(Type modifierType, MiraPluginInfo info)
@@ -61,7 +66,6 @@ public static class ModifierManager
IdToTypeModifierMap.Add(GetNextId(), modifierType);
TypeToIdModifierMap.Add(modifierType, _nextId);
var bm = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType); // this probably isn't a great idea
- bm.ModifierId = _nextId;
info.Modifiers.Add(bm);
if (!typeof(GameModifier).IsAssignableFrom(modifierType))
diff --git a/MiraAPI/Modifiers/Types/TimedModifier.cs b/MiraAPI/Modifiers/Types/TimedModifier.cs
index 286b80a..038fa6d 100644
--- a/MiraAPI/Modifiers/Types/TimedModifier.cs
+++ b/MiraAPI/Modifiers/Types/TimedModifier.cs
@@ -102,7 +102,7 @@ public abstract class TimedModifier : BaseModifier
if (RemoveOnComplete)
{
- ModifierComponent?.RemoveModifier(ModifierId);
+ ModifierComponent?.RemoveModifier(this);
}
}
diff --git a/MiraAPI/Networking/AddModifierRpc.cs b/MiraAPI/Networking/AddModifierRpc.cs
index 3546d4f..fdc37a9 100644
--- a/MiraAPI/Networking/AddModifierRpc.cs
+++ b/MiraAPI/Networking/AddModifierRpc.cs
@@ -1,7 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
using Hazel;
using MiraAPI.Modifiers;
using Reactor.Networking.Attributes;
@@ -18,44 +15,45 @@ namespace MiraAPI.Networking;
[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);
+ writer.WritePacked(data.Id);
+ writer.WritePacked(data.Args.Length);
+ foreach (var arg in data.Args)
+ {
+ writer.Write(arg.GetType().AssemblyQualifiedName);
+ writer.Serialize(arg);
+ }
}
///
public override ModifierData Read(MessageReader reader)
{
var modId = reader.ReadPackedUInt32();
- var modifier = ModifierManager.GetModifierType(modId)!;
+ var argCount = reader.ReadPackedUInt32();
+ var objects = new object[argCount];
- if (!ParameterCache.TryGetValue(modifier, out var paramTypes))
+ if (argCount > 0)
{
- paramTypes = modifier.GetConstructors().OrderBy(x => x.GetParameters().Length).First().GetParameters();
- ParameterCache[modifier] = paramTypes;
+ var types = new Type[argCount];
+ for (var i = 0; i < argCount; i++)
+ {
+ var name = reader.ReadString();
+ types[i] = Type.GetType(name) ?? throw new InvalidOperationException($"Type not found: {name}");
+ objects[i] = reader.Deserialize(types[i]);
+ }
}
- var objects = new object[paramTypes.Length];
- foreach (var paramType in paramTypes)
- {
- objects[paramType.Position] = reader.Deserialize(paramType.ParameterType);
- }
-
- return new ModifierData(modifier, objects);
+ return new ModifierData(modId, objects);
}
///
- public override void Handle(PlayerControl innerNetObject, ModifierData data)
+ public override void Handle(PlayerControl player, ModifierData data)
{
- var modifier = ModifierFactory.CreateInstance(data.Type, data.Args);
- innerNetObject.GetModifierComponent()?.AddModifier(modifier);
+ player.AddModifier(data.Id, data.Args);
}
}
diff --git a/MiraAPI/Patches/Freeplay/TaskAddButtonPatches.cs b/MiraAPI/Patches/Freeplay/TaskAddButtonPatches.cs
index fb57d70..184bafb 100644
--- a/MiraAPI/Patches/Freeplay/TaskAddButtonPatches.cs
+++ b/MiraAPI/Patches/Freeplay/TaskAddButtonPatches.cs
@@ -1,6 +1,6 @@
using HarmonyLib;
+using MiraAPI.Modifiers;
using MiraAPI.Roles;
-using MiraAPI.Utilities;
using UnityEngine;
namespace MiraAPI.Patches.Freeplay;
diff --git a/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs b/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs
index d1c6cb9..b634c91 100644
--- a/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs
+++ b/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs
@@ -326,7 +326,7 @@ internal static class TaskAdderPatches
}
var taskAddButton = Object.Instantiate(instance.RoleButton);
- taskAddButton.name = modifier.ModifierId.ToString(CultureInfo.InvariantCulture);
+ taskAddButton.name = modifier.GetId().ToString(NumberFormatInfo.InvariantInfo);
taskAddButton.role = null;
taskAddButton.MyTask = null;
taskAddButton.SafePositionWorld = instance.SafePositionWorld;
@@ -336,14 +336,15 @@ internal static class TaskAdderPatches
taskAddButton.Button.OnClick = new Button.ButtonClickedEvent();
taskAddButton.Button.OnClick.AddListener((UnityEngine.Events.UnityAction)(() =>
{
- if (PlayerControl.LocalPlayer.HasModifier(modifier.ModifierId))
+ var id = modifier.GetId();
+ if (PlayerControl.LocalPlayer.HasModifier(id))
{
- PlayerControl.LocalPlayer.RemoveModifier(modifier.ModifierId);
+ PlayerControl.LocalPlayer.RemoveModifier(id);
taskAddButton.Overlay.enabled = false;
}
else
{
- PlayerControl.LocalPlayer.AddModifier(ModifierManager.GetModifierType(modifier.ModifierId)!);
+ PlayerControl.LocalPlayer.AddModifier(id);
taskAddButton.Overlay.enabled = true;
}
}));
diff --git a/MiraAPI/Patches/PlayerControlPatches.cs b/MiraAPI/Patches/PlayerControlPatches.cs
index fbabe1a..31fdbb8 100644
--- a/MiraAPI/Patches/PlayerControlPatches.cs
+++ b/MiraAPI/Patches/PlayerControlPatches.cs
@@ -126,6 +126,6 @@ public static class PlayerControlPatches
[HarmonyPatch(nameof(PlayerControl.OnDestroy))]
public static void PlayerControlOnDestroyPrefix(PlayerControl __instance)
{
- Utilities.ModifierExtensions.ModifierComponents.Remove(__instance);
+ ModifierExtensions.ModifierComponents.Remove(__instance);
}
}
diff --git a/MiraAPI/Patches/Roles/TaskPanelPatch.cs b/MiraAPI/Patches/Roles/TaskPanelPatch.cs
index 431d47b..a08445a 100644
--- a/MiraAPI/Patches/Roles/TaskPanelPatch.cs
+++ b/MiraAPI/Patches/Roles/TaskPanelPatch.cs
@@ -4,7 +4,7 @@ using UnityEngine;
namespace MiraAPI.Patches.Roles;
[HarmonyPatch(typeof(TaskPanelBehaviour))]
-public static class TaskPanelPatch
+internal static class TaskPanelPatch
{
///
/// This patch is to override the automatic updating of the y position on the tab (which is in base game)
diff --git a/MiraAPI/Utilities/ModifierExtensions.cs b/MiraAPI/Utilities/ModifierExtensions.cs
deleted file mode 100644
index dadb62c..0000000
--- a/MiraAPI/Utilities/ModifierExtensions.cs
+++ /dev/null
@@ -1,252 +0,0 @@
-using System;
-using System.Collections.Generic;
-using MiraAPI.Modifiers;
-using MiraAPI.Networking;
-using Reactor.Networking.Attributes;
-using Reactor.Utilities;
-
-namespace MiraAPI.Utilities;
-
-///
-/// Extensions for modifiers.
-///
-public static class ModifierExtensions
-{
- ///
- /// Gets the dictionary to cache ModifierComponents.
- ///
- public static Dictionary ModifierComponents { get; } = [];
-
- ///
- /// Remote Procedure Call to add a modifier to a player.
- ///
- /// The player to add the modifier to.
- /// The modifier ID.
- [MethodRpc((uint)MiraRpc.AddModifier)]
- public static void RpcAddModifier(this PlayerControl target, uint modifierId)
- {
- var type = ModifierManager.GetModifierType(modifierId);
- if (type == null)
- {
- Logger.Error($"Cannot add modifier with id {modifierId} because it is not registered.");
- return;
- }
-
- target.AddModifier(type);
- }
-
- ///
- /// Remote Procedure Call to add a modifier to a player.
- ///
- /// The player to add the modifier to.
- /// The modifier Type.
- public static void RpcAddModifier(this PlayerControl player) where T : BaseModifier
- {
- var id = ModifierManager.GetModifierId(typeof(T));
- if (id == null)
- {
- Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
- return;
- }
-
- player.RpcAddModifier(id.Value);
- }
-
- ///
- /// Remote Procedure Call to remove a modifier from a player.
- ///
- /// The player to remove the modifier from.
- /// The ID of the modifier.
- [MethodRpc((uint)MiraRpc.RemoveModifier)]
- public static void RpcRemoveModifier(this PlayerControl target, uint modifierId)
- {
- target.RemoveModifier(modifierId);
- }
-
- ///
- /// Remote Procedure Call to remove a modifier from a player.
- ///
- /// The player to remove the modifier from.
- /// The Type of the Modifier.
- public static void RpcRemoveModifier(this PlayerControl player) where T : BaseModifier
- {
- var id = ModifierManager.GetModifierId(typeof(T));
- if (id == null)
- {
- Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
- return;
- }
-
- player.RpcRemoveModifier(id.Value);
- }
-
- ///
- /// Gets the ModifierComponent for a player.
- ///
- /// The PlayerControl object.
- /// A ModifierComponent if there is one, null otherwise.
- public static ModifierComponent? GetModifierComponent(this PlayerControl player)
- {
- if (ModifierComponents.TryGetValue(player, out var component))
- {
- return component;
- }
-
- component = player.GetComponent();
- if (!component)
- {
- return null;
- }
-
- ModifierComponents[player] = component;
- return component;
- }
-
- ///
- /// Gets the ModifierComponent for a player.
- ///
- /// The PlayerControl object.
- /// The ModifierComponent if it is found.
- /// A ModifierComponent if there is one, null otherwise.
- public static bool TryGetModifierComponent(this PlayerControl player, out ModifierComponent? component)
- {
- if (ModifierComponents.TryGetValue(player, out component))
- {
- return component;
- }
-
- component = player.GetComponent();
- return component;
- }
-
- ///
- /// Gets a collection of modifiers by their type, or null if the player doesn't have one.
- ///
- /// The PlayerControl object.
- /// The Type of the Modifier.
- /// The Modifier if it is found, null otherwise.
- public static IEnumerable GetModifiersByType(this PlayerControl player) where T : BaseModifier
- {
- return player.GetModifierComponent()!.GetModifiersByType();
- }
-
- ///
- /// Gets a modifier by its type, or null if the player doesn't have it.
- ///
- /// The PlayerControl object.
- /// The Type of the Modifier.
- /// The Modifier if it is found, null otherwise.
- public static T? GetModifier(this PlayerControl player) where T : BaseModifier
- {
- return player.GetModifierComponent()!.GetModifier();
- }
-
- ///
- /// Tries to get a modifier by its type.
- ///
- /// The PlayerControl object.
- /// The modifier or null.
- /// The Type of the Modifier.
- /// True if the modifier was found, false otherwise.
- public static bool TryGetModifier(this PlayerControl player, out T? modifier) where T : BaseModifier
- {
- return player.GetModifierComponent()!.TryGetModifier(out modifier);
- }
-
- ///
- /// Removes a modifier from the player.
- ///
- /// The PlayerControl object.
- /// The modifier type.
- public static void RemoveModifier(this PlayerControl player, Type type)
- {
- player.GetModifierComponent()!.RemoveModifier(type);
- }
-
- ///
- /// Removes a modifier from the player.
- ///
- /// The PlayerControl object.
- /// The modifier type.
- public static void RemoveModifier(this PlayerControl player) where T : BaseModifier
- {
- player.GetModifierComponent()!.RemoveModifier();
- }
-
- ///
- /// Removes a modifier from the player.
- ///
- /// The PlayerControl object.
- /// The modifier ID.
- public static void RemoveModifier(this PlayerControl player, uint modifierId)
- {
- player.GetModifierComponent()!.RemoveModifier(modifierId);
- }
-
- ///
- /// Removes a modifier from the player.
- ///
- /// The PlayerControl object.
- /// The modifier object.
- public static void RemoveModifier(this PlayerControl player, BaseModifier modifier)
- {
- player.GetModifierComponent()!.RemoveModifier(modifier);
- }
-
- ///
- /// Adds a modifier to the player.
- ///
- /// The PlayerControl object.
- /// The modifier to add.
- /// The modifier that was added.
- public static BaseModifier? AddModifier(this PlayerControl player, BaseModifier modifier)
- {
- return player.GetModifierComponent()!.AddModifier(modifier);
- }
-
- ///
- /// Adds a modifier to the player.
- ///
- /// The PlayerControl object.
- /// The modifier type.
- /// The modifier that was added.
- public static BaseModifier? AddModifier(this PlayerControl player, Type type)
- {
- return player.GetModifierComponent()!.AddModifier(type);
- }
-
- ///
- /// Adds a modifier to the player.
- ///
- /// The PlayerControl object.
- /// The Type of the modifier.
- /// The new modifier.
- public static T? AddModifier(this PlayerControl player) where T : BaseModifier
- {
- return player.GetModifierComponent()!.AddModifier();
- }
-
- ///
- /// Checks if a player has an active or queued modifier by its ID.
- ///
- /// The PlayerControl object.
- /// The Modifier ID.
- /// The predicate to check the modifier.
- /// True if the Modifier is present, false otherwise.
- public static bool HasModifier(this PlayerControl player, uint id, Func? predicate=null)
- {
- return player.GetModifierComponent()!.HasModifier(id, predicate);
- }
-
- ///
- /// Checks if a player has an active or queued modifier by its type.
- ///
- /// The PlayerControl object.
- /// The predicate to check the modifier.
- /// The Type of the Modifier.
- /// True if the Modifier is present, false otherwise.
- public static bool HasModifier(this PlayerControl player, Func? predicate=null) where T : BaseModifier
- {
- return player.GetModifierComponent()!.HasModifier(predicate);
- }
-}
From 9ae9094a85e2443e98725e8cff0603b2f114f88a Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 24 Feb 2025 21:52:06 -0500
Subject: [PATCH 06/14] oops fix that
---
MiraAPI/Patches/VentPatches.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/MiraAPI/Patches/VentPatches.cs b/MiraAPI/Patches/VentPatches.cs
index 621abbc..8aa174b 100644
--- a/MiraAPI/Patches/VentPatches.cs
+++ b/MiraAPI/Patches/VentPatches.cs
@@ -1,8 +1,8 @@
using HarmonyLib;
using MiraAPI.Events;
using MiraAPI.Events.Vanilla.Usables;
+using MiraAPI.Modifiers;
using MiraAPI.Roles;
-using MiraAPI.Utilities;
using UnityEngine;
namespace MiraAPI.Patches;
From 4a8fb38380402e2745c080103bed37155de1aa15 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Tue, 25 Feb 2025 17:17:40 -0500
Subject: [PATCH 07/14] improvements to timed modifier
---
MiraAPI/Modifiers/Types/TimedModifier.cs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/MiraAPI/Modifiers/Types/TimedModifier.cs b/MiraAPI/Modifiers/Types/TimedModifier.cs
index 038fa6d..ebb0457 100644
--- a/MiraAPI/Modifiers/Types/TimedModifier.cs
+++ b/MiraAPI/Modifiers/Types/TimedModifier.cs
@@ -17,7 +17,7 @@ public abstract class TimedModifier : BaseModifier
///
/// Gets a value indicating whether the timer should start automatically when added.
///
- public virtual bool AutoStart => false;
+ public virtual bool AutoStart => true;
///
/// Gets a value indicating whether the modifier should be removed when the timer completes.
@@ -27,7 +27,9 @@ public abstract class TimedModifier : BaseModifier
///
/// Called when the timer completes.
///
- public abstract void OnTimerComplete();
+ public virtual void OnTimerComplete()
+ {
+ }
///
/// Gets or sets a value indicating whether the timer is active.
From caa27642db35486f326ac6e81a8f2e4ab539faed Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Tue, 25 Feb 2025 17:22:00 -0500
Subject: [PATCH 08/14] further modifier improvements (massive changes)
---
MiraAPI.Example/Buttons/TestButton.cs | 6 +
.../Events/Vanilla/Usables/PlayerUseEvent.cs | 2 +-
MiraAPI/Modifiers/BaseModifier.cs | 13 +-
MiraAPI/Modifiers/ModifierComponent.cs | 155 +++++++++-----
MiraAPI/Modifiers/ModifierExtensions.cs | 191 ++++++++++++------
MiraAPI/Modifiers/ModifierManager.cs | 24 +--
.../{ => Modifiers}/AddModifierRpc.cs | 2 +-
.../{ => Modifiers}/SyncModifiersRpc.cs | 2 +-
.../Patches/Events/KillAnimationPatches.cs | 2 +-
MiraAPI/Patches/Events/UsePatches.cs | 2 +-
.../Patches/Freeplay/TaskAddButtonPatches.cs | 2 +-
MiraAPI/Patches/Freeplay/TaskAdderPatches.cs | 8 +-
.../Patches/Modifiers/EndGameDidWinPatch.cs | 2 +-
MiraAPI/Patches/VentPatches.cs | 4 +-
14 files changed, 276 insertions(+), 139 deletions(-)
rename MiraAPI/Networking/{ => Modifiers}/AddModifierRpc.cs (97%)
rename MiraAPI/Networking/{ => Modifiers}/SyncModifiersRpc.cs (97%)
diff --git a/MiraAPI.Example/Buttons/TestButton.cs b/MiraAPI.Example/Buttons/TestButton.cs
index feb7992..776dc40 100644
--- a/MiraAPI.Example/Buttons/TestButton.cs
+++ b/MiraAPI.Example/Buttons/TestButton.cs
@@ -15,6 +15,12 @@ public class TestButton : CustomActionButton
protected override void OnClick()
{
+ if (PlayerControl.LocalPlayer.HasModifier())
+ {
+ PlayerControl.LocalPlayer.RpcRemoveModifier();
+ return;
+ }
+
var randomPlayer = PlayerControl.AllPlayerControls.ToArray().Random();
PlayerControl.LocalPlayer.RpcAddModifier("test", 1, randomPlayer);
}
diff --git a/MiraAPI/Events/Vanilla/Usables/PlayerUseEvent.cs b/MiraAPI/Events/Vanilla/Usables/PlayerUseEvent.cs
index 655a46c..5f05676 100644
--- a/MiraAPI/Events/Vanilla/Usables/PlayerUseEvent.cs
+++ b/MiraAPI/Events/Vanilla/Usables/PlayerUseEvent.cs
@@ -1,4 +1,4 @@
-namespace MiraAPI.Events.Vanilla;
+namespace MiraAPI.Events.Vanilla.Usables;
///
/// Event for using a from Vanilla Among Us. Will always be ran locally.
diff --git a/MiraAPI/Modifiers/BaseModifier.cs b/MiraAPI/Modifiers/BaseModifier.cs
index 8834454..21ce064 100644
--- a/MiraAPI/Modifiers/BaseModifier.cs
+++ b/MiraAPI/Modifiers/BaseModifier.cs
@@ -43,13 +43,14 @@ public abstract class BaseModifier
public bool Initialized { get; internal set; }
///
- /// Get the ID of the modifier.
+ /// Gets the unique ID of the modifier.
///
- /// The ID of the modifier.
- public uint GetId()
- {
- return ModifierManager.GetModifierId(GetType()) ?? throw new InvalidOperationException("Modifier is not registered.");
- }
+ public uint UniqueId { get; internal set; }
+
+ ///
+ /// Gets the type ID of the modifier.
+ ///
+ public uint TypeId => ModifierManager.GetModifierTypeId(GetType()) ?? throw new InvalidOperationException("Modifier is not registered.");
///
/// Gets the HUD information for this modifier. Defaults to the modifier name. Does nothing if is true.
diff --git a/MiraAPI/Modifiers/ModifierComponent.cs b/MiraAPI/Modifiers/ModifierComponent.cs
index 6cd3d5e..94ab3db 100644
--- a/MiraAPI/Modifiers/ModifierComponent.cs
+++ b/MiraAPI/Modifiers/ModifierComponent.cs
@@ -37,6 +37,14 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
private readonly List _toAdd = [];
+ private uint _nextUniqueId;
+
+ private uint GetNextUniqueId()
+ {
+ _nextUniqueId++;
+ return _nextUniqueId;
+ }
+
internal void ClearModifiers()
{
_toRemove.AddRange(Modifiers);
@@ -104,14 +112,12 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
return;
}
- var filteredModifiers = Modifiers.Where(mod => !mod.HideOnUi);
+ var filteredModifiers = Modifiers.Where(mod => !mod.HideOnUi).ToArray();
- var baseModifiers = filteredModifiers as BaseModifier[] ?? filteredModifiers.ToArray();
-
- if (baseModifiers.Length != 0 && !MeetingHud.Instance)
+ if (filteredModifiers.Length != 0 && !MeetingHud.Instance)
{
var stringBuild = new StringBuilder();
- foreach (var mod in baseModifiers)
+ foreach (var mod in filteredModifiers)
{
stringBuild.Append(CultureInfo.InvariantCulture, $"\n{mod.GetHudString()}");
}
@@ -128,11 +134,11 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
///
/// The predicate to check the modifier by.
/// The Type of the Modifier.
- /// The Modifier if it is found, null otherwise.
+ /// A collection of modifiers.
[HideFromIl2Cpp]
- public IEnumerable GetModifiersByType(Func? predicate=null) where T : BaseModifier
+ public IEnumerable GetModifiers(Func? predicate=null) where T : BaseModifier
{
- return ActiveModifiers.OfType().Where(x => predicate == null || predicate(x));
+ return Modifiers.OfType().Where(x => predicate == null || predicate(x));
}
///
@@ -140,26 +146,26 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
///
/// The modifier type.
/// The predicate to check the modifier by.
- /// The Modifier if it is found, null otherwise.
+ /// A collection of modifiers.
[HideFromIl2Cpp]
- public IEnumerable GetModifiersByType(Type type, Func? predicate=null)
+ public IEnumerable GetModifiers(Type type, Func? predicate=null)
{
- return ActiveModifiers.Where(x => x.GetType() == type && (predicate == null || predicate(x)));
+ return Modifiers.Where(x => x.GetType() == type && (predicate == null || predicate(x)));
}
///
- /// Gets a collection of modifiers by ID.
+ /// Gets a collection of modifiers by type ID.
///
- /// The Modifier ID.
+ /// The modifier's type ID.
/// The predicate to check the modifier by.
- /// The Modifier if it is found, null otherwise.
+ /// A collection of modifiers.
[HideFromIl2Cpp]
- public IEnumerable GetModifiersByType(uint id, Func? predicate=null)
+ public IEnumerable GetModifiers(uint id, Func? predicate=null)
{
var type = ModifierManager.GetModifierType(id) ?? throw new InvalidOperationException(
$"Cannot get modifier with id {id} because it is not registered.");
- return GetModifiersByType(type, predicate);
+ return GetModifiers(type, predicate);
}
///
@@ -191,23 +197,34 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
}
///
- /// Tries to get a modifier by its ID.
+ /// Tries to get a modifier by its type ID.
///
- /// The modifier ID.
+ /// The modifier type ID.
/// The modifier or null.
/// The predicate to check the modifier by.
/// True if the modifier was found, false otherwise.
[HideFromIl2Cpp]
- public bool TryGetModifier(uint id, out BaseModifier? modifier, Func? predicate = null)
+ public bool TryGetModifierByTypeId(uint id, out BaseModifier? modifier, Func? predicate = null)
{
- var type = ModifierManager.GetModifierType(id) ?? throw new InvalidOperationException(
- $"Cannot get modifier with id {id} because it is not registered.");
-
- return TryGetModifier(type, out modifier, predicate);
+ modifier = GetModifierByTypeId(id, predicate);
+ return modifier != null;
}
///
- /// Gets a modifier by its type, or null if the player doesn't have it.
+ /// Tries to get a modifier by its unique ID.
+ ///
+ /// The modifier unique ID.
+ /// The modifier or null.
+ /// True if the modifier was found, false otherwise.
+ [HideFromIl2Cpp]
+ public bool TryGetModifierByUniqueId(uint id, out BaseModifier? modifier)
+ {
+ modifier = GetModifierByUniqueId(id);
+ return modifier != null;
+ }
+
+ ///
+ /// Gets a modifier by its type.
///
/// The predicate to check the modifier by.
/// The Type of the Modifier.
@@ -215,11 +232,11 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
[HideFromIl2Cpp]
public T? GetModifier(Func? predicate = null) where T : BaseModifier
{
- return GetModifiersByType(predicate).FirstOrDefault();
+ return GetModifiers(predicate).FirstOrDefault();
}
///
- /// Gets a modifier by its type, or null if the player doesn't have it.
+ /// Gets a modifier by its type.
///
/// The modifier type.
/// The predicate to check the modifier by.
@@ -227,17 +244,17 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
[HideFromIl2Cpp]
public BaseModifier? GetModifier(Type type, Func? predicate = null)
{
- return GetModifiersByType(type).FirstOrDefault(predicate ?? (_ => true));
+ return GetModifiers(type).FirstOrDefault(predicate ?? (_ => true));
}
///
- /// Gets a modifier by its type, or null if the player doesn't have it.
+ /// Gets a modifier by its type ID.
///
/// The modifier ID.
/// The predicate to check the modifier by.
/// The Modifier if it is found, null otherwise.
[HideFromIl2Cpp]
- public BaseModifier? GetModifier(uint id, Func? predicate = null)
+ public BaseModifier? GetModifierByTypeId(uint id, Func? predicate = null)
{
var type = ModifierManager.GetModifierType(id) ?? throw new InvalidOperationException(
$"Cannot get modifier with id {id} because it is not registered.");
@@ -245,6 +262,17 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
return GetModifier(type, predicate);
}
+ ///
+ /// Gets a modifier by unique ID.
+ ///
+ /// The modifier's unique ID.
+ /// The modifier if it is found, or null.
+ [HideFromIl2Cpp]
+ public BaseModifier? GetModifierByUniqueId(uint id)
+ {
+ return Modifiers.Find(x => x.UniqueId == id);
+ }
+
///
/// Removes a modifier from the player.
///
@@ -280,19 +308,6 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
RemoveModifier(modifier);
}
- ///
- /// Removes a modifier from the player.
- ///
- /// The modifier ID.
- /// The predicate to check the modifier by.
- [HideFromIl2Cpp]
- public void RemoveModifier(uint modifierId, Func? predicate = null)
- {
- var type = ModifierManager.GetModifierType(modifierId) ?? throw new InvalidOperationException(
- $"Cannot remove modifier with id {modifierId} because it is not registered.");
- RemoveModifier(type, predicate);
- }
-
///
/// Removes a modifier from the player.
///
@@ -309,6 +324,36 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
_toRemove.Add(modifier);
}
+ ///
+ /// Removes a modifier from the player.
+ ///
+ /// The modifier's type ID.
+ /// The predicate to check the modifier by.
+ [HideFromIl2Cpp]
+ public void RemoveModifierByTypeId(uint typeId, Func? predicate = null)
+ {
+ var type = ModifierManager.GetModifierType(typeId) ?? throw new InvalidOperationException(
+ $"Cannot remove modifier with id {typeId} because it is not registered.");
+ RemoveModifier(type, predicate);
+ }
+
+ ///
+ /// Removes a modifier from the player.
+ ///
+ /// The modifier's unique ID.
+ [HideFromIl2Cpp]
+ public void RemoveModifierByUniqueId(uint uniqueId)
+ {
+ var modifier = GetModifierByUniqueId(uniqueId);
+ if (modifier == null)
+ {
+ Logger.Error($"Cannot remove modifier with unique id {uniqueId} because it is not active.");
+ return;
+ }
+
+ RemoveModifier(modifier);
+ }
+
///
/// Adds a modifier to the player.
///
@@ -329,8 +374,8 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
[HideFromIl2Cpp]
public BaseModifier? AddModifier(BaseModifier modifier)
{
- var id = modifier.GetId();
- if (modifier.Unique && Modifiers.Find(x => x.GetId() == id) != null)
+ var id = modifier.TypeId;
+ if (modifier.Unique && Modifiers.Find(x => x.TypeId == id) != null)
{
Logger.Error($"Player already has modifier with id {id}!");
return null;
@@ -345,6 +390,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
_toAdd.Add(modifier);
modifier.Player = _player;
modifier.ModifierComponent = this;
+ modifier.UniqueId = GetNextUniqueId();
return modifier;
}
@@ -398,7 +444,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
[HideFromIl2Cpp]
public bool HasModifier(Func? predicate=null) where T : BaseModifier
{
- return ActiveModifiers.Exists(x => x is T modifier && (predicate == null || predicate(modifier)));
+ return Modifiers.Exists(x => x is T modifier && (predicate == null || predicate(modifier)));
}
///
@@ -410,21 +456,32 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
[HideFromIl2Cpp]
public bool HasModifier(Type type, Func? predicate=null)
{
- return ActiveModifiers.Exists(x => x.GetType() == type && (predicate == null || predicate(x)));
+ return Modifiers.Exists(x => x.GetType() == type && (predicate == null || predicate(x)));
}
///
- /// Checks if a player has an active modifier by its ID.
+ /// Checks if a player has an active modifier by its type ID
///
- /// The Modifier ID.
+ /// The Modifier type ID.
/// The predicate to check the modifier.
/// True if the Modifier is present, false otherwise.
[HideFromIl2Cpp]
- public bool HasModifier(uint id, Func? predicate=null)
+ public bool HasModifierByTypeId(uint id, Func? predicate=null)
{
var type = ModifierManager.GetModifierType(id) ?? throw new InvalidOperationException(
$"Cannot get modifier with id {id} because it is not registered.");
return HasModifier(type, predicate);
}
+
+ ///
+ /// Checks if a player has an active modifier by its unique ID
+ ///
+ /// The Modifier type ID.
+ /// True if the Modifier is present, false otherwise.
+ [HideFromIl2Cpp]
+ public bool HasModifierByUniqueId(uint id)
+ {
+ return Modifiers.Exists(x => x.UniqueId == id);
+ }
}
diff --git a/MiraAPI/Modifiers/ModifierExtensions.cs b/MiraAPI/Modifiers/ModifierExtensions.cs
index 226b16b..5b42c6b 100644
--- a/MiraAPI/Modifiers/ModifierExtensions.cs
+++ b/MiraAPI/Modifiers/ModifierExtensions.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using MiraAPI.Networking;
+using MiraAPI.Networking.Modifiers;
using Reactor.Networking.Attributes;
using Reactor.Networking.Rpc;
using Reactor.Utilities;
@@ -21,14 +22,14 @@ public static class ModifierExtensions
/// Remote Procedure Call to add a modifier to a player.
///
/// The player to add the modifier to.
- /// The modifier ID.
+ /// The modifier type ID.
/// The arguments to initialize the modifier constructor with.
- public static void RpcAddModifier(this PlayerControl target, uint modifierId, params object[] args)
+ public static void RpcAddModifier(this PlayerControl target, uint typeId, params object[] args)
{
- _ = ModifierManager.GetModifierType(modifierId) ?? throw new InvalidOperationException(
- $"Modifier with ID {modifierId} is not registered.");
+ _ = ModifierManager.GetModifierType(typeId) ?? throw new InvalidOperationException(
+ $"Modifier with ID {typeId} is not registered.");
- Rpc.Instance.Send(target, new ModifierData(modifierId, args));
+ Rpc.Instance.Send(target, new ModifierData(typeId, args));
}
///
@@ -39,7 +40,7 @@ public static class ModifierExtensions
/// The arguments to initialize the modifier constructor with.
public static void RpcAddModifier(this PlayerControl player, Type type, params object[] args)
{
- var id = ModifierManager.GetModifierId(type) ?? throw new InvalidOperationException(
+ var id = ModifierManager.GetModifierTypeId(type) ?? throw new InvalidOperationException(
$"Modifier {type.Name} is not registered.");
player.RpcAddModifier(id, args);
@@ -60,28 +61,61 @@ public static class ModifierExtensions
/// Remote Procedure Call to remove a modifier from a player.
///
/// The player to remove the modifier from.
- /// The ID of the modifier.
+ /// The unique ID of the modifier.
[MethodRpc((uint)MiraRpc.RemoveModifier)]
- public static void RpcRemoveModifier(this PlayerControl target, uint modifierId)
+ public static void RpcRemoveModifierByUniqueId(this PlayerControl target, uint uniqueId)
{
- target.RemoveModifier(modifierId);
+ target.RemoveModifierByUniqueId(uniqueId);
+ }
+
+ ///
+ /// Remote Procedure Call to remove a modifier from a player by type ID.
+ ///
+ /// The player to remove the modifier from.
+ /// The type ID of the modifier.
+ /// Optional predicate to filter the modifiers.
+ public static void RpcRemoveModifierByTypeId(
+ this PlayerControl target,
+ uint typeId,
+ Func? predicate = null)
+ {
+ var modifier = target.GetModifierByTypeId(typeId, predicate);
+ if (modifier is null)
+ {
+ Logger.Error($"Player {target.PlayerId} does not have modifier with type ID {typeId}.");
+ return;
+ }
+
+ target.RpcRemoveModifierByUniqueId(modifier.UniqueId);
}
///
/// Remote Procedure Call to remove a modifier from a player.
///
/// The player to remove the modifier from.
- /// The Type of the Modifier.
- public static void RpcRemoveModifier(this PlayerControl player) where T : BaseModifier
+ /// The type of the modifier.
+ /// Optional predicate to filter the modifiers.
+ public static void RpcRemoveModifier(
+ this PlayerControl player,
+ Type type,
+ Func? predicate = null)
{
- var id = ModifierManager.GetModifierId(typeof(T));
- if (id == null)
- {
- Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
- return;
- }
+ var id = ModifierManager.GetModifierTypeId(type) ?? throw new InvalidOperationException(
+ $"Modifier {type.Name} is not registered.");
- player.RpcRemoveModifier(id.Value);
+ player.RpcRemoveModifierByTypeId(id, predicate);
+ }
+
+ ///
+ /// Remote Procedure Call to remove a modifier from a player.
+ ///
+ /// The player to remove the modifier from.
+ /// Optional predicate to filter the modifiers.
+ /// The Type of the Modifier.
+ public static void RpcRemoveModifier(this PlayerControl player, Func? predicate = null)
+ where T : BaseModifier
+ {
+ player.RpcRemoveModifier(typeof(T), predicate);
}
///
@@ -89,7 +123,7 @@ public static class ModifierExtensions
///
/// The PlayerControl object.
/// A ModifierComponent if there is one, null otherwise.
- public static ModifierComponent? GetModifierComponent(this PlayerControl player)
+ public static ModifierComponent GetModifierComponent(this PlayerControl player)
{
if (ModifierComponents.TryGetValue(player, out var component))
{
@@ -97,9 +131,9 @@ public static class ModifierExtensions
}
component = player.GetComponent();
- if (component == null)
+ if (!component)
{
- return null;
+ throw new InvalidOperationException("ModifierComponent is not attached to the player.");
}
ModifierComponents[player] = component;
@@ -115,7 +149,7 @@ public static class ModifierExtensions
/// True if the player has the modifier, false otherwise.
public static bool HasModifier(this PlayerControl player, Func? predicate = null) where T : BaseModifier
{
- return player.GetModifierComponent()!.HasModifier(predicate);
+ return player.GetModifierComponent().HasModifier(predicate);
}
///
@@ -127,19 +161,33 @@ public static class ModifierExtensions
/// True if the player has the modifier, false otherwise.
public static bool HasModifier(this PlayerControl player, Type type, Func? predicate = null)
{
- return player.GetModifierComponent()!.HasModifier(type, predicate);
+ return player.GetModifierComponent().HasModifier(type, predicate);
}
///
- /// Checks if the player has a specific modifier by ID.
+ /// Checks if the player has a specific modifier by type ID.
///
/// The PlayerControl instance.
- /// The ID of the modifier.
+ /// The type ID of the modifier.
/// Optional predicate to filter the modifiers.
/// True if the player has the modifier, false otherwise.
- public static bool HasModifier(this PlayerControl player, uint id, Func? predicate = null)
+ public static bool HasModifierByTypeId(
+ this PlayerControl player,
+ uint id,
+ Func? predicate = null)
{
- return player.GetModifierComponent()!.HasModifier(id, predicate);
+ return player.GetModifierComponent().HasModifierByTypeId(id, predicate);
+ }
+
+ ///
+ /// Checks if the player has a specific modifier by unique ID.
+ ///
+ /// The PlayerControl instance.
+ /// The unique ID of the modifier.
+ /// True if the player has the modifier, false otherwise.
+ public static bool HasModifierByUniqueId(this PlayerControl player, uint id)
+ {
+ return player.GetModifierComponent().HasModifierByUniqueId(id);
}
///
@@ -151,7 +199,7 @@ public static class ModifierExtensions
/// The modifier if found, null otherwise.
public static T? GetModifier(this PlayerControl player, Func? predicate = null) where T : BaseModifier
{
- return player.GetModifierComponent()!.GetModifier(predicate);
+ return player.GetModifierComponent().GetModifier(predicate);
}
///
@@ -166,7 +214,22 @@ public static class ModifierExtensions
Type type,
Func? predicate = null)
{
- return player.GetModifierComponent()!.GetModifier(type, predicate);
+ return player.GetModifierComponent().GetModifier(type, predicate);
+ }
+
+ ///
+ /// Gets a specific modifier from the player by type ID.
+ ///
+ /// The PlayerControl instance.
+ /// The type ID of the modifier.
+ /// Optional predicate to filter the modifiers.
+ /// The modifier if found, null otherwise.
+ public static BaseModifier? GetModifierByTypeId(
+ this PlayerControl player,
+ uint id,
+ Func? predicate = null)
+ {
+ return player.GetModifierComponent().GetModifierByTypeId(id, predicate);
}
///
@@ -174,14 +237,12 @@ public static class ModifierExtensions
///
/// The PlayerControl instance.
/// The ID of the modifier.
- /// Optional predicate to filter the modifiers.
/// The modifier if found, null otherwise.
- public static BaseModifier? GetModifier(
+ public static BaseModifier? GetModifierByUniqueId(
this PlayerControl player,
- uint id,
- Func? predicate = null)
+ uint id)
{
- return player.GetModifierComponent()!.GetModifier(id, predicate);
+ return player.GetModifierComponent().GetModifierByUniqueId(id);
}
///
@@ -191,10 +252,10 @@ public static class ModifierExtensions
/// The PlayerControl instance.
/// Optional predicate to filter the modifiers.
/// An enumerable of modifiers.
- public static IEnumerable GetModifiersByType(this PlayerControl player, Func? predicate = null)
+ public static IEnumerable GetModifiers(this PlayerControl player, Func? predicate = null)
where T : BaseModifier
{
- return player.GetModifierComponent()!.GetModifiersByType(predicate);
+ return player.GetModifierComponent().GetModifiers(predicate);
}
///
@@ -204,27 +265,37 @@ public static class ModifierExtensions
/// The type of the modifiers.
/// Optional predicate to filter the modifiers.
/// An enumerable of modifiers.
- public static IEnumerable GetModifiersByType(
+ public static IEnumerable GetModifiers(
this PlayerControl player,
Type type,
Func? predicate = null)
{
- return player.GetModifierComponent()!.GetModifiersByType(type, predicate);
+ return player.GetModifierComponent().GetModifiers(type, predicate);
}
///
- /// Gets all modifiers of a specific type from the player by ID.
+ /// Gets all modifiers of a specific type from the player by type ID.
///
/// The PlayerControl instance.
- /// The ID of the modifiers.
+ /// The type ID of the modifiers.
/// Optional predicate to filter the modifiers.
/// An enumerable of modifiers.
- public static IEnumerable GetModifiersByType(
+ public static IEnumerable GetModifiers(
this PlayerControl player,
uint id,
Func? predicate = null)
{
- return player.GetModifierComponent()!.GetModifiersByType(id, predicate);
+ return player.GetModifierComponent().GetModifiers(id, predicate);
+ }
+
+ ///
+ /// Removes a specific modifier from the player.
+ ///
+ /// The PlayerControl instance.
+ /// The modifier to remove.
+ public static void RemoveModifier(this PlayerControl player, BaseModifier modifier)
+ {
+ player.GetModifierComponent().RemoveModifier(modifier);
}
///
@@ -236,7 +307,7 @@ public static class ModifierExtensions
public static void RemoveModifier(this PlayerControl player, Func? predicate = null)
where T : BaseModifier
{
- player.GetModifierComponent()!.RemoveModifier(predicate);
+ player.GetModifierComponent().RemoveModifier(predicate);
}
///
@@ -247,31 +318,33 @@ public static class ModifierExtensions
/// Optional predicate to filter the modifiers.
public static void RemoveModifier(this PlayerControl player, Type type, Func? predicate = null)
{
- player.GetModifierComponent()!.RemoveModifier(type, predicate);
+ player.GetModifierComponent().RemoveModifier(type, predicate);
}
///
/// Removes a specific modifier from the player by ID.
///
/// The PlayerControl instance.
- /// The ID of the modifier.
+ /// The ID of the modifier.
/// Optional predicate to filter the modifiers.
- public static void RemoveModifier(
+ public static void RemoveModifierByTypeId(
this PlayerControl player,
- uint modifierId,
+ uint typeId,
Func? predicate = null)
{
- player.GetModifierComponent()!.RemoveModifier(modifierId, predicate);
+ player.GetModifierComponent().RemoveModifierByTypeId(typeId, predicate);
}
///
- /// Removes a specific modifier from the player.
+ /// Removes a specific modifier from the player by ID.
///
/// The PlayerControl instance.
- /// The modifier to remove.
- public static void RemoveModifier(this PlayerControl player, BaseModifier modifier)
+ /// The ID of the modifier.
+ public static void RemoveModifierByUniqueId(
+ this PlayerControl player,
+ uint uniqueId)
{
- player.GetModifierComponent()!.RemoveModifier(modifier);
+ player.GetModifierComponent().RemoveModifierByUniqueId(uniqueId);
}
///
@@ -283,7 +356,7 @@ public static class ModifierExtensions
/// The added modifier.
public static T? AddModifier(this PlayerControl player, params object[] args) where T : BaseModifier
{
- return player.GetModifierComponent()!.AddModifier(args);
+ return player.GetModifierComponent().AddModifier(args);
}
///
@@ -294,7 +367,7 @@ public static class ModifierExtensions
/// The added modifier.
public static BaseModifier? AddModifier(this PlayerControl player, BaseModifier modifier)
{
- return player.GetModifierComponent()!.AddModifier(modifier);
+ return player.GetModifierComponent().AddModifier(modifier);
}
///
@@ -306,18 +379,18 @@ public static class ModifierExtensions
/// The added modifier.
public static BaseModifier? AddModifier(this PlayerControl player, Type type, params object[] args)
{
- return player.GetModifierComponent()!.AddModifier(type, args);
+ return player.GetModifierComponent().AddModifier(type, args);
}
///
- /// Adds a specific modifier to the player by ID.
+ /// Adds a specific modifier to the player by type ID.
///
/// The PlayerControl instance.
- /// The ID of the modifier.
+ /// The type ID of the modifier.
/// The arguments to initialize the modifier constructor with.
/// The added modifier.
- public static BaseModifier? AddModifier(this PlayerControl player, uint id, params object[] args)
+ public static BaseModifier? AddModifier(this PlayerControl player, uint typeId, params object[] args)
{
- return player.GetModifierComponent()!.AddModifier(id, args);
+ return player.GetModifierComponent().AddModifier(typeId, args);
}
}
diff --git a/MiraAPI/Modifiers/ModifierManager.cs b/MiraAPI/Modifiers/ModifierManager.cs
index 65341a0..209423e 100644
--- a/MiraAPI/Modifiers/ModifierManager.cs
+++ b/MiraAPI/Modifiers/ModifierManager.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Runtime.Serialization;
using MiraAPI.Modifiers.Types;
using MiraAPI.Networking;
+using MiraAPI.Networking.Modifiers;
using MiraAPI.PluginLoading;
using MiraAPI.Roles;
using MiraAPI.Utilities;
@@ -23,16 +24,16 @@ public static class ModifierManager
private static readonly Dictionary TypeToIdModifierMap = [];
private static readonly Dictionary> PrioritiesToIdsMap = [];
- private static uint _nextId;
+ private static uint _nextTypeId;
- private static uint GetNextId()
+ private static uint GetNextTypeId()
{
- _nextId++;
- return _nextId;
+ _nextTypeId++;
+ return _nextTypeId;
}
///
- /// Gets the modifier type from the id.
+ /// Gets the modifier type from the type id.
///
/// The ID.
/// The Type of the modifier.
@@ -46,7 +47,7 @@ public static class ModifierManager
///
/// The Type.
/// The ID of the modifier.
- public static uint? GetModifierId(Type type)
+ public static uint? GetModifierTypeId(Type type)
{
if (!TypeToIdModifierMap.TryGetValue(type, out var id))
{
@@ -63,8 +64,8 @@ public static class ModifierManager
return false;
}
- IdToTypeModifierMap.Add(GetNextId(), modifierType);
- TypeToIdModifierMap.Add(modifierType, _nextId);
+ IdToTypeModifierMap.Add(GetNextTypeId(), modifierType);
+ TypeToIdModifierMap.Add(modifierType, _nextTypeId);
var bm = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType); // this probably isn't a great idea
info.Modifiers.Add(bm);
@@ -81,7 +82,7 @@ public static class ModifierManager
PrioritiesToIdsMap[priority] = list = [];
}
- list.Add(_nextId);
+ list.Add(_nextTypeId);
return true;
}
@@ -143,7 +144,7 @@ public static class ModifierManager
var mod = Activator.CreateInstance(IdToTypeModifierMap[id]) as GameModifier;
var plr = plrs.Where(x => IsGameModifierValid(x, mod!, id)).Random();
- if (plr == null)
+ if (!plr || plr == null)
{
Logger.Warning($"Somehow valid players for modifier {mod!.ModifierName} disappeared");
}
@@ -158,8 +159,7 @@ public static class ModifierManager
private static bool IsGameModifierValid(PlayerControl player, GameModifier modifier, uint modifierId)
{
return (player.Data.Role is not ICustomRole role || role.IsModifierApplicable(modifier)) &&
- modifier.IsModifierValidOn(player.Data.Role) &&
- !player.HasModifier(modifierId);
+ modifier.IsModifierValidOn(player.Data.Role) && !player.HasModifierByTypeId(modifierId);
}
internal static void SyncAllModifiers(int targetId = -1)
diff --git a/MiraAPI/Networking/AddModifierRpc.cs b/MiraAPI/Networking/Modifiers/AddModifierRpc.cs
similarity index 97%
rename from MiraAPI/Networking/AddModifierRpc.cs
rename to MiraAPI/Networking/Modifiers/AddModifierRpc.cs
index fdc37a9..5727ba5 100644
--- a/MiraAPI/Networking/AddModifierRpc.cs
+++ b/MiraAPI/Networking/Modifiers/AddModifierRpc.cs
@@ -5,7 +5,7 @@ using Reactor.Networking.Attributes;
using Reactor.Networking.Rpc;
using Reactor.Networking.Serialization;
-namespace MiraAPI.Networking;
+namespace MiraAPI.Networking.Modifiers;
///
/// Remote procedure call for adding a modifier.
diff --git a/MiraAPI/Networking/SyncModifiersRpc.cs b/MiraAPI/Networking/Modifiers/SyncModifiersRpc.cs
similarity index 97%
rename from MiraAPI/Networking/SyncModifiersRpc.cs
rename to MiraAPI/Networking/Modifiers/SyncModifiersRpc.cs
index 288e2c1..0571198 100644
--- a/MiraAPI/Networking/SyncModifiersRpc.cs
+++ b/MiraAPI/Networking/Modifiers/SyncModifiersRpc.cs
@@ -3,7 +3,7 @@ using MiraAPI.Modifiers;
using Reactor.Networking.Attributes;
using Reactor.Networking.Rpc;
-namespace MiraAPI.Networking;
+namespace MiraAPI.Networking.Modifiers;
[RegisterCustomRpc((uint)MiraRpc.SyncModifiers)]
internal sealed class SyncModifiersRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc(plugin, id)
diff --git a/MiraAPI/Patches/Events/KillAnimationPatches.cs b/MiraAPI/Patches/Events/KillAnimationPatches.cs
index 13b4cff..3572ff8 100644
--- a/MiraAPI/Patches/Events/KillAnimationPatches.cs
+++ b/MiraAPI/Patches/Events/KillAnimationPatches.cs
@@ -2,7 +2,7 @@
using MiraAPI.Events;
using MiraAPI.Events.Vanilla.Gameplay;
-namespace MiraAPI.Patches;
+namespace MiraAPI.Patches.Events;
///
/// General patches for the KillAnimation class.
diff --git a/MiraAPI/Patches/Events/UsePatches.cs b/MiraAPI/Patches/Events/UsePatches.cs
index beb1f69..0571cd6 100644
--- a/MiraAPI/Patches/Events/UsePatches.cs
+++ b/MiraAPI/Patches/Events/UsePatches.cs
@@ -1,8 +1,8 @@
using HarmonyLib;
using MiraAPI.Events;
-using MiraAPI.Events.Vanilla;
using System.Collections.Generic;
using System.Reflection;
+using MiraAPI.Events.Vanilla.Usables;
namespace MiraAPI.Patches.Events;
diff --git a/MiraAPI/Patches/Freeplay/TaskAddButtonPatches.cs b/MiraAPI/Patches/Freeplay/TaskAddButtonPatches.cs
index 184bafb..0ee6da4 100644
--- a/MiraAPI/Patches/Freeplay/TaskAddButtonPatches.cs
+++ b/MiraAPI/Patches/Freeplay/TaskAddButtonPatches.cs
@@ -16,7 +16,7 @@ internal static class TaskAddButtonPatches
if (uint.TryParse(__instance.name, out var result))
{
__instance.Overlay.sprite = __instance.CheckImage;
- __instance.Overlay.enabled = PlayerControl.LocalPlayer.HasModifier(result);
+ __instance.Overlay.enabled = PlayerControl.LocalPlayer.HasModifierByTypeId(result);
return false;
}
diff --git a/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs b/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs
index b634c91..0c35670 100644
--- a/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs
+++ b/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs
@@ -326,7 +326,7 @@ internal static class TaskAdderPatches
}
var taskAddButton = Object.Instantiate(instance.RoleButton);
- taskAddButton.name = modifier.GetId().ToString(NumberFormatInfo.InvariantInfo);
+ taskAddButton.name = modifier.TypeId.ToString(NumberFormatInfo.InvariantInfo);
taskAddButton.role = null;
taskAddButton.MyTask = null;
taskAddButton.SafePositionWorld = instance.SafePositionWorld;
@@ -336,10 +336,10 @@ internal static class TaskAdderPatches
taskAddButton.Button.OnClick = new Button.ButtonClickedEvent();
taskAddButton.Button.OnClick.AddListener((UnityEngine.Events.UnityAction)(() =>
{
- var id = modifier.GetId();
- if (PlayerControl.LocalPlayer.HasModifier(id))
+ var id = modifier.TypeId;
+ if (PlayerControl.LocalPlayer.HasModifierByTypeId(id))
{
- PlayerControl.LocalPlayer.RemoveModifier(id);
+ PlayerControl.LocalPlayer.RemoveModifierByTypeId(id);
taskAddButton.Overlay.enabled = false;
}
else
diff --git a/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs b/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs
index 17356db..a86383d 100644
--- a/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs
+++ b/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs
@@ -24,7 +24,7 @@ public static class EndGameDidWinPatch
var didWin = networkedPlayerInfo.Role.DidWin(gameOverReason);
- var modifierWin = networkedPlayerInfo.Object?.GetModifierComponent()?.ActiveModifiers.OfType()
+ var modifierWin = networkedPlayerInfo.Object?.GetModifierComponent().GetModifiers()
.FirstOrDefault(x => x.DidWin(gameOverReason) != null)?.DidWin(gameOverReason);
if (modifierWin != null)
{
diff --git a/MiraAPI/Patches/VentPatches.cs b/MiraAPI/Patches/VentPatches.cs
index 8aa174b..2f8991d 100644
--- a/MiraAPI/Patches/VentPatches.cs
+++ b/MiraAPI/Patches/VentPatches.cs
@@ -35,8 +35,8 @@ public static class VentPatches
var canVent = role is ICustomRole customRole ? customRole.Configuration.CanUseVent : role.CanVent;
couldUse = canVent;
- var modifiers = @object.GetModifierComponent()?.ActiveModifiers;
- if (modifiers is { Count: > 0 })
+ var modifiers = @object.GetModifierComponent().ActiveModifiers;
+ if (modifiers.Count > 0)
{
switch (canVent)
{
From 7e4a71739c0ba89fdf2312e89c668d4751052619 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Tue, 25 Feb 2025 21:57:38 -0500
Subject: [PATCH 09/14] better modifier unique IDs
---
MiraAPI/Modifiers/BaseModifier.cs | 2 +-
MiraAPI/Modifiers/ModifierComponent.cs | 53 ++++++------
MiraAPI/Modifiers/ModifierData.cs | 19 -----
MiraAPI/Modifiers/ModifierExtensions.cs | 80 +++++++++----------
MiraAPI/Modifiers/ModifierManager.cs | 69 +---------------
MiraAPI/Networking/GuidConverter.cs | 32 ++++++++
.../Networking/Modifiers/AddModifierRpc.cs | 23 +++++-
MiraAPI/Networking/Modifiers/ModifierData.cs | 11 +++
.../Networking/Modifiers/SyncModifiersRpc.cs | 52 ------------
MiraAPI/Patches/AmongUsClientSyncPatch.cs | 6 +-
.../Patches/Freeplay/TaskAddButtonPatches.cs | 2 +-
MiraAPI/Patches/Freeplay/TaskAdderPatches.cs | 4 +-
12 files changed, 134 insertions(+), 219 deletions(-)
delete mode 100644 MiraAPI/Modifiers/ModifierData.cs
create mode 100644 MiraAPI/Networking/GuidConverter.cs
create mode 100644 MiraAPI/Networking/Modifiers/ModifierData.cs
delete mode 100644 MiraAPI/Networking/Modifiers/SyncModifiersRpc.cs
diff --git a/MiraAPI/Modifiers/BaseModifier.cs b/MiraAPI/Modifiers/BaseModifier.cs
index 21ce064..52a2bb0 100644
--- a/MiraAPI/Modifiers/BaseModifier.cs
+++ b/MiraAPI/Modifiers/BaseModifier.cs
@@ -45,7 +45,7 @@ public abstract class BaseModifier
///
/// Gets the unique ID of the modifier.
///
- public uint UniqueId { get; internal set; }
+ public Guid UniqueId { get; internal set; } = Guid.Empty;
///
/// Gets the type ID of the modifier.
diff --git a/MiraAPI/Modifiers/ModifierComponent.cs b/MiraAPI/Modifiers/ModifierComponent.cs
index 94ab3db..57abd8c 100644
--- a/MiraAPI/Modifiers/ModifierComponent.cs
+++ b/MiraAPI/Modifiers/ModifierComponent.cs
@@ -37,14 +37,6 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
private readonly List _toAdd = [];
- private uint _nextUniqueId;
-
- private uint GetNextUniqueId()
- {
- _nextUniqueId++;
- return _nextUniqueId;
- }
-
internal void ClearModifiers()
{
_toRemove.AddRange(Modifiers);
@@ -204,22 +196,22 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
/// The predicate to check the modifier by.
/// True if the modifier was found, false otherwise.
[HideFromIl2Cpp]
- public bool TryGetModifierByTypeId(uint id, out BaseModifier? modifier, Func? predicate = null)
+ public bool TryGetModifier(uint id, out BaseModifier? modifier, Func? predicate = null)
{
- modifier = GetModifierByTypeId(id, predicate);
+ modifier = GetModifier(id, predicate);
return modifier != null;
}
///
/// Tries to get a modifier by its unique ID.
///
- /// The modifier unique ID.
+ /// The modifier unique ID.
/// The modifier or null.
/// True if the modifier was found, false otherwise.
[HideFromIl2Cpp]
- public bool TryGetModifierByUniqueId(uint id, out BaseModifier? modifier)
+ public bool TryGetModifier(Guid modifierGuid, out BaseModifier? modifier)
{
- modifier = GetModifierByUniqueId(id);
+ modifier = GetModifier(modifierGuid);
return modifier != null;
}
@@ -254,7 +246,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
/// The predicate to check the modifier by.
/// The Modifier if it is found, null otherwise.
[HideFromIl2Cpp]
- public BaseModifier? GetModifierByTypeId(uint id, Func? predicate = null)
+ public BaseModifier? GetModifier(uint id, Func? predicate = null)
{
var type = ModifierManager.GetModifierType(id) ?? throw new InvalidOperationException(
$"Cannot get modifier with id {id} because it is not registered.");
@@ -265,12 +257,12 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
///
/// Gets a modifier by unique ID.
///
- /// The modifier's unique ID.
+ /// The modifier's unique ID.
/// The modifier if it is found, or null.
[HideFromIl2Cpp]
- public BaseModifier? GetModifierByUniqueId(uint id)
+ public BaseModifier? GetModifier(Guid modifierGuid)
{
- return Modifiers.Find(x => x.UniqueId == id);
+ return Modifiers.Find(x => x.UniqueId == modifierGuid);
}
///
@@ -330,7 +322,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
/// The modifier's type ID.
/// The predicate to check the modifier by.
[HideFromIl2Cpp]
- public void RemoveModifierByTypeId(uint typeId, Func? predicate = null)
+ public void RemoveModifier(uint typeId, Func? predicate = null)
{
var type = ModifierManager.GetModifierType(typeId) ?? throw new InvalidOperationException(
$"Cannot remove modifier with id {typeId} because it is not registered.");
@@ -342,9 +334,9 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
///
/// The modifier's unique ID.
[HideFromIl2Cpp]
- public void RemoveModifierByUniqueId(uint uniqueId)
+ public void RemoveModifier(Guid uniqueId)
{
- var modifier = GetModifierByUniqueId(uniqueId);
+ var modifier = GetModifier(uniqueId);
if (modifier == null)
{
Logger.Error($"Cannot remove modifier with unique id {uniqueId} because it is not active.");
@@ -390,7 +382,10 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
_toAdd.Add(modifier);
modifier.Player = _player;
modifier.ModifierComponent = this;
- modifier.UniqueId = GetNextUniqueId();
+ if (modifier.UniqueId == Guid.Empty)
+ {
+ modifier.UniqueId = Guid.NewGuid();
+ }
return modifier;
}
@@ -460,13 +455,13 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
}
///
- /// Checks if a player has an active modifier by its type ID
+ /// Checks if a player has an active modifier by its type ID.
///
- /// The Modifier type ID.
+ /// The modifier's type ID.
/// The predicate to check the modifier.
- /// True if the Modifier is present, false otherwise.
+ /// True if the modifier is present, false otherwise.
[HideFromIl2Cpp]
- public bool HasModifierByTypeId(uint id, Func? predicate=null)
+ public bool HasModifier(uint id, Func? predicate=null)
{
var type = ModifierManager.GetModifierType(id) ?? throw new InvalidOperationException(
$"Cannot get modifier with id {id} because it is not registered.");
@@ -475,12 +470,12 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
}
///
- /// Checks if a player has an active modifier by its unique ID
+ /// Checks if a player has an active modifier by its unique ID.
///
- /// The Modifier type ID.
- /// True if the Modifier is present, false otherwise.
+ /// The modifier's guid.
+ /// True if the modifier is present, false otherwise.
[HideFromIl2Cpp]
- public bool HasModifierByUniqueId(uint id)
+ public bool HasModifier(Guid id)
{
return Modifiers.Exists(x => x.UniqueId == id);
}
diff --git a/MiraAPI/Modifiers/ModifierData.cs b/MiraAPI/Modifiers/ModifierData.cs
deleted file mode 100644
index 7260834..0000000
--- a/MiraAPI/Modifiers/ModifierData.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace MiraAPI.Modifiers;
-
-///
-/// Modifier data for networking.
-///
-/// The ID of the modifier.
-/// Parameters for constructor.
-public readonly struct ModifierData(uint id, object[] args)
-{
- ///
- /// Gets the type of the modifier.
- ///
- public uint Id { get; } = id;
-
- ///
- /// Gets the parameters for the constructor.
- ///
- public object[] Args { get; } = args;
-}
diff --git a/MiraAPI/Modifiers/ModifierExtensions.cs b/MiraAPI/Modifiers/ModifierExtensions.cs
index 5b42c6b..5d05d69 100644
--- a/MiraAPI/Modifiers/ModifierExtensions.cs
+++ b/MiraAPI/Modifiers/ModifierExtensions.cs
@@ -29,7 +29,7 @@ public static class ModifierExtensions
_ = ModifierManager.GetModifierType(typeId) ?? throw new InvalidOperationException(
$"Modifier with ID {typeId} is not registered.");
- Rpc.Instance.Send(target, new ModifierData(typeId, args));
+ Rpc.Instance.Send(target, new ModifierData(typeId, Guid.NewGuid(), args));
}
///
@@ -63,9 +63,9 @@ public static class ModifierExtensions
/// The player to remove the modifier from.
/// The unique ID of the modifier.
[MethodRpc((uint)MiraRpc.RemoveModifier)]
- public static void RpcRemoveModifierByUniqueId(this PlayerControl target, uint uniqueId)
+ public static void RpcRemoveModifier(this PlayerControl target, Guid uniqueId)
{
- target.RemoveModifierByUniqueId(uniqueId);
+ target.RemoveModifier(uniqueId);
}
///
@@ -74,19 +74,19 @@ public static class ModifierExtensions
/// The player to remove the modifier from.
/// The type ID of the modifier.
/// Optional predicate to filter the modifiers.
- public static void RpcRemoveModifierByTypeId(
+ public static void RpcRemoveModifier(
this PlayerControl target,
uint typeId,
Func? predicate = null)
{
- var modifier = target.GetModifierByTypeId(typeId, predicate);
+ var modifier = target.GetModifier(typeId, predicate);
if (modifier is null)
{
Logger.Error($"Player {target.PlayerId} does not have modifier with type ID {typeId}.");
return;
}
- target.RpcRemoveModifierByUniqueId(modifier.UniqueId);
+ target.RpcRemoveModifier(modifier.UniqueId);
}
///
@@ -103,7 +103,7 @@ public static class ModifierExtensions
var id = ModifierManager.GetModifierTypeId(type) ?? throw new InvalidOperationException(
$"Modifier {type.Name} is not registered.");
- player.RpcRemoveModifierByTypeId(id, predicate);
+ player.RpcRemoveModifier(id, predicate);
}
///
@@ -168,26 +168,26 @@ public static class ModifierExtensions
/// Checks if the player has a specific modifier by type ID.
///
/// The PlayerControl instance.
- /// The type ID of the modifier.
+ /// The type ID of the modifier.
/// Optional predicate to filter the modifiers.
/// True if the player has the modifier, false otherwise.
- public static bool HasModifierByTypeId(
+ public static bool HasModifier(
this PlayerControl player,
- uint id,
+ uint typeId,
Func? predicate = null)
{
- return player.GetModifierComponent().HasModifierByTypeId(id, predicate);
+ return player.GetModifierComponent().HasModifier(typeId, predicate);
}
///
- /// Checks if the player has a specific modifier by unique ID.
+ /// Checks if the player has a specific modifier by its GUID.
///
/// The PlayerControl instance.
- /// The unique ID of the modifier.
+ /// The unique ID of the modifier.
/// True if the player has the modifier, false otherwise.
- public static bool HasModifierByUniqueId(this PlayerControl player, uint id)
+ public static bool HasModifier(this PlayerControl player, Guid uniqueId)
{
- return player.GetModifierComponent().HasModifierByUniqueId(id);
+ return player.GetModifierComponent().HasModifier(uniqueId);
}
///
@@ -218,31 +218,31 @@ public static class ModifierExtensions
}
///
- /// Gets a specific modifier from the player by type ID.
+ /// Gets a specific modifier from the player by its type ID.
///
/// The PlayerControl instance.
- /// The type ID of the modifier.
+ /// The type ID of the modifier.
/// Optional predicate to filter the modifiers.
/// The modifier if found, null otherwise.
- public static BaseModifier? GetModifierByTypeId(
+ public static BaseModifier? GetModifier(
this PlayerControl player,
- uint id,
+ uint typeId,
Func? predicate = null)
{
- return player.GetModifierComponent().GetModifierByTypeId(id, predicate);
+ return player.GetModifierComponent().GetModifier(typeId, predicate);
}
///
- /// Gets a specific modifier from the player by ID.
+ /// Gets a specific modifier from the player by its GUID.
///
/// The PlayerControl instance.
- /// The ID of the modifier.
+ /// The GUID of the modifier.
/// The modifier if found, null otherwise.
- public static BaseModifier? GetModifierByUniqueId(
+ public static BaseModifier? GetModifier(
this PlayerControl player,
- uint id)
+ Guid uniqueId)
{
- return player.GetModifierComponent().GetModifierByUniqueId(id);
+ return player.GetModifierComponent().GetModifier(uniqueId);
}
///
@@ -251,7 +251,7 @@ public static class ModifierExtensions
/// The type of the modifiers.
/// The PlayerControl instance.
/// Optional predicate to filter the modifiers.
- /// An enumerable of modifiers.
+ /// A collection of modifiers.
public static IEnumerable GetModifiers(this PlayerControl player, Func? predicate = null)
where T : BaseModifier
{
@@ -264,7 +264,7 @@ public static class ModifierExtensions
/// The PlayerControl instance.
/// The type of the modifiers.
/// Optional predicate to filter the modifiers.
- /// An enumerable of modifiers.
+ /// A collection of modifiers.
public static IEnumerable GetModifiers(
this PlayerControl player,
Type type,
@@ -277,15 +277,15 @@ public static class ModifierExtensions
/// Gets all modifiers of a specific type from the player by type ID.
///
/// The PlayerControl instance.
- /// The type ID of the modifiers.
+ /// The type ID of the modifiers.
/// Optional predicate to filter the modifiers.
- /// An enumerable of modifiers.
+ /// A collection of modifiers.
public static IEnumerable GetModifiers(
this PlayerControl player,
- uint id,
+ uint typeId,
Func? predicate = null)
{
- return player.GetModifierComponent().GetModifiers(id, predicate);
+ return player.GetModifierComponent().GetModifiers(typeId, predicate);
}
///
@@ -322,29 +322,29 @@ public static class ModifierExtensions
}
///
- /// Removes a specific modifier from the player by ID.
+ /// Removes a specific modifier from the player by its type ID.
///
/// The PlayerControl instance.
- /// The ID of the modifier.
+ /// The type ID of the modifier.
/// Optional predicate to filter the modifiers.
- public static void RemoveModifierByTypeId(
+ public static void RemoveModifier(
this PlayerControl player,
uint typeId,
Func? predicate = null)
{
- player.GetModifierComponent().RemoveModifierByTypeId(typeId, predicate);
+ player.GetModifierComponent().RemoveModifier(typeId, predicate);
}
///
- /// Removes a specific modifier from the player by ID.
+ /// Removes a specific modifier from the player by its GUID.
///
/// The PlayerControl instance.
- /// The ID of the modifier.
- public static void RemoveModifierByUniqueId(
+ /// The GUID of the modifier.
+ public static void RemoveModifier(
this PlayerControl player,
- uint uniqueId)
+ Guid uniqueId)
{
- player.GetModifierComponent().RemoveModifierByUniqueId(uniqueId);
+ player.GetModifierComponent().RemoveModifier(uniqueId);
}
///
diff --git a/MiraAPI/Modifiers/ModifierManager.cs b/MiraAPI/Modifiers/ModifierManager.cs
index 209423e..4285a73 100644
--- a/MiraAPI/Modifiers/ModifierManager.cs
+++ b/MiraAPI/Modifiers/ModifierManager.cs
@@ -3,12 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using MiraAPI.Modifiers.Types;
-using MiraAPI.Networking;
-using MiraAPI.Networking.Modifiers;
using MiraAPI.PluginLoading;
using MiraAPI.Roles;
using MiraAPI.Utilities;
-using Reactor.Networking.Rpc;
using Reactor.Utilities;
using Reactor.Utilities.Extensions;
using Random = System.Random;
@@ -159,70 +156,6 @@ public static class ModifierManager
private static bool IsGameModifierValid(PlayerControl player, GameModifier modifier, uint modifierId)
{
return (player.Data.Role is not ICustomRole role || role.IsModifierApplicable(modifier)) &&
- modifier.IsModifierValidOn(player.Data.Role) && !player.HasModifierByTypeId(modifierId);
- }
-
- internal static void SyncAllModifiers(int targetId = -1)
- {
- var data = new List();
-
- foreach (var player in PlayerControl.AllPlayerControls)
- {
- data.Add(GetPlayerModifiers(player));
- }
-
- Rpc.Instance.SendTo(PlayerControl.LocalPlayer, targetId, [.. data]);
- }
-
- internal static void HandleSyncModifiers(NetData[] data)
- {
- foreach (var netData in data)
- {
- var ids = new uint[netData.Data.Length / 4];
- Buffer.BlockCopy(netData.Data, 0, ids, 0, netData.Data.Length);
-
- var plr = GameData.Instance.GetPlayerById((byte)netData.Id).Object;
- var modifierComponent = plr.GetComponent