From 3a36acd13147cd51f251e96bf2a08facf008148a Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Thu, 3 Apr 2025 20:37:09 -0400 Subject: [PATCH 01/12] rework modifier assignment --- MiraAPI/Modifiers/ModifierManager.cs | 88 ++++++++++++---------------- 1 file changed, 38 insertions(+), 50 deletions(-) diff --git a/MiraAPI/Modifiers/ModifierManager.cs b/MiraAPI/Modifiers/ModifierManager.cs index 5f6bbff..8b67b4f 100644 --- a/MiraAPI/Modifiers/ModifierManager.cs +++ b/MiraAPI/Modifiers/ModifierManager.cs @@ -103,68 +103,56 @@ public static class ModifierManager { var rand = new Random(); - foreach (var priority in PrioritiesToIdsMap.Keys.OrderByDescending(x => x)) + // Filter and sort modifiers by descending priority. + var modifiers = IdToTypeModifierMap + .Select(x => Activator.CreateInstance(x.Value) as GameModifier) + .OfType() + .Where(x => x.GetAmountPerGame() > 0 && x.GetAssignmentChance() > 0) + .OrderByDescending(x => x.Priority()) + .ToArray(); + + foreach (var modifier in modifiers) { - var filteredModifiers = new List(); + var assignments = modifier.GetAmountPerGame(); - foreach (var id in PrioritiesToIdsMap[priority]) + var validPlayers = plrs.Where(x => IsGameModifierValid(x, modifier, modifier.TypeId)).ToList(); + if (validPlayers.Count == 0) { - var mod = Activator.CreateInstance(IdToTypeModifierMap[id]) as GameModifier; - var chance = Math.Clamp(mod!.GetAssignmentChance(), 0, 100); - var count = mod.GetAmountPerGame(); - - if (chance == 0 || count == 0) - { - continue; - } - - var maxCount = plrs.Count(x => IsGameModifierValid(x, mod, id)); - - if (maxCount == 0) - { - Logger.Warning($"No players are valid for {mod.ModifierName}"); - continue; - } - - var num = Math.Clamp(count, 0, maxCount); - - for (var i = 0; i < num; i++) - { - var randomNum = rand.Next(100); - - if (randomNum < chance) - { - filteredModifiers.Add(id); - } - } - } - - if (filteredModifiers.Count == 0) - { - Logger.Warning($"No filtered modifiers for priority {priority}"); + Logger.Warning($"No valid players for modifier {modifier.ModifierName}"); continue; } - var shuffledList = filteredModifiers.Randomize(); + assignments = Math.Min(assignments, validPlayers.Count); + var availablePlayers = new List(validPlayers); - if (shuffledList.Count > plrs.Count) + for (var i = 0; i < assignments; i++) { - shuffledList = shuffledList.GetRange(0, plrs.Count); - } - - foreach (var id in shuffledList) - { - var mod = Activator.CreateInstance(IdToTypeModifierMap[id]) as GameModifier; - var plr = plrs.Where(x => IsGameModifierValid(x, mod!, id)).Random(); - - if (!plr || plr == null) + var chance = Math.Clamp(modifier.GetAssignmentChance(), 0, 100); + if (rand.Next(100) >= chance) { - Logger.Warning($"Somehow valid players for modifier {mod!.ModifierName} disappeared"); + continue; } - else + + var candidates = availablePlayers + .Where(x => IsGameModifierValid(x, modifier, modifier.TypeId)) + .ToList(); + + if (candidates.Count == 0) { - plr.RpcAddModifier(id); + Logger.Warning( + $"No available players for modifier {modifier.ModifierName} at assignment {i + 1}"); + break; } + + var plr = candidates.Random(); + if (plr == null) + { + Logger.Warning($"Valid player for modifier {modifier.ModifierName} disappeared"); + continue; + } + + plr.RpcAddModifier(modifier.TypeId); + availablePlayers.Remove(plr); } } } From b2fabdb1392ae7431143d97951787c4569bd62b5 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Fri, 4 Apr 2025 09:33:59 -0400 Subject: [PATCH 02/12] add check inactive variants of hasmodifier --- MiraAPI/Modifiers/ModifierComponent.cs | 57 +++++++++++++++++++++++++ MiraAPI/Modifiers/ModifierExtensions.cs | 22 +++++----- MiraAPI/Modifiers/ModifierManager.cs | 1 + 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/MiraAPI/Modifiers/ModifierComponent.cs b/MiraAPI/Modifiers/ModifierComponent.cs index f8859e3..6335059 100644 --- a/MiraAPI/Modifiers/ModifierComponent.cs +++ b/MiraAPI/Modifiers/ModifierComponent.cs @@ -507,4 +507,61 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr) { return ActiveModifiers.Exists(x => x.UniqueId == id); } + + /// + /// Checks if a player has an active modifier by its type. + /// + /// Whether to check inactive modifiers (those pending to be added or removed). + /// The predicate to check the modifier. + /// The Type of the Modifier. + /// True if the Modifier is present, false otherwise. + [HideFromIl2Cpp] + public bool HasModifier(bool checkInactive, Func? predicate=null) where T : BaseModifier + { + return ActiveModifiers.Exists(MatchExpr) || (checkInactive && (_toAdd.Exists(MatchExpr) || _toRemove.Exists(MatchExpr))); + bool MatchExpr(BaseModifier bm) => bm is T modifier && (predicate == null || predicate(modifier)); + } + + /// + /// Checks if a player has an active modifier by its type. + /// + /// The modifier type. + /// Whether to check inactive modifiers (those pending to be added or removed). + /// The predicate to check the modifier. + /// True if the Modifier is present, false otherwise. + [HideFromIl2Cpp] + public bool HasModifier(Type type, bool checkInactive, Func? predicate=null) + { + return ActiveModifiers.Exists(MatchExpr) || (checkInactive && (_toAdd.Exists(MatchExpr) || _toRemove.Exists(MatchExpr))); + bool MatchExpr(BaseModifier bm) => bm.GetType() == type && (predicate == null || predicate(bm)); + } + + /// + /// Checks if a player has an active modifier by its type ID. + /// + /// The modifier's type ID. + /// Whether to check inactive modifiers (those pending to be added or removed). + /// The predicate to check the modifier. + /// True if the modifier is present, false otherwise. + [HideFromIl2Cpp] + public bool HasModifier(uint id, bool checkInactive, 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, checkInactive, predicate); + } + + /// + /// Checks if a player has an active modifier by its unique ID. + /// + /// The modifier's guid. + /// Whether to check inactive modifiers (those pending to be added or removed). + /// True if the modifier is present, false otherwise. + [HideFromIl2Cpp] + public bool HasModifier(Guid id, bool checkInactive) + { + return ActiveModifiers.Exists(MatchExpr) || (checkInactive && (_toAdd.Exists(MatchExpr) || _toRemove.Exists(MatchExpr))); + bool MatchExpr(BaseModifier bm) => bm.UniqueId == id; + } } diff --git a/MiraAPI/Modifiers/ModifierExtensions.cs b/MiraAPI/Modifiers/ModifierExtensions.cs index ca49808..c028fa3 100644 --- a/MiraAPI/Modifiers/ModifierExtensions.cs +++ b/MiraAPI/Modifiers/ModifierExtensions.cs @@ -180,6 +180,17 @@ public static class ModifierExtensions return player.GetModifierComponent().HasModifier(typeId, predicate); } + /// + /// Checks if the player has a specific modifier by its GUID. + /// + /// The PlayerControl instance. + /// The unique ID of the modifier. + /// True if the player has the modifier, false otherwise. + public static bool HasModifier(this PlayerControl player, Guid uniqueId) + { + return player.GetModifierComponent().HasModifier(uniqueId); + } + /// /// Clears all modifiers from a player. /// @@ -204,17 +215,6 @@ public static class ModifierExtensions } } - /// - /// Checks if the player has a specific modifier by its GUID. - /// - /// The PlayerControl instance. - /// The unique ID of the modifier. - /// True if the player has the modifier, false otherwise. - public static bool HasModifier(this PlayerControl player, Guid uniqueId) - { - return player.GetModifierComponent().HasModifier(uniqueId); - } - /// /// Tries to get a modifier by its type. /// diff --git a/MiraAPI/Modifiers/ModifierManager.cs b/MiraAPI/Modifiers/ModifierManager.cs index 8b67b4f..9f61239 100644 --- a/MiraAPI/Modifiers/ModifierManager.cs +++ b/MiraAPI/Modifiers/ModifierManager.cs @@ -105,6 +105,7 @@ public static class ModifierManager // Filter and sort modifiers by descending priority. var modifiers = IdToTypeModifierMap + .Where(x=>x.Value.IsAssignableTo(typeof(GameModifier))) .Select(x => Activator.CreateInstance(x.Value) as GameModifier) .OfType() .Where(x => x.GetAmountPerGame() > 0 && x.GetAssignmentChance() > 0) From efd176f7a4e8c3805f0eb4ff9bc0db62c32ff775 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Fri, 4 Apr 2025 12:18:37 -0400 Subject: [PATCH 03/12] fix timer bug related to effects --- MiraAPI/Hud/CustomActionButton.cs | 42 ++++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/MiraAPI/Hud/CustomActionButton.cs b/MiraAPI/Hud/CustomActionButton.cs index 6a721da..e215fda 100644 --- a/MiraAPI/Hud/CustomActionButton.cs +++ b/MiraAPI/Hud/CustomActionButton.cs @@ -417,9 +417,12 @@ public abstract class CustomActionButton /// The local PlayerControl. public virtual void FixedUpdateHandler(PlayerControl playerControl) { - if (Timer >= 0 && !TimerPaused) + if (Timer >= 0) { - Timer -= Time.deltaTime; + if (!TimerPaused) + { + Timer -= Time.deltaTime; + } } else if (HasEffect && EffectActive) { @@ -428,25 +431,28 @@ public abstract class CustomActionButton OnEffectEnd(); } - if (CanUse()) + if (Button) { - Button?.SetEnabled(); - } - else - { - Button?.SetDisabled(); - } + if (CanUse()) + { + Button.SetEnabled(); + } + else + { + Button.SetDisabled(); + } - if (EffectActive) - { - Button?.SetFillUp(Timer, EffectDuration); + if (EffectActive) + { + Button.SetFillUp(Timer, EffectDuration); - Button!.cooldownTimerText.text = Mathf.CeilToInt(Timer).ToString(NumberFormatInfo.InvariantInfo); - Button!.cooldownTimerText.gameObject.SetActive(true); - } - else - { - Button?.SetCoolDown(Timer, Cooldown); + Button.cooldownTimerText.text = Mathf.CeilToInt(Timer).ToString(NumberFormatInfo.InvariantInfo); + Button.cooldownTimerText.gameObject.SetActive(true); + } + else + { + Button.SetCoolDown(Timer, Cooldown); + } } FixedUpdate(playerControl); From f43a54213407a7ef391fafe58e3ddc4a1e579565 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Fri, 4 Apr 2025 12:34:41 -0400 Subject: [PATCH 04/12] fix voting never ends bug --- MiraAPI/Patches/Voting/MeetingHudPatches.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MiraAPI/Patches/Voting/MeetingHudPatches.cs b/MiraAPI/Patches/Voting/MeetingHudPatches.cs index 3f0df63..dc5f02b 100644 --- a/MiraAPI/Patches/Voting/MeetingHudPatches.cs +++ b/MiraAPI/Patches/Voting/MeetingHudPatches.cs @@ -53,6 +53,17 @@ internal static class MeetingHudPatches MiraEventManager.InvokeEvent(new VotingCompleteEvent(__instance)); } + [HarmonyPostfix] + [HarmonyPatch(nameof(MeetingHud.ForceSkipAll))] + public static void MeetingHudForceSkipAllPatch(MeetingHud __instance) + { + foreach (var plr in PlayerControl.AllPlayerControls) + { + var voteData = plr.GetVoteData(); + voteData.SetRemainingVotes(0); + } + } + [HarmonyPrefix] [HarmonyPatch(nameof(MeetingHud.Select))] public static bool SelectPatch(MeetingHud __instance, int suspectStateIdx) From bd0aa68cb89b90490897849999950091d36b31ba Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Fri, 4 Apr 2025 12:42:12 -0400 Subject: [PATCH 05/12] slight logic adjustment to fix inactive modifier checks --- MiraAPI/Modifiers/ModifierComponent.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/MiraAPI/Modifiers/ModifierComponent.cs b/MiraAPI/Modifiers/ModifierComponent.cs index 6335059..918c1a4 100644 --- a/MiraAPI/Modifiers/ModifierComponent.cs +++ b/MiraAPI/Modifiers/ModifierComponent.cs @@ -511,14 +511,14 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr) /// /// Checks if a player has an active modifier by its type. /// - /// Whether to check inactive modifiers (those pending to be added or removed). + /// Whether to check inactive modifiers (those pending to be added). /// The predicate to check the modifier. /// The Type of the Modifier. /// True if the Modifier is present, false otherwise. [HideFromIl2Cpp] public bool HasModifier(bool checkInactive, Func? predicate=null) where T : BaseModifier { - return ActiveModifiers.Exists(MatchExpr) || (checkInactive && (_toAdd.Exists(MatchExpr) || _toRemove.Exists(MatchExpr))); + return ActiveModifiers.Exists(MatchExpr) || (checkInactive && _toAdd.Exists(MatchExpr)); bool MatchExpr(BaseModifier bm) => bm is T modifier && (predicate == null || predicate(modifier)); } @@ -526,13 +526,13 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr) /// Checks if a player has an active modifier by its type. /// /// The modifier type. - /// Whether to check inactive modifiers (those pending to be added or removed). + /// Whether to check inactive modifiers (those pending to be added). /// The predicate to check the modifier. /// True if the Modifier is present, false otherwise. [HideFromIl2Cpp] public bool HasModifier(Type type, bool checkInactive, Func? predicate=null) { - return ActiveModifiers.Exists(MatchExpr) || (checkInactive && (_toAdd.Exists(MatchExpr) || _toRemove.Exists(MatchExpr))); + return ActiveModifiers.Exists(MatchExpr) || (checkInactive && _toAdd.Exists(MatchExpr)); bool MatchExpr(BaseModifier bm) => bm.GetType() == type && (predicate == null || predicate(bm)); } @@ -540,7 +540,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr) /// Checks if a player has an active modifier by its type ID. /// /// The modifier's type ID. - /// Whether to check inactive modifiers (those pending to be added or removed). + /// Whether to check inactive modifiers (those pending to be added). /// The predicate to check the modifier. /// True if the modifier is present, false otherwise. [HideFromIl2Cpp] @@ -556,12 +556,12 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr) /// Checks if a player has an active modifier by its unique ID. /// /// The modifier's guid. - /// Whether to check inactive modifiers (those pending to be added or removed). + /// Whether to check inactive modifiers (those pending to be added). /// True if the modifier is present, false otherwise. [HideFromIl2Cpp] public bool HasModifier(Guid id, bool checkInactive) { - return ActiveModifiers.Exists(MatchExpr) || (checkInactive && (_toAdd.Exists(MatchExpr) || _toRemove.Exists(MatchExpr))); + return ActiveModifiers.Exists(MatchExpr) || (checkInactive && _toAdd.Exists(MatchExpr)); bool MatchExpr(BaseModifier bm) => bm.UniqueId == id; } } From aef4d6daf1d9ffec46a3d58f3ea0fab18352efe3 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Fri, 4 Apr 2025 13:08:35 -0400 Subject: [PATCH 06/12] actually fix meetinghud vote issue --- MiraAPI/Patches/Voting/MeetingHudPatches.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MiraAPI/Patches/Voting/MeetingHudPatches.cs b/MiraAPI/Patches/Voting/MeetingHudPatches.cs index dc5f02b..d873f56 100644 --- a/MiraAPI/Patches/Voting/MeetingHudPatches.cs +++ b/MiraAPI/Patches/Voting/MeetingHudPatches.cs @@ -41,21 +41,21 @@ internal static class MeetingHudPatches [HarmonyPostfix] [HarmonyPatch(nameof(MeetingHud.OnDestroy))] - public static void MeetingHudOnDestroyPatch(MeetingHud __instance) + public static void OnDestroyPatch(MeetingHud __instance) { MiraEventManager.InvokeEvent(new EndMeetingEvent(__instance)); } [HarmonyPostfix] [HarmonyPatch(nameof(MeetingHud.VotingComplete))] - public static void MeetingHudVotingCompletePatch(MeetingHud __instance) + public static void VotingCompletePatch(MeetingHud __instance) { MiraEventManager.InvokeEvent(new VotingCompleteEvent(__instance)); } - [HarmonyPostfix] + [HarmonyPrefix] [HarmonyPatch(nameof(MeetingHud.ForceSkipAll))] - public static void MeetingHudForceSkipAllPatch(MeetingHud __instance) + public static void ForceSkipAllPatch(MeetingHud __instance) { foreach (var plr in PlayerControl.AllPlayerControls) { From 21bec074fac562a79a024d16278aa6ba76da3fa6 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Fri, 4 Apr 2025 18:25:57 -0400 Subject: [PATCH 07/12] improve GetAlivePlayers --- MiraAPI/Utilities/Helpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MiraAPI/Utilities/Helpers.cs b/MiraAPI/Utilities/Helpers.cs index 513789e..7d8ce9b 100644 --- a/MiraAPI/Utilities/Helpers.cs +++ b/MiraAPI/Utilities/Helpers.cs @@ -19,7 +19,7 @@ public static class Helpers /// A list of alive players. public static List GetAlivePlayers() { - return PlayerControl.AllPlayerControls.ToArray().Where(x => !x.Data.IsDead).ToList(); + return [.. GameData.Instance.AllPlayers.ToArray().Where(x => !x.IsDead && !x.Disconnected && x.Object).Select(x=>x.Object)]; } /// From fcb693e89938864a403c38eb7c23877a5fcf5c14 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Fri, 4 Apr 2025 18:26:16 -0400 Subject: [PATCH 08/12] fix modifier adding/removing AGAIN --- MiraAPI/Modifiers/ModifierComponent.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/MiraAPI/Modifiers/ModifierComponent.cs b/MiraAPI/Modifiers/ModifierComponent.cs index 918c1a4..988eac6 100644 --- a/MiraAPI/Modifiers/ModifierComponent.cs +++ b/MiraAPI/Modifiers/ModifierComponent.cs @@ -67,14 +67,18 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr) private void FixedUpdate() { + var removed = _toRemove.Count > 0; foreach (var modifier in _toRemove.ToArray()) { + _toRemove.Remove(modifier); modifier.OnDeactivate(); Modifiers.Remove(modifier); } + var added = _toAdd.Count > 0; foreach (var modifier in _toAdd.ToArray()) { + _toAdd.Remove(modifier); Modifiers.Add(modifier); modifier.Initialized = true; modifier.OnActivate(); @@ -85,14 +89,12 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr) } } - if (_toAdd.Count > 0 || _toRemove.Count > 0) + if (removed || added) { if (_player.AmOwner && HudManager.InstanceExists) { HudManager.Instance.SetHudActive(_player, _player.Data.Role, HudManager.Instance.TaskPanel.isActiveAndEnabled); } - _toAdd.Clear(); - _toRemove.Clear(); ActiveModifiers = Modifiers.ToImmutableList(); } From f1846375ca11209a7cb469d85fa230600d091d28 Mon Sep 17 00:00:00 2001 From: ang-xd Date: Sat, 5 Apr 2025 13:06:35 -0400 Subject: [PATCH 09/12] Fix end game stuff --- .../Patches/Modifiers/EndGameDidWinPatch.cs | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs b/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs index a86383d..1a7046c 100644 --- a/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs +++ b/MiraAPI/Patches/Modifiers/EndGameDidWinPatch.cs @@ -2,13 +2,15 @@ using HarmonyLib; using MiraAPI.Modifiers; using MiraAPI.Modifiers.Types; +using MiraAPI.Utilities; +using Reactor.Utilities; namespace MiraAPI.Patches.Modifiers; -[HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.CoEndGame))] +[HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.OnGameEnd))] public static class EndGameDidWinPatch { - public static void Prefix() + public static void Postfix() { var gameOverReason = EndGameResult.CachedGameOverReason; EndGameResult.CachedWinners.Clear(); @@ -17,18 +19,26 @@ public static class EndGameDidWinPatch for (var i = 0; i < GameData.Instance.PlayerCount; i++) { var networkedPlayerInfo = players[i]; - if (networkedPlayerInfo == null) + if (!networkedPlayerInfo) { continue; } var didWin = networkedPlayerInfo.Role.DidWin(gameOverReason); - var modifierWin = networkedPlayerInfo.Object?.GetModifierComponent().GetModifiers() - .FirstOrDefault(x => x.DidWin(gameOverReason) != null)?.DidWin(gameOverReason); - if (modifierWin != null) + bool? modifierDidWin = null; + foreach (var modifier in networkedPlayerInfo.Object.GetModifiers().OrderByDescending(x => x.Priority())) { - didWin = modifierWin.Value; + var result = modifier.DidWin(gameOverReason); + if (!result.HasValue) continue; + + modifierDidWin = result.Value; + break; + } + + if (modifierDidWin.HasValue) + { + didWin = modifierDidWin.Value; } if (didWin) From ddfad0752d45ac3d4e928471e2ee9e343e748b56 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sat, 5 Apr 2025 14:30:52 -0400 Subject: [PATCH 10/12] proper fix for meeting vote issue (I HATE IL2CPP) --- MiraAPI/Patches/Voting/MeetingHudPatches.cs | 25 +++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/MiraAPI/Patches/Voting/MeetingHudPatches.cs b/MiraAPI/Patches/Voting/MeetingHudPatches.cs index d873f56..316fc7f 100644 --- a/MiraAPI/Patches/Voting/MeetingHudPatches.cs +++ b/MiraAPI/Patches/Voting/MeetingHudPatches.cs @@ -35,6 +35,7 @@ internal static class MeetingHudPatches modifier.OnMeetingStart(); } } + var @event = new StartMeetingEvent(__instance); MiraEventManager.InvokeEvent(@event); } @@ -53,10 +54,30 @@ internal static class MeetingHudPatches MiraEventManager.InvokeEvent(new VotingCompleteEvent(__instance)); } + // this is necessary because the actual ForceSkipAll method is inlined. [HarmonyPrefix] - [HarmonyPatch(nameof(MeetingHud.ForceSkipAll))] - public static void ForceSkipAllPatch(MeetingHud __instance) + [HarmonyPatch(nameof(MeetingHud.Update))] + public static void ForceSkipPatch(MeetingHud __instance) { + if (__instance.state is not (MeetingHud.VoteStates.NotVoted or MeetingHud.VoteStates.Voted)) + { + return; + } + + var logicOptionsNormal = GameManager.Instance.LogicOptions.Cast(); + var votingTime = logicOptionsNormal.GetVotingTime(); + if (votingTime <= 0) + { + return; + } + + var num2 = __instance.discussionTimer - logicOptionsNormal.GetDiscussionTime(); + + if (!AmongUsClient.Instance.AmHost || num2 < votingTime) + { + return; + } + foreach (var plr in PlayerControl.AllPlayerControls) { var voteData = plr.GetVoteData(); From 3e6eb49d933d20e5c6d6ecff345baff7dd97826b Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sat, 5 Apr 2025 15:00:35 -0400 Subject: [PATCH 11/12] fix scroller in freeplay role menu --- MiraAPI/Patches/Freeplay/TaskAdderPatches.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs b/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs index 666a1ea..e06e3f0 100644 --- a/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs +++ b/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs @@ -18,7 +18,7 @@ namespace MiraAPI.Patches.Freeplay; [HarmonyPatch(typeof(TaskAdderGame))] internal static class TaskAdderPatches { - private static Scroller? _scroller; + private static Scroller _scroller = null!; [HarmonyPostfix] [HarmonyPatch(nameof(TaskAdderGame.Begin))] @@ -293,9 +293,9 @@ internal static class TaskAdderPatches chip.GetComponent().maskInteraction = SpriteMaskInteraction.VisibleInsideMask; } - if (_scroller && _scroller != null) + if (_scroller) { - _scroller.CalculateAndSetYBounds(__instance.ActiveItems.Count, 6, 3, 1f); + _scroller.CalculateAndSetYBounds(__instance.ActiveItems.Count, 6, 5, 1.4f); _scroller.SetYBoundsMin(0.0f); _scroller.ScrollToTop(); } From 531a799a24752398f1db53f683bc38c538a75bd0 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sat, 5 Apr 2025 16:28:34 -0400 Subject: [PATCH 12/12] fix double initialization of roles --- MiraAPI.Example/Roles/ChameleonRole.cs | 7 +++++++ MiraAPI/Patches/Roles/RoleManagerPatches.cs | 12 +++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/MiraAPI.Example/Roles/ChameleonRole.cs b/MiraAPI.Example/Roles/ChameleonRole.cs index 52550a3..6f485d7 100644 --- a/MiraAPI.Example/Roles/ChameleonRole.cs +++ b/MiraAPI.Example/Roles/ChameleonRole.cs @@ -1,5 +1,6 @@ using AmongUs.GameOptions; using MiraAPI.Roles; +using Reactor.Utilities; using TMPro; using UnityEngine; @@ -19,6 +20,12 @@ public class ChameloenRole : CrewmateRole, ICustomRole IntroSound = CustomRoleUtils.GetIntroSound(RoleTypes.Shapeshifter), }; + public override void Initialize(PlayerControl player) + { + Player = player; + Logger.Error("Initializing ChamelonRole for player: " + player.PlayerId); + } + public void PlayerControlFixedUpdate(PlayerControl playerControl) { if (playerControl.MyPhysics.Velocity.magnitude > 0) diff --git a/MiraAPI/Patches/Roles/RoleManagerPatches.cs b/MiraAPI/Patches/Roles/RoleManagerPatches.cs index 63ed61a..57512e3 100644 --- a/MiraAPI/Patches/Roles/RoleManagerPatches.cs +++ b/MiraAPI/Patches/Roles/RoleManagerPatches.cs @@ -12,19 +12,19 @@ namespace MiraAPI.Patches.Roles; [HarmonyPatch(typeof(RoleManager))] public static class RoleManagerPatches { - [HarmonyPostfix] + [HarmonyPrefix] [HarmonyPatch(nameof(RoleManager.SetRole))] - public static void SetRolePatch(RoleManager __instance, PlayerControl targetPlayer, RoleTypes roleType) + public static bool SetRolePatch(RoleManager __instance, PlayerControl targetPlayer, RoleTypes roleType) { if (!targetPlayer) { - return; + return false; } var data = targetPlayer.Data; if (data == null) { Debug.LogError("It shouldn't be possible, but " + targetPlayer.name + " still doesn't have PlayerData during role selection."); - return; + return false; } if (data.Role) { @@ -47,7 +47,7 @@ public static class RoleManagerPatches { case true when !targetPlayer.Data.IsDead: targetPlayer.Die(DeathReason.Kill, false); - return; + return false; case false when targetPlayer.Data.IsDead: targetPlayer.Revive(); break; @@ -55,6 +55,8 @@ public static class RoleManagerPatches var @event = new SetRoleEvent(targetPlayer, roleType); MiraEventManager.InvokeEvent(@event); + + return false; } [HarmonyPostfix]