From 9b173a4298e195e514d201034a28f158085f4ad7 Mon Sep 17 00:00:00 2001 From: ang-xd Date: Fri, 23 Aug 2024 20:30:34 -0400 Subject: [PATCH] Updates to Modifiers --- MiraAPI.Example/CustomRole.cs | 20 ----- MiraAPI.Example/CustomRole2.cs | 20 ----- MiraAPI.Example/CustomRole3.cs | 17 ----- MiraAPI.Example/CustomRoleSettings.cs | 19 ----- MiraAPI.Example/ExampleOptions.cs | 33 --------- MiraAPI.Example/ExampleOptions2.cs | 27 ------- MiraAPI.Example/ExamplePlugin.cs | 1 + MiraAPI.Example/MiraDebugWindow.cs | 33 +++++++++ MiraAPI.Example/ModifierExample.cs | 8 +- MiraAPI.Example/SomeRandomNonGroupClass.cs | 9 --- MiraAPI.Example/TorchModifier.cs | 26 ------- MiraAPI/Modifiers/BaseModifier.cs | 4 +- MiraAPI/Modifiers/ModifierComponent.cs | 74 ++++++------------- MiraAPI/Modifiers/ModifierManager.cs | 31 ++++++-- MiraAPI/Modifiers/Types/TimedModifier.cs | 25 ++++++- MiraAPI/Networking/MiraRpc.cs | 3 +- MiraAPI/Networking/SyncModifiersRpc.cs | 46 ++++++++++++ MiraAPI/Patches/AmongUsClientSyncPatch.cs | 3 +- .../Patches/Options/RoleSettingMenuPatches.cs | 12 +-- MiraAPI/Utilities/Extensions.cs | 21 +++++- 20 files changed, 189 insertions(+), 243 deletions(-) delete mode 100644 MiraAPI.Example/CustomRole.cs delete mode 100644 MiraAPI.Example/CustomRole2.cs delete mode 100644 MiraAPI.Example/CustomRole3.cs delete mode 100644 MiraAPI.Example/CustomRoleSettings.cs delete mode 100644 MiraAPI.Example/ExampleOptions.cs delete mode 100644 MiraAPI.Example/ExampleOptions2.cs create mode 100644 MiraAPI.Example/MiraDebugWindow.cs delete mode 100644 MiraAPI.Example/SomeRandomNonGroupClass.cs delete mode 100644 MiraAPI.Example/TorchModifier.cs create mode 100644 MiraAPI/Networking/SyncModifiersRpc.cs diff --git a/MiraAPI.Example/CustomRole.cs b/MiraAPI.Example/CustomRole.cs deleted file mode 100644 index 47b361b..0000000 --- a/MiraAPI.Example/CustomRole.cs +++ /dev/null @@ -1,20 +0,0 @@ -using MiraAPI.GameOptions.Attributes; -using MiraAPI.Roles; -using MiraAPI.Utilities.Assets; -using UnityEngine; - -namespace MiraAPI.Example; - -[RegisterCustomRole] -public class CustomRole : ImpostorRole, ICustomRole -{ - public string RoleName => "fortnite killer"; - public string RoleLongDescription => "ok so your objective is to eliminate everyone with your fortnite tactical shotgun, good luck"; - public string RoleDescription => RoleLongDescription; - public Color RoleColor => Palette.Orange; - public ModdedRoleTeams Team => ModdedRoleTeams.Impostor; - public LoadableAsset OptionsScreenshot => MiraAssets.Banner; - - [ModdedNumberOption("Testing level", min: 3, max: 9, roleType: typeof(CustomRole))] public float testingLevel { get; set; } = 4; - -} \ No newline at end of file diff --git a/MiraAPI.Example/CustomRole2.cs b/MiraAPI.Example/CustomRole2.cs deleted file mode 100644 index 3033a12..0000000 --- a/MiraAPI.Example/CustomRole2.cs +++ /dev/null @@ -1,20 +0,0 @@ -using MiraAPI.GameOptions.Attributes; -using MiraAPI.Roles; -using MiraAPI.Utilities.Assets; -using UnityEngine; - -namespace MiraAPI.Example; - -[RegisterCustomRole] -public class CustomRole2 : CrewmateRole, ICustomRole -{ - public string RoleName => "fortnite defender"; - public string RoleLongDescription => "ok so your objective is to save everyone from the fortnite killer"; - public string RoleDescription => RoleLongDescription; - public Color RoleColor => Palette.AcceptedGreen; - public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate; - public LoadableAsset OptionsScreenshot => MiraAssets.Banner; - - [ModdedToggleOption("Teleportation ability", roleType: typeof(CustomRole2))] public bool teleport { get; set; } = true; - -} \ No newline at end of file diff --git a/MiraAPI.Example/CustomRole3.cs b/MiraAPI.Example/CustomRole3.cs deleted file mode 100644 index bf309d8..0000000 --- a/MiraAPI.Example/CustomRole3.cs +++ /dev/null @@ -1,17 +0,0 @@ -using MiraAPI.Roles; -using MiraAPI.Utilities.Assets; -using UnityEngine; - -namespace MiraAPI.Example; - -[RegisterCustomRole] -public class CustomRole3 : CrewmateRole, ICustomRole -{ - public string RoleName => "fortnite helper"; - public string RoleLongDescription => "ok so your objective is to help"; - public string RoleDescription => RoleLongDescription; - public Color RoleColor => Palette.Brown; - public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate; - public LoadableAsset OptionsScreenshot => MiraAssets.Banner; - -} \ No newline at end of file diff --git a/MiraAPI.Example/CustomRoleSettings.cs b/MiraAPI.Example/CustomRoleSettings.cs deleted file mode 100644 index 34cb47a..0000000 --- a/MiraAPI.Example/CustomRoleSettings.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using MiraAPI.GameOptions; -using MiraAPI.GameOptions.Attributes; -using MiraAPI.GameOptions.OptionTypes; - -namespace MiraAPI.Example; - -public class CustomRoleSettings : IModdedOptionGroup -{ - public string GroupName => "Custom Role"; - - public Type AdvancedRole => typeof(CustomRole); - - [ModdedNumberOption("amogus", min: 3, max: 9)] public float amogus { get; set; } = 1; - - [ModdedEnumOption("dwayne the rock johnson", typeof(TestEnum))] public TestEnum dwayneTheRockJohnson { get; set; } = TestEnum.Hello; - - public ModdedToggleOption testToggle { get; } = new ("test toggle", false); -} \ No newline at end of file diff --git a/MiraAPI.Example/ExampleOptions.cs b/MiraAPI.Example/ExampleOptions.cs deleted file mode 100644 index 4160189..0000000 --- a/MiraAPI.Example/ExampleOptions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using MiraAPI.GameOptions; -using MiraAPI.GameOptions.Attributes; -using UnityEngine; - -namespace MiraAPI.Example; - -public class ExampleOptions : IModdedOptionGroup -{ - public string GroupName => "General Group"; - public Color GroupColor => Color.red; - - [ModdedToggleOption("Use Thing")] - public bool useThing { get; set; } = false; - - [ModdedToggleOption("Use another thing")] - public bool useAnotherThing { get; set; } = true; - - [ModdedNumberOption("Sussy level", min: 0, max: 10)] - public float sussyLevel { get; set; } = 4f; - - [ModdedStringOption("Sus choices", ["hello", "hello 2", "hello 3"])] - public int susChoices { get; set; } = 2; - - [ModdedEnumOption("Enum test", typeof(TestEnum))] - public TestEnum enumTest { get; set; } = TestEnum.Bye; -} - -public enum TestEnum -{ - Hello, - Hi, - Bye -} \ No newline at end of file diff --git a/MiraAPI.Example/ExampleOptions2.cs b/MiraAPI.Example/ExampleOptions2.cs deleted file mode 100644 index e6b8fb6..0000000 --- a/MiraAPI.Example/ExampleOptions2.cs +++ /dev/null @@ -1,27 +0,0 @@ -using MiraAPI.GameOptions; -using MiraAPI.GameOptions.OptionTypes; - -namespace MiraAPI.Example; - -public class ExampleOptions2 : IModdedOptionGroup -{ - public string GroupName => "Example 2"; - - public ModdedToggleOption UseThing { get; } = new("Use Thingy 5", false); - - public ModdedToggleOption UseThing2 { get; } = new("Use Thingy 6", false); - - public ModdedStringOption Sussy { get; } = new("Sussy", 0, ["Sussy 1", "Sussy 2", "Sussy 3"]); - - public ModdedEnumOption SussyEnum { get; } = new("Sussy Enum", 0, typeof(SussyEnum)); - - public ModdedNumberOption YeezyLevel { get; } = new("Yeezy Level", 50, 0, 100, 25, NumberSuffixes.Multiplier); -} - -public enum SussyEnum -{ - Sussy, - Baka, - Imposter, - Kanye -} \ No newline at end of file diff --git a/MiraAPI.Example/ExamplePlugin.cs b/MiraAPI.Example/ExamplePlugin.cs index 1f3ac7b..593d252 100644 --- a/MiraAPI.Example/ExamplePlugin.cs +++ b/MiraAPI.Example/ExamplePlugin.cs @@ -21,5 +21,6 @@ public partial class ExamplePlugin : BasePlugin, IMiraPlugin public override void Load() { Harmony.PatchAll(); + AddComponent(); } } \ No newline at end of file diff --git a/MiraAPI.Example/MiraDebugWindow.cs b/MiraAPI.Example/MiraDebugWindow.cs new file mode 100644 index 0000000..34bbb64 --- /dev/null +++ b/MiraAPI.Example/MiraDebugWindow.cs @@ -0,0 +1,33 @@ +using MiraAPI.Utilities; +using Reactor.Utilities.Attributes; +using Reactor.Utilities.ImGui; +using System; +using UnityEngine; + +namespace MiraAPI.Example; +[RegisterInIl2Cpp] +public class MiraDebugWindow : MonoBehaviour +{ + public DragWindow DebuggingWindow; + public MiraDebugWindow(IntPtr ptr) : base(ptr) + { + DebuggingWindow = new DragWindow(new Rect(10, 10, 0, 0), "MIRA API DEBUGGING", () => + { + if (GUILayout.Button("Test modifier")) + { + PlayerControl.LocalPlayer.AddModifier(); + } + if (GUILayout.Button("Remove modifier")) + { + PlayerControl.LocalPlayer.RemoveModifier(); + } + }); + + DebuggingWindow.Enabled = true; + } + + public void OnGUI() + { + DebuggingWindow.OnGUI(); + } +} \ No newline at end of file diff --git a/MiraAPI.Example/ModifierExample.cs b/MiraAPI.Example/ModifierExample.cs index f30f079..54a474e 100644 --- a/MiraAPI.Example/ModifierExample.cs +++ b/MiraAPI.Example/ModifierExample.cs @@ -6,10 +6,14 @@ namespace MiraAPI.Example; public class ModifierExample : TimedModifier { public override string ModifierName => "Timed modifier example"; - public override float Duration => 10; + public override float Duration => 1.5f; + public override bool AutoStart => true; + + private System.Random _rand = new(); public override void OnTimerComplete() { - + Player.SetColor((byte)_rand.Next(0, 18)); + StartTimer(); } } \ No newline at end of file diff --git a/MiraAPI.Example/SomeRandomNonGroupClass.cs b/MiraAPI.Example/SomeRandomNonGroupClass.cs deleted file mode 100644 index 7e57075..0000000 --- a/MiraAPI.Example/SomeRandomNonGroupClass.cs +++ /dev/null @@ -1,9 +0,0 @@ -using MiraAPI.GameOptions.Attributes; - -namespace MiraAPI.Example; - -public class SomeRandomNonGroupClass -{ - [ModdedStringOption("Yeah, idk", ["Idk 1", "idk 2", "idk 3", "idk 4"])] public static int yeaIdk { get; set; } = 3; - [ModdedNumberOption("Aw man", min: 45, max: 95)] public float sussyLevel { get; set; } = 63; -} \ No newline at end of file diff --git a/MiraAPI.Example/TorchModifier.cs b/MiraAPI.Example/TorchModifier.cs deleted file mode 100644 index 6da062f..0000000 --- a/MiraAPI.Example/TorchModifier.cs +++ /dev/null @@ -1,26 +0,0 @@ -using MiraAPI.GameOptions.Attributes; -using MiraAPI.Modifiers.Types; - -namespace MiraAPI.Example -{ - [RegisterModifier] - public class TorchModifier : GameModifier - { - public override string ModifierName => "Torch"; - - [ModdedNumberOption("Torch Chance", 0, 100, 10)] - public float chance { get; } = 50; - [ModdedNumberOption("Torch Amount", 0, 10, 1)] - public float amount { get; } = 3; - - public override int GetAmountPerGame() - { - return (int)amount; - } - - public override int GetAssignmentChance() - { - return (int)chance; - } - } -} diff --git a/MiraAPI/Modifiers/BaseModifier.cs b/MiraAPI/Modifiers/BaseModifier.cs index 2e6812b..07bac31 100644 --- a/MiraAPI/Modifiers/BaseModifier.cs +++ b/MiraAPI/Modifiers/BaseModifier.cs @@ -2,9 +2,9 @@ public abstract class BaseModifier { public abstract string ModifierName { get; } - + public PlayerControl Player { get; internal set; } - + public virtual void OnActivate() { } public virtual void OnDeactivate() { } public virtual void Update() { } diff --git a/MiraAPI/Modifiers/ModifierComponent.cs b/MiraAPI/Modifiers/ModifierComponent.cs index bfe7d0e..e9955af 100644 --- a/MiraAPI/Modifiers/ModifierComponent.cs +++ b/MiraAPI/Modifiers/ModifierComponent.cs @@ -1,12 +1,11 @@ -using Reactor.Utilities.Attributes; -using System; -using System.Collections; -using System.Collections.Generic; -using MiraAPI.Modifiers.Types; +using MiraAPI.Modifiers.Types; using MiraAPI.Networking; using MiraAPI.Utilities; using Reactor.Networking.Attributes; using Reactor.Utilities; +using Reactor.Utilities.Attributes; +using System; +using System.Collections.Generic; using UnityEngine; namespace MiraAPI.Modifiers; @@ -22,7 +21,7 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr) { player = GetComponent(); } - + public void Update() { foreach (var modifier in activeModifiers) @@ -31,44 +30,16 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr) } } - public bool HasModifier() where T : BaseModifier - { - return activeModifiers.Exists(x=>x is T); - } - - public void AddModifier() where T : BaseModifier - { - if (!ModifierManager.TypeToIdModifiers.TryGetValue(typeof(T), out var id)) - { - Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered."); - return; - } - - RpcAddModifier(player, id); - } - - public void RemoveModifier() where T : BaseModifier - { - if (!ModifierManager.TypeToIdModifiers.TryGetValue(typeof(T), out var id)) - { - Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered."); - return; - } - - RpcRemoveModifier(player, id); - } - - [MethodRpc((uint)MiraRpc.RemoveModifier)] - private static void RpcRemoveModifier(PlayerControl target, uint modifierId) + public static void RemoveModifier(PlayerControl target, uint modifierId) { if (!ModifierManager.IdToTypeModifiers.TryGetValue(modifierId, out var type)) { Logger.Error($"Cannot remove modifier with id {modifierId} because it is not registered."); return; } - + var modifierComponent = target.GetModifierComponent(); - + var modifier = modifierComponent.activeModifiers.Find(x => x.GetType() == type); if (modifier is null) @@ -76,39 +47,42 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr) Logger.Error($"Cannot remove modifier {type.Name} because it is not active."); return; } - + modifier.OnDeactivate(); modifierComponent.activeModifiers.Remove(modifier); } - [MethodRpc((uint)MiraRpc.AddModifier)] - private static void RpcAddModifier(PlayerControl target, uint modifierId) + public static void AddModifier(PlayerControl target, uint modifierId) { if (!ModifierManager.IdToTypeModifiers.TryGetValue(modifierId, out var type)) { Logger.Error($"Cannot add modifier with id {modifierId} because it is not registered."); return; } - + var modifier = (BaseModifier)Activator.CreateInstance(type); var modifierComponent = target.GetModifierComponent(); - + if (modifier is null) { Logger.Error($"Cannot add modifier {type.Name} because it is null."); return; } - + modifierComponent.activeModifiers.Add(modifier); - modifier.Player = modifierComponent.player; + modifier.Player = modifierComponent.player; modifier.OnActivate(); + + if (modifier is TimedModifier timer && timer.AutoStart && target.AmOwner) + { + timer.StartTimer(); + } } - public static IEnumerator ModifierTimer(TimedModifier modifier) - { - yield return new WaitForSeconds(modifier.Duration); - modifier.TimerActive = false; - modifier.OnTimerComplete(); - } + [MethodRpc((uint)MiraRpc.RemoveModifier)] + public static void RpcRemoveModifier(PlayerControl target, uint modifierId) => RemoveModifier(target, modifierId); + + [MethodRpc((uint)MiraRpc.AddModifier)] + public static void RpcAddModifier(PlayerControl target, uint modifierId) => AddModifier(target, modifierId); } \ No newline at end of file diff --git a/MiraAPI/Modifiers/ModifierManager.cs b/MiraAPI/Modifiers/ModifierManager.cs index 8093e09..32d95ef 100644 --- a/MiraAPI/Modifiers/ModifierManager.cs +++ b/MiraAPI/Modifiers/ModifierManager.cs @@ -1,4 +1,5 @@ -using System; +using MiraAPI.Networking; +using System; using System.Collections.Generic; namespace MiraAPI.Modifiers; @@ -7,22 +8,40 @@ public static class ModifierManager { public static readonly Dictionary IdToTypeModifiers = []; public static readonly Dictionary TypeToIdModifiers = []; - + private static uint _nextId; - + private static uint GetNextId() { - return _nextId++; + _nextId++; + return _nextId; } - + public static void RegisterModifier(Type modifierType) { if (!typeof(BaseModifier).IsAssignableFrom(modifierType)) { return; } - + IdToTypeModifiers.Add(GetNextId(), modifierType); TypeToIdModifiers.Add(modifierType, _nextId); } + + public static void SyncAllModifiers(int targetId = -1) + { + + } + + public static void HandleSyncModifiers(NetData[] data) + { + foreach (var netData in data) + { + PlayerControl plr = GameData.Instance.GetPlayerById((byte)netData.Id).Object; + foreach (var id in netData.Data) + { + ModifierComponent.AddModifier(plr, id); + } + } + } } \ No newline at end of file diff --git a/MiraAPI/Modifiers/Types/TimedModifier.cs b/MiraAPI/Modifiers/Types/TimedModifier.cs index a193a38..1725ed0 100644 --- a/MiraAPI/Modifiers/Types/TimedModifier.cs +++ b/MiraAPI/Modifiers/Types/TimedModifier.cs @@ -1,22 +1,41 @@ using Reactor.Utilities; +using UnityEngine; namespace MiraAPI.Modifiers.Types; public abstract class TimedModifier : BaseModifier { public abstract float Duration { get; } + public virtual bool AutoStart => false; public abstract void OnTimerComplete(); - internal bool TimerActive; + public bool TimerActive = false; + public float TimeRemaining; + + public override void Update() + { + if (!Player.AmOwner) return; + + if (TimeRemaining > 0 && TimerActive) + { + TimeRemaining -= Time.deltaTime; + } + else + { + TimerActive = false; + TimeRemaining = Duration; + OnTimerComplete(); + } + } public void StartTimer() { if (TimerActive) { - Logger.Error("Can't start a timer that is already started."); + Logger.Error("Can't start a timer that has already been started."); return; } TimerActive = true; - Coroutines.Start(ModifierComponent.ModifierTimer(this)); + TimeRemaining = Duration; } } \ No newline at end of file diff --git a/MiraAPI/Networking/MiraRpc.cs b/MiraAPI/Networking/MiraRpc.cs index 268f680..50625bc 100644 --- a/MiraAPI/Networking/MiraRpc.cs +++ b/MiraAPI/Networking/MiraRpc.cs @@ -5,5 +5,6 @@ public enum MiraRpc : uint SyncGameOptions, SyncRoleOptions, AddModifier, - RemoveModifier + RemoveModifier, + SyncModifiers } \ No newline at end of file diff --git a/MiraAPI/Networking/SyncModifiersRpc.cs b/MiraAPI/Networking/SyncModifiersRpc.cs new file mode 100644 index 0000000..e760522 --- /dev/null +++ b/MiraAPI/Networking/SyncModifiersRpc.cs @@ -0,0 +1,46 @@ +using Hazel; +using MiraAPI.Modifiers; +using Reactor.Networking.Attributes; +using Reactor.Networking.Rpc; + +namespace MiraAPI.Networking; + +[RegisterCustomRpc((uint)MiraRpc.SyncModifiers)] +public class SyncModifiersRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc(plugin, id) +{ + public override RpcLocalHandling LocalHandling => RpcLocalHandling.None; + + public override void Write(MessageWriter writer, NetData[] data) + { + 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 id = reader.ReadPackedUInt32(); + var bytes = reader.ReadBytesAndSize(); + data[i] = new NetData(id, bytes); + } + + return data; + } + + public override void Handle(PlayerControl playerControl, NetData[] data) + { + if (AmongUsClient.Instance.HostId != playerControl.OwnerId) + { + return; + } + + ModifierManager.HandleSyncModifiers(data); + } +} \ No newline at end of file diff --git a/MiraAPI/Patches/AmongUsClientSyncPatch.cs b/MiraAPI/Patches/AmongUsClientSyncPatch.cs index 121eca5..3e71ae5 100644 --- a/MiraAPI/Patches/AmongUsClientSyncPatch.cs +++ b/MiraAPI/Patches/AmongUsClientSyncPatch.cs @@ -14,7 +14,7 @@ public static class AmongUsClientSyncPatch { return; } - + if (clientData.Id == AmongUsClient.Instance.HostId) { return; @@ -22,5 +22,6 @@ public static class AmongUsClientSyncPatch ModdedOptionsManager.SyncAllOptions(clientData.Id); CustomRoleManager.SyncAllRoleSettings(clientData.Id); + // ModifierManager.SyncAllModifiers(clientData.Id); } } \ No newline at end of file diff --git a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs index bcdecbe..48ff1dd 100644 --- a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs +++ b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs @@ -1,13 +1,13 @@ using HarmonyLib; +using MiraAPI.Networking; using MiraAPI.Roles; using MiraAPI.Utilities; using MiraAPI.Utilities.Assets; +using Reactor.Networking.Rpc; +using Reactor.Utilities; using Reactor.Utilities.Extensions; using System; using System.Linq; -using MiraAPI.Networking; -using Reactor.Networking.Rpc; -using Reactor.Utilities; using TMPro; using UnityEngine; using UnityEngine.Events; @@ -25,7 +25,7 @@ public static class RoleSettingMenuPatches { __instance.roleChances = new Il2CppSystem.Collections.Generic.List(); __instance.advancedSettingChildren = new Il2CppSystem.Collections.Generic.List(); - + var maskBg = __instance.scrollBar.transform.FindChild("MaskBg"); if (GameSettingMenuPatches.CurrentSelectedMod == 0) @@ -124,7 +124,7 @@ public static class RoleSettingMenuPatches private static void CreateAdvancedSettings(RolesSettingsMenu __instance, RoleBehaviour role) { - foreach (var option in __instance.advancedSettingChildren) + foreach (var option in __instance.advancedSettingChildren) { Object.Destroy(option.gameObject); } @@ -162,7 +162,7 @@ public static class RoleSettingMenuPatches { ICustomRole customRole = role as ICustomRole; __instance.roleDescriptionText.text = customRole.RoleLongDescription; - __instance.roleTitleText.text = DestroyableSingleton.Instance.GetString(role.StringName, []); + __instance.roleTitleText.text = DestroyableSingleton.Instance.GetString(role.StringName, Array.Empty()); __instance.roleScreenshot.sprite = Sprite.Create(role.RoleScreenshot.texture, new Rect(0, 0, 370, 230), Vector2.one / 2, 100); __instance.roleScreenshot.drawMode = SpriteDrawMode.Sliced; __instance.roleHeaderSprite.color = customRole.RoleColor; diff --git a/MiraAPI/Utilities/Extensions.cs b/MiraAPI/Utilities/Extensions.cs index 2291243..21d7d5a 100644 --- a/MiraAPI/Utilities/Extensions.cs +++ b/MiraAPI/Utilities/Extensions.cs @@ -1,6 +1,7 @@ using MiraAPI.GameOptions; using MiraAPI.Modifiers; using MiraAPI.Roles; +using Reactor.Utilities; using Reactor.Utilities.Extensions; using System.Linq; using UnityEngine; @@ -19,13 +20,31 @@ public static class Extensions return player.gameObject.GetComponent(); } + public static bool HasModifier(this PlayerControl player) where T : BaseModifier + { + return player.GetModifierComponent().activeModifiers.Exists(x => x is T); + } + public static void AddModifier(this PlayerControl player) where T : BaseModifier { - player.GetModifierComponent().AddModifier(); + if (!ModifierManager.TypeToIdModifiers.TryGetValue(typeof(T), out var id)) + { + Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered."); + return; + } + + ModifierComponent.RpcAddModifier(player, id); } public static void RemoveModifier(this PlayerControl player) where T : BaseModifier { + if (!ModifierManager.TypeToIdModifiers.TryGetValue(typeof(T), out var id)) + { + Logger.Error($"Cannot add modifier {typeof(T).Name} because it is not registered."); + return; + } + + ModifierComponent.RpcRemoveModifier(player, id); } public static Color DarkenColor(this Color color)