better modifier unique IDs

This commit is contained in:
XtraCube committed 2025-02-25 21:57:38 -05:00
1 parent caa27642db
commit 7e4a71739c
12 files changed
+134 -219

No files matched your search

+1 -1
View File
@@ -45,7 +45,7 @@ public abstract class BaseModifier
/// <summary>
/// Gets the unique ID of the modifier.
/// </summary>
public uint UniqueId { get; internal set; }
public Guid UniqueId { get; internal set; } = Guid.Empty;
/// <summary>
/// Gets the type ID of the modifier.
+24 -29
View File
@@ -37,14 +37,6 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
private readonly List<BaseModifier> _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)
/// <param name="predicate">The predicate to check the modifier by.</param>
/// <returns>True if the modifier was found, false otherwise.</returns>
[HideFromIl2Cpp]
public bool TryGetModifierByTypeId(uint id, out BaseModifier? modifier, Func<BaseModifier, bool>? predicate = null)
public bool TryGetModifier(uint id, out BaseModifier? modifier, Func<BaseModifier, bool>? predicate = null)
{
modifier = GetModifierByTypeId(id, predicate);
modifier = GetModifier(id, predicate);
return modifier != null;
}
/// <summary>
/// Tries to get a modifier by its unique ID.
/// </summary>
/// <param name="id">The modifier unique ID.</param>
/// <param name="modifierGuid">The modifier unique ID.</param>
/// <param name="modifier">The modifier or null.</param>
/// <returns>True if the modifier was found, false otherwise.</returns>
[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)
/// <param name="predicate">The predicate to check the modifier by.</param>
/// <returns>The Modifier if it is found, null otherwise.</returns>
[HideFromIl2Cpp]
public BaseModifier? GetModifierByTypeId(uint id, Func<BaseModifier, bool>? predicate = null)
public BaseModifier? GetModifier(uint id, Func<BaseModifier, bool>? 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)
/// <summary>
/// Gets a modifier by unique ID.
/// </summary>
/// <param name="id">The modifier's unique ID.</param>
/// <param name="modifierGuid">The modifier's unique ID.</param>
/// <returns>The modifier if it is found, or null.</returns>
[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);
}
/// <summary>
@@ -330,7 +322,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
/// <param name="typeId">The modifier's type ID.</param>
/// <param name="predicate">The predicate to check the modifier by.</param>
[HideFromIl2Cpp]
public void RemoveModifierByTypeId(uint typeId, Func<BaseModifier, bool>? predicate = null)
public void RemoveModifier(uint typeId, Func<BaseModifier, bool>? 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)
/// </summary>
/// <param name="uniqueId">The modifier's unique ID.</param>
[HideFromIl2Cpp]
public void RemoveModifierByUniqueId(uint uniqueId)
public void RemoveModifier(Guid uniqueId)
{
var modifier = GetModifierByUniqueId(uniqueId);
var modifier = GetModifier(uniqueId);
if (modifier == null)
{
Logger<MiraApiPlugin>.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)
}
/// <summary>
/// Checks if a player has an active modifier by its type ID
/// Checks if a player has an active modifier by its type ID.
/// </summary>
/// <param name="id">The Modifier type ID.</param>
/// <param name="id">The modifier's type ID.</param>
/// <param name="predicate">The predicate to check the modifier.</param>
/// <returns>True if the Modifier is present, false otherwise.</returns>
/// <returns>True if the modifier is present, false otherwise.</returns>
[HideFromIl2Cpp]
public bool HasModifierByTypeId(uint id, Func<BaseModifier, bool>? predicate=null)
public bool HasModifier(uint id, Func<BaseModifier, bool>? 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)
}
/// <summary>
/// Checks if a player has an active modifier by its unique ID
/// Checks if a player has an active modifier by its unique ID.
/// </summary>
/// <param name="id">The Modifier type ID.</param>
/// <returns>True if the Modifier is present, false otherwise.</returns>
/// <param name="id">The modifier's guid.</param>
/// <returns>True if the modifier is present, false otherwise.</returns>
[HideFromIl2Cpp]
public bool HasModifierByUniqueId(uint id)
public bool HasModifier(Guid id)
{
return Modifiers.Exists(x => x.UniqueId == id);
}
-19
View File
@@ -1,19 +0,0 @@
namespace MiraAPI.Modifiers;
/// <summary>
/// Modifier data for networking.
/// </summary>
/// <param name="id">The ID of the modifier.</param>
/// <param name="args">Parameters for constructor.</param>
public readonly struct ModifierData(uint id, object[] args)
{
/// <summary>
/// Gets the type of the modifier.
/// </summary>
public uint Id { get; } = id;
/// <summary>
/// Gets the parameters for the constructor.
/// </summary>
public object[] Args { get; } = args;
}
+40 -40
View File
@@ -29,7 +29,7 @@ public static class ModifierExtensions
_ = ModifierManager.GetModifierType(typeId) ?? throw new InvalidOperationException(
$"Modifier with ID {typeId} is not registered.");
Rpc<AddModifierRpc>.Instance.Send(target, new ModifierData(typeId, args));
Rpc<AddModifierRpc>.Instance.Send(target, new ModifierData(typeId, Guid.NewGuid(), args));
}
/// <summary>
@@ -63,9 +63,9 @@ public static class ModifierExtensions
/// <param name="target">The player to remove the modifier from.</param>
/// <param name="uniqueId">The unique ID of the modifier.</param>
[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);
}
/// <summary>
@@ -74,19 +74,19 @@ public static class ModifierExtensions
/// <param name="target">The player to remove the modifier from.</param>
/// <param name="typeId">The type ID of the modifier.</param>
/// <param name="predicate">Optional predicate to filter the modifiers.</param>
public static void RpcRemoveModifierByTypeId(
public static void RpcRemoveModifier(
this PlayerControl target,
uint typeId,
Func<BaseModifier, bool>? predicate = null)
{
var modifier = target.GetModifierByTypeId(typeId, predicate);
var modifier = target.GetModifier(typeId, predicate);
if (modifier is null)
{
Logger<MiraApiPlugin>.Error($"Player {target.PlayerId} does not have modifier with type ID {typeId}.");
return;
}
target.RpcRemoveModifierByUniqueId(modifier.UniqueId);
target.RpcRemoveModifier(modifier.UniqueId);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -168,26 +168,26 @@ public static class ModifierExtensions
/// Checks if the player has a specific modifier by type ID.
/// </summary>
/// <param name="player">The PlayerControl instance.</param>
/// <param name="id">The type ID of the modifier.</param>
/// <param name="typeId">The type ID of the modifier.</param>
/// <param name="predicate">Optional predicate to filter the modifiers.</param>
/// <returns>True if the player has the modifier, false otherwise.</returns>
public static bool HasModifierByTypeId(
public static bool HasModifier(
this PlayerControl player,
uint id,
uint typeId,
Func<BaseModifier, bool>? predicate = null)
{
return player.GetModifierComponent().HasModifierByTypeId(id, predicate);
return player.GetModifierComponent().HasModifier(typeId, predicate);
}
/// <summary>
/// Checks if the player has a specific modifier by unique ID.
/// Checks if the player has a specific modifier by its GUID.
/// </summary>
/// <param name="player">The PlayerControl instance.</param>
/// <param name="id">The unique ID of the modifier.</param>
/// <param name="uniqueId">The unique ID of the modifier.</param>
/// <returns>True if the player has the modifier, false otherwise.</returns>
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);
}
/// <summary>
@@ -218,31 +218,31 @@ public static class ModifierExtensions
}
/// <summary>
/// Gets a specific modifier from the player by type ID.
/// Gets a specific modifier from the player by its type ID.
/// </summary>
/// <param name="player">The PlayerControl instance.</param>
/// <param name="id">The type ID of the modifier.</param>
/// <param name="typeId">The type ID of the modifier.</param>
/// <param name="predicate">Optional predicate to filter the modifiers.</param>
/// <returns>The modifier if found, null otherwise.</returns>
public static BaseModifier? GetModifierByTypeId(
public static BaseModifier? GetModifier(
this PlayerControl player,
uint id,
uint typeId,
Func<BaseModifier, bool>? predicate = null)
{
return player.GetModifierComponent().GetModifierByTypeId(id, predicate);
return player.GetModifierComponent().GetModifier(typeId, predicate);
}
/// <summary>
/// Gets a specific modifier from the player by ID.
/// Gets a specific modifier from the player by its GUID.
/// </summary>
/// <param name="player">The PlayerControl instance.</param>
/// <param name="id">The ID of the modifier.</param>
/// <param name="uniqueId">The GUID of the modifier.</param>
/// <returns>The modifier if found, null otherwise.</returns>
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);
}
/// <summary>
@@ -251,7 +251,7 @@ public static class ModifierExtensions
/// <typeparam name="T">The type of the modifiers.</typeparam>
/// <param name="player">The PlayerControl instance.</param>
/// <param name="predicate">Optional predicate to filter the modifiers.</param>
/// <returns>An enumerable of modifiers.</returns>
/// <returns>A collection of modifiers.</returns>
public static IEnumerable<T> GetModifiers<T>(this PlayerControl player, Func<T, bool>? predicate = null)
where T : BaseModifier
{
@@ -264,7 +264,7 @@ public static class ModifierExtensions
/// <param name="player">The PlayerControl instance.</param>
/// <param name="type">The type of the modifiers.</param>
/// <param name="predicate">Optional predicate to filter the modifiers.</param>
/// <returns>An enumerable of modifiers.</returns>
/// <returns>A collection of modifiers.</returns>
public static IEnumerable<BaseModifier> 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.
/// </summary>
/// <param name="player">The PlayerControl instance.</param>
/// <param name="id">The type ID of the modifiers.</param>
/// <param name="typeId">The type ID of the modifiers.</param>
/// <param name="predicate">Optional predicate to filter the modifiers.</param>
/// <returns>An enumerable of modifiers.</returns>
/// <returns>A collection of modifiers.</returns>
public static IEnumerable<BaseModifier> GetModifiers(
this PlayerControl player,
uint id,
uint typeId,
Func<BaseModifier, bool>? predicate = null)
{
return player.GetModifierComponent().GetModifiers(id, predicate);
return player.GetModifierComponent().GetModifiers(typeId, predicate);
}
/// <summary>
@@ -322,29 +322,29 @@ public static class ModifierExtensions
}
/// <summary>
/// Removes a specific modifier from the player by ID.
/// Removes a specific modifier from the player by its type ID.
/// </summary>
/// <param name="player">The PlayerControl instance.</param>
/// <param name="typeId">The ID of the modifier.</param>
/// <param name="typeId">The type ID of the modifier.</param>
/// <param name="predicate">Optional predicate to filter the modifiers.</param>
public static void RemoveModifierByTypeId(
public static void RemoveModifier(
this PlayerControl player,
uint typeId,
Func<BaseModifier, bool>? predicate = null)
{
player.GetModifierComponent().RemoveModifierByTypeId(typeId, predicate);
player.GetModifierComponent().RemoveModifier(typeId, predicate);
}
/// <summary>
/// Removes a specific modifier from the player by ID.
/// Removes a specific modifier from the player by its GUID.
/// </summary>
/// <param name="player">The PlayerControl instance.</param>
/// <param name="uniqueId">The ID of the modifier.</param>
public static void RemoveModifierByUniqueId(
/// <param name="uniqueId">The GUID of the modifier.</param>
public static void RemoveModifier(
this PlayerControl player,
uint uniqueId)
Guid uniqueId)
{
player.GetModifierComponent().RemoveModifierByUniqueId(uniqueId);
player.GetModifierComponent().RemoveModifier(uniqueId);
}
/// <summary>
+1 -68
View File
@@ -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<NetData>();
foreach (var player in PlayerControl.AllPlayerControls)
{
data.Add(GetPlayerModifiers(player));
}
Rpc<SyncModifiersRpc>.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<ModifierComponent>();
if (!modifierComponent)
{
continue;
}
modifierComponent.ClearModifiers();
foreach (var id in ids)
{
if (!IdToTypeModifierMap.TryGetValue(id, out var type))
{
Logger<MiraApiPlugin>.Error($"Cannot add modifier with id {id} because it is not registered.");
continue;
}
modifierComponent.AddModifier(type);
}
}
}
private static NetData GetPlayerModifiers(PlayerControl? player)
{
if (player == null || !player)
{
return new NetData(0, []);
}
List<byte> bytes = [];
var modifierComponent = player.GetComponent<ModifierComponent>();
if (modifierComponent == null || !modifierComponent)
{
return new NetData(player.PlayerId, []);
}
foreach (var modifier in modifierComponent.ActiveModifiers)
{
bytes.AddRange(BitConverter.GetBytes(TypeToIdModifierMap[modifier.GetType()]));
}
return new NetData(player.PlayerId, [.. bytes]);
modifier.IsModifierValidOn(player.Data.Role) && !player.HasModifier(modifierId);
}
}
+32
View File
@@ -0,0 +1,32 @@
using System;
using Hazel;
using Reactor.Networking.Attributes;
using Reactor.Networking.Serialization;
namespace MiraAPI.Networking;
/// <summary>
/// Converter for <see cref="Guid"/>.
/// </summary>
[MessageConverter]
public class GuidConverter : MessageConverter<Guid>
{
/// <summary>
/// Writes a <see cref="Guid"/> to the writer.
/// </summary>
/// <inheritdoc />
public override void Write(MessageWriter writer, Guid value)
{
writer.WriteBytesAndSize(value.ToByteArray());
}
/// <summary>
/// Reads a <see cref="Guid"/> from the reader.
/// </summary>
/// <inheritdoc />
/// <returns>A GUID object.</returns>
public override Guid Read(MessageReader reader, Type objectType)
{
return new Guid(reader.ReadBytesAndSize());
}
}
+20 -3
View File
@@ -21,7 +21,8 @@ public class AddModifierRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<Mir
/// <inheritdoc />
public override void Write(MessageWriter writer, ModifierData data)
{
writer.WritePacked(data.Id);
writer.WritePacked(data.TypeId);
writer.WriteBytesAndSize(data.UniqueId.ToByteArray());
writer.WritePacked(data.Args.Length);
foreach (var arg in data.Args)
{
@@ -34,6 +35,7 @@ public class AddModifierRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<Mir
public override ModifierData Read(MessageReader reader)
{
var modId = reader.ReadPackedUInt32();
var guid = new Guid(reader.ReadBytesAndSize());
var argCount = reader.ReadPackedUInt32();
var objects = new object[argCount];
@@ -48,12 +50,27 @@ public class AddModifierRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<Mir
}
}
return new ModifierData(modId, objects);
return new ModifierData(modId, guid, objects);
}
/// <inheritdoc />
public override void Handle(PlayerControl player, ModifierData data)
{
player.AddModifier(data.Id, data.Args);
var type = ModifierManager.GetModifierType(data.TypeId) ?? throw new InvalidOperationException($"Modifier type not found for ID {data.TypeId}.");
BaseModifier? modifier;
if (data.Args.Length > 0)
{
modifier = ModifierFactory.CreateInstance(type, data.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.");
}
}
modifier.UniqueId = data.UniqueId;
player.AddModifier(modifier);
}
}
@@ -0,0 +1,11 @@
using System;
namespace MiraAPI.Networking.Modifiers;
/// <summary>
/// Modifier data for networking.
/// </summary>
/// <param name="TypeId">The ID of the modifier.</param>
/// <param name="UniqueId">The unique ID of the modifier.</param>
/// <param name="Args">Parameters for constructor.</param>
public record struct ModifierData(uint TypeId, Guid UniqueId, object[] Args);
@@ -1,52 +0,0 @@
using Hazel;
using MiraAPI.Modifiers;
using Reactor.Networking.Attributes;
using Reactor.Networking.Rpc;
namespace MiraAPI.Networking.Modifiers;
[RegisterCustomRpc((uint)MiraRpc.SyncModifiers)]
internal sealed class SyncModifiersRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<MiraApiPlugin, NetData[]>(plugin, id)
{
public override RpcLocalHandling LocalHandling => RpcLocalHandling.None;
public override void Write(MessageWriter writer, NetData[]? data)
{
if (data == null)
{
writer.WritePacked(0U);
return;
}
writer.WritePacked((uint)data.Length);
foreach (var netData in data)
{
writer.WritePacked(netData.Id);
writer.WriteBytesAndSize(netData.Data);
}
}
public override NetData[] Read(MessageReader reader)
{
var length = reader.ReadPackedUInt32();
var data = new NetData[length];
for (var i = 0; i < length; i++)
{
var dataId = reader.ReadPackedUInt32();
var bytes = reader.ReadBytesAndSize();
data[i] = new NetData(dataId, bytes);
}
return data;
}
public override void Handle(PlayerControl playerControl, NetData[]? data)
{
if (AmongUsClient.Instance.HostId != playerControl.OwnerId)
{
return;
}
ModifierManager.HandleSyncModifiers(data ?? []);
}
}
+2 -4
View File
@@ -3,16 +3,15 @@ using InnerNet;
using MiraAPI.Events;
using MiraAPI.Events.Vanilla.Player;
using MiraAPI.GameOptions;
using MiraAPI.Modifiers;
using MiraAPI.Roles;
namespace MiraAPI.Patches;
/// <summary>
/// Sync all options, role settings, and modifiers to the player when they join the game.
/// Sync all settings to the player when they join the game.
/// </summary>
[HarmonyPatch(typeof(AmongUsClient))]
public static class AmongUsClientSyncPatch
internal static class AmongUsClientSyncPatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.CreatePlayer))]
@@ -33,7 +32,6 @@ public static class AmongUsClientSyncPatch
ModdedOptionsManager.SyncAllOptions(clientData.Id);
CustomRoleManager.SyncAllRoleSettings(clientData.Id);
ModifierManager.SyncAllModifiers(clientData.Id);
}
[HarmonyPostfix]
@@ -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.HasModifierByTypeId(result);
__instance.Overlay.enabled = PlayerControl.LocalPlayer.HasModifier(result);
return false;
}
+2 -2
View File
@@ -337,9 +337,9 @@ internal static class TaskAdderPatches
taskAddButton.Button.OnClick.AddListener((UnityEngine.Events.UnityAction)(() =>
{
var id = modifier.TypeId;
if (PlayerControl.LocalPlayer.HasModifierByTypeId(id))
if (PlayerControl.LocalPlayer.HasModifier(id))
{
PlayerControl.LocalPlayer.RemoveModifierByTypeId(id);
PlayerControl.LocalPlayer.RemoveModifier(id);
taskAddButton.Overlay.enabled = false;
}
else