From faec32d378c4d7d6208515c359019e8d68e756f7 Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:40:21 +0100
Subject: [PATCH 01/12] Update Utils.cs
---
src/Utilities/Utils.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Utilities/Utils.cs b/src/Utilities/Utils.cs
index a27fd9ed..beb45742 100644
--- a/src/Utilities/Utils.cs
+++ b/src/Utilities/Utils.cs
@@ -20,7 +20,7 @@ public static class Utils
public static bool isLocalGame => AmongUsClient.Instance && AmongUsClient.Instance.NetworkMode == NetworkModes.LocalGame;
public static bool isFreePlay => AmongUsClient.Instance && AmongUsClient.Instance.NetworkMode == NetworkModes.FreePlay;
public static bool isPlayer => PlayerControl.LocalPlayer;
- public static bool isHost = AmongUsClient.Instance && AmongUsClient.Instance.AmHost;
+ public static bool isHost => AmongUsClient.Instance && AmongUsClient.Instance.AmHost; // Check if is host every time instead of once
public static bool isInGame => AmongUsClient.Instance && AmongUsClient.Instance.GameState == InnerNetClient.GameStates.Started && isPlayer;
public static bool isMeeting => MeetingHud.Instance;
public static bool isMeetingVoting => isMeeting && MeetingHud.Instance.state is MeetingHud.VoteStates.Voted or MeetingHud.VoteStates.NotVoted;
From 944275003c375b0cc7ac4d20c82afe401925a483 Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:47:13 +0100
Subject: [PATCH 02/12] Update ConsoleUI.cs
---
src/UI/ConsoleUI.cs | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/UI/ConsoleUI.cs b/src/UI/ConsoleUI.cs
index 076f3c4d..4b188975 100644
--- a/src/UI/ConsoleUI.cs
+++ b/src/UI/ConsoleUI.cs
@@ -33,7 +33,8 @@ private void OnGUI()
logStyle = new GUIStyle(GUI.skin.label)
{
- fontSize = 20
+ fontSize = 20,
+ richText = true // Essential for colored names
};
}
@@ -57,6 +58,10 @@ private void ConsoleWindow(int windowID)
GUILayout.Label(log, logStyle); // Use the custom GUIStyle with the specified font size
}
+ if (GUILayout.Button("Clear Log")){
+ logEntries.Clear();
+ }
+
GUILayout.EndScrollView();
GUILayout.EndVertical();
From a77ae2e97ec275a90ec7b0b26f1af8246d3d03c5 Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:51:21 +0100
Subject: [PATCH 03/12] Create NotificationHandler.cs
---
src/Utilities/NotificationHandler.cs | 119 +++++++++++++++++++++++++++
1 file changed, 119 insertions(+)
create mode 100644 src/Utilities/NotificationHandler.cs
diff --git a/src/Utilities/NotificationHandler.cs b/src/Utilities/NotificationHandler.cs
new file mode 100644
index 00000000..89c22e41
--- /dev/null
+++ b/src/Utilities/NotificationHandler.cs
@@ -0,0 +1,119 @@
+using System.Collections.Generic;
+using UnityEngine;
+using AmongUs.GameOptions;
+
+namespace MalumMenu;
+
+///
+/// Handles the creation and storage of event-based notification logs.
+///
+public static class NotificationHandler
+{
+ private const int MaxLogEntries = 100;
+ private static void AddLog(string message)
+ {
+ ConsoleUI.logEntries.Add(message);
+
+ // Also show the notification on the bottom-left of the screen.
+ if (DestroyableSingleton.InstanceExists && HudManager.Instance.Notifier != null)
+ {
+ // We use AddDisconnectMessage as it's a simple way to show custom text.
+ HudManager.Instance.Notifier.AddDisconnectMessage(message);
+ }
+ }
+
+ ///
+ /// Checks if a player is currently disguised and returns their real and displayed names.
+ ///
+ private static (string realName, string displayName, bool isDisguised) GetPlayerIdentity(PlayerControl player)
+ {
+ if (player == null || player.Data == null) return ("", "", false);
+
+ // Get the real player's name and color from their permanent data
+ string realName = $"{player.Data.PlayerName}";
+
+ // Get the displayed (current outfit) name and color
+ string displayName = $"{player.CurrentOutfit.PlayerName}";
+
+ // A player is disguised if their currently displayed name is different from their real name.
+ // This is the most reliable way to check for shapeshifting on ALL clients,
+ // as the 'CurrentOutfit' is synchronized for rendering purposes, whereas specific
+ // role timers (like durationSecondsRemaining) might not be.
+ bool isDisguised = player.CurrentOutfit.PlayerName != player.Data.PlayerName;
+
+ return (realName, displayName, isDisguised);
+ }
+
+ public static void HandlePlayerKill(PlayerControl killer, PlayerControl victim)
+ {
+ if (!CheatToggles.notifyOnDeath || killer == null || victim == null) return;
+
+ var (realKillerName, displayKillerName, isDisguised) = GetPlayerIdentity(killer);
+ string victimName = $"{victim.CurrentOutfit.PlayerName}";
+
+ PlainShipRoom room = Utils.getRoomFromPosition(victim.GetTruePosition());
+ string roomName = room != null ? room.RoomId.ToString() : "an unknown location";
+
+ string message;
+ if (isDisguised)
+ {
+ message = $"{realKillerName} (as {displayKillerName}) killed {victimName} in {roomName}.";
+ }
+ else
+ {
+ message = $"{realKillerName} killed {victimName} in {roomName}.";
+ }
+ AddLog(message);
+ }
+
+ public static void HandleGuardianAngelSave(PlayerControl killer, PlayerControl target)
+ {
+ if (!CheatToggles.notifyOnDeath || killer == null || target == null) return;
+
+ var (realKillerName, displayKillerName, isDisguised) = GetPlayerIdentity(killer);
+ string targetName = $"{target.CurrentOutfit.PlayerName}";
+
+ PlainShipRoom room = Utils.getRoomFromPosition(target.GetTruePosition());
+ string roomName = room != null ? room.RoomId.ToString() : "an unknown location";
+
+ string message;
+ if (isDisguised)
+ {
+ message = $"{realKillerName} (as {displayKillerName}) tried to kill {targetName} in {roomName}. (Saved)";
+ }
+ else
+ {
+ message = $"{realKillerName} tried to kill {targetName} in {roomName}. (Saved)";
+ }
+ AddLog(message);
+ }
+
+ public static void HandleVent(PlayerControl player, bool entered, string roomName)
+ {
+ if (!CheatToggles.notifyOnVent || player == null) return;
+
+ var (realPlayerName, displayPlayerName, isDisguised) = GetPlayerIdentity(player);
+ string action = entered ? "entered" : "exited";
+
+ string message;
+ if (isDisguised)
+ {
+ message = $"{realPlayerName} (as {displayPlayerName}) has {action} a vent in {roomName}.";
+ }
+ else
+ {
+ message = $"{realPlayerName} has {action} a vent in {roomName}.";
+ }
+ AddLog(message);
+ }
+
+ public static void HandlePlayerDisconnect(NetworkedPlayerInfo player)
+ {
+ if (!CheatToggles.notifyOnDisconnect || player == null) return;
+
+ string playerName = $"{player.PlayerName}";
+
+ string message = $"{playerName} has disconnected.";
+ AddLog(message);
+ }
+}
From 95c408386e14c7682fb9f4006df8cefe0152bebc Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:51:44 +0100
Subject: [PATCH 04/12] Update ConsoleUI.cs
---
src/UI/ConsoleUI.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/UI/ConsoleUI.cs b/src/UI/ConsoleUI.cs
index 4b188975..aa3973f2 100644
--- a/src/UI/ConsoleUI.cs
+++ b/src/UI/ConsoleUI.cs
@@ -7,7 +7,7 @@ public class ConsoleUI : MonoBehaviour
{
public bool isVisible = false;
private Vector2 scrollPosition = Vector2.zero;
- private List logEntries = new List();
+ public static List logEntries = new List();
private Rect windowRect = new Rect(320, 10, 500, 300); // Adjust size and position as needed
private GUIStyle logStyle;
From 18671bd79ed4716c7b9bb2116de1abae25ebf87b Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:54:20 +0100
Subject: [PATCH 05/12] Update MenuUI.cs
---
src/UI/MenuUI.cs | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/src/UI/MenuUI.cs b/src/UI/MenuUI.cs
index 03a79e97..135239a1 100644
--- a/src/UI/MenuUI.cs
+++ b/src/UI/MenuUI.cs
@@ -102,7 +102,7 @@ private void Start()
groups.Add(new GroupInfo("Chat", false, new List() {
new ToggleInfo(" Enable Chat", () => CheatToggles.alwaysChat, x => CheatToggles.alwaysChat = x),
new ToggleInfo(" Unlock Textbox", () => CheatToggles.chatJailbreak, x => CheatToggles.chatJailbreak = x)
- }, new List()));
+ }, []));
// Host-Only cheats are temporarly disabled because of some bugs
@@ -113,12 +113,6 @@ private void Start()
// new ToggleInfo(" VoteImmune", () => CheatSettings.voteImmune, x => CheatSettings.voteImmune = x)
//}, new List()));
- // Console is temporarly disabled until we implement some features for it
-
- //groups.Add(new GroupInfo("Console", false, new List() {
- // new ToggleInfo(" ConsoleUI", () => MalumMenu.consoleUI.isVisible, x => MalumMenu.consoleUI.isVisible = x),
- //}, new List()));
-
groups.Add(new GroupInfo("Host-Only", false,
new List{
new ToggleInfo(" Kill While Vanished", () => CheatToggles.killVanished, x => CheatToggles.killVanished = x),
@@ -139,7 +133,15 @@ private void Start()
new ToggleInfo(" Free Cosmetics", () => CheatToggles.freeCosmetics, x => CheatToggles.freeCosmetics = x),
new ToggleInfo(" Avoid Penalties", () => CheatToggles.avoidBans, x => CheatToggles.avoidBans = x),
new ToggleInfo(" Unlock Extra Features", () => CheatToggles.unlockFeatures, x => CheatToggles.unlockFeatures = x),
- }, new List()));
+ }, []));
+
+ groups.Add(new GroupInfo("Notifications", false, [
+ new ToggleInfo(" Console", () => MalumMenu.consoleUI.isVisible, x => MalumMenu.consoleUI.isVisible = x),
+ new ToggleInfo(" On Player Death", () => CheatToggles.notifyOnDeath, x => CheatToggles.notifyOnDeath = x),
+ new ToggleInfo(" On Player Disconnect", () => CheatToggles.notifyOnDisconnect, x => CheatToggles.notifyOnDisconnect = x),
+ new ToggleInfo(" On Vent Usage", () => CheatToggles.notifyOnVent, x => CheatToggles.notifyOnVent = x),
+ new ToggleInfo(" Show Notification Log", () => CheatToggles.showNotificationLog, x => CheatToggles.showNotificationLog = x)
+ ], []));
}
private void Update(){
From 466b37328d3137725a5d2f54292484d0af319e53 Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:55:42 +0100
Subject: [PATCH 06/12] Update MalumMenu.cs
---
src/MalumMenu.cs | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/src/MalumMenu.cs b/src/MalumMenu.cs
index b7b3e27d..e3531378 100644
--- a/src/MalumMenu.cs
+++ b/src/MalumMenu.cs
@@ -15,10 +15,10 @@ namespace MalumMenu;
public partial class MalumMenu : BasePlugin
{
public Harmony Harmony { get; } = new(Id);
- public static string malumVersion = "2.4.2";
- public static List supportedAU = new List { "2024.9.4" };
+ public static string malumVersion = "2.5.3";
+ public static List supportedAU = new List { "2025.9.9" };
public static MenuUI menuUI;
- // public static ConsoleUI consoleUI;
+ public static ConsoleUI consoleUI;
public static ConfigEntry menuKeybind;
public static ConfigEntry menuHtmlColor;
public static ConfigEntry spoofLevel;
@@ -77,15 +77,16 @@ public override void Load()
Harmony.PatchAll();
menuUI = AddComponent();
- // consoleUI = AddComponent();
+ consoleUI = AddComponent();
- // Disable Telemetry (haven't fully tested if it works, but according to Unity docs it should)
+ // Disable Telemetry (better one)
if (noTelemetry.Value){
-
- Analytics.enabled = false;
Analytics.deviceStatsEnabled = false;
+ Analytics.enabled = false;
+ Analytics.initializeOnStartup = false;
+ Analytics.limitUserTracking = true;
+ CrashReportHandler.enableCaptureExceptions = false;
PerformanceReporting.enabled = false;
-
}
SceneManager.add_sceneLoaded((Action) ((scene, _) =>
From a80c68cd2c18983c8f3149f4ebaaf239bc1d0c94 Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:56:25 +0100
Subject: [PATCH 07/12] Update CheatToggles.cs
---
src/UI/CheatToggles.cs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/UI/CheatToggles.cs b/src/UI/CheatToggles.cs
index ba0211ed..d8e5f665 100644
--- a/src/UI/CheatToggles.cs
+++ b/src/UI/CheatToggles.cs
@@ -89,6 +89,12 @@ public struct CheatToggles
public static bool freeCosmetics = true;
public static bool avoidBans = true;
+ //Notifications
+ public static bool notifyOnDeath;
+ public static bool notifyOnDisconnect;
+ public static bool notifyOnVent;
+ public static bool showNotificationLog;
+
public static void DisablePPMCheats(string variableToKeep)
{
reportBody = variableToKeep != "reportBody" ? false : reportBody;
From 54ee6030dc19c59eec870665bba965da5a4f2835 Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:57:09 +0100
Subject: [PATCH 08/12] Update Utils.cs
---
src/Utilities/Utils.cs | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/src/Utilities/Utils.cs b/src/Utilities/Utils.cs
index beb45742..bb2560b3 100644
--- a/src/Utilities/Utils.cs
+++ b/src/Utilities/Utils.cs
@@ -90,6 +90,19 @@ public static void adjustResolution() {
ResolutionManager.ResolutionChanged.Invoke((float)Screen.width / Screen.height, Screen.width, Screen.height, Screen.fullScreen);
}
+ // Gets the room object from a Vector2 position.
+ public static PlainShipRoom getRoomFromPosition(Vector2 position){
+ if (ShipStatus.Instance == null) return null;
+
+ foreach (var room in ShipStatus.Instance.AllRooms)
+ {
+ if (room != null && room.roomArea != null && room.roomArea.OverlapPoint(position)){
+ return room;
+ }
+ }
+ return null;
+ }
+
// Get RoleBehaviour from a RoleType
public static RoleBehaviour getBehaviourByRoleType(RoleTypes roleType) {
return RoleManager.Instance.AllRoles.First(r => r.Role == roleType);
From 9a03a1db340cc8a581baa2b9e9f272478e95b393 Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:58:30 +0100
Subject: [PATCH 09/12] Update PlayerPhysicsPatches.cs
---
src/Patches/PlayerPhysicsPatches.cs | 44 +++++++++++++++++++++++++----
1 file changed, 39 insertions(+), 5 deletions(-)
diff --git a/src/Patches/PlayerPhysicsPatches.cs b/src/Patches/PlayerPhysicsPatches.cs
index 03f0b35e..bf1e4dbf 100644
--- a/src/Patches/PlayerPhysicsPatches.cs
+++ b/src/Patches/PlayerPhysicsPatches.cs
@@ -1,13 +1,48 @@
using HarmonyLib;
using UnityEngine;
+using System.Collections.Generic;
namespace MalumMenu;
[HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.LateUpdate))]
public static class PlayerPhysics_LateUpdate
{
+ private static readonly Dictionary wasInVent = new();
+ public static readonly Dictionary lastKnownPositions = new();
+
+ public static void ClearAllStates()
+ {
+ wasInVent.Clear();
+ lastKnownPositions.Clear();
+ }
+
public static void Postfix(PlayerPhysics __instance)
{
+ if (__instance.myPlayer != null && !__instance.myPlayer.Data.IsDead)
+ {
+ // Update the player's last known position every frame they are not in a vent.
+ if (!__instance.myPlayer.inVent)
+ {
+ lastKnownPositions[__instance.myPlayer.PlayerId] = __instance.myPlayer.GetTruePosition();
+ }
+
+ // Vent usage detection
+ if (CheatToggles.notifyOnVent && Utils.isInGame)
+ {
+ byte playerId = __instance.myPlayer.PlayerId;
+ bool currentlyInVent = __instance.myPlayer.inVent;
+
+ if (wasInVent.TryGetValue(playerId, out bool previouslyInVent) && currentlyInVent != previouslyInVent)
+ {
+ Vector2 positionToCheck = currentlyInVent ? lastKnownPositions[playerId] : __instance.myPlayer.GetTruePosition();
+ PlainShipRoom room = Utils.getRoomFromPosition(positionToCheck);
+ string roomName = room != null ? room.RoomId.ToString() : "an unknown location";
+
+ NotificationHandler.HandleVent(__instance.myPlayer, currentlyInVent, roomName);
+ }
+ wasInVent[playerId] = currentlyInVent;
+ }
+ }
MalumESP.playerNametags(__instance);
MalumESP.seeGhostsCheat(__instance);
@@ -40,11 +75,10 @@ public static void Postfix(PlayerPhysics __instance)
{
DeadBody deadBody = bodyObject.GetComponent();
- if (deadBody){
- if (!deadBody.Reported){ // Only draw tracers for unreported dead bodies
- TracersHandler.drawBodyTracer(deadBody);
- }
+ if (deadBody && !deadBody.Reported)
+ {
+ TracersHandler.drawBodyTracer(deadBody);
}
}
}
-}
\ No newline at end of file
+}
From c989f99cd45a49b55baa9dd1a0403e280e2b4c8c Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:59:14 +0100
Subject: [PATCH 10/12] Update PlayerControlPatches.cs
---
src/Patches/PlayerControlPatches.cs | 45 +++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/src/Patches/PlayerControlPatches.cs b/src/Patches/PlayerControlPatches.cs
index 36ea7ee0..fa27c8be 100644
--- a/src/Patches/PlayerControlPatches.cs
+++ b/src/Patches/PlayerControlPatches.cs
@@ -1,4 +1,5 @@
using HarmonyLib;
+using System.Collections.Generic;
namespace MalumMenu;
@@ -80,3 +81,47 @@ public static void Prefix(ref bool shouldAnimate){
}
}
}
+
+[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.MurderPlayer))]
+public static class PlayerControl_MurderPlayer_Patch
+{
+ // A HashSet to track victims for whom a notification has already been sent on this client.
+ // This prevents duplicate notifications if the event is somehow triggered more than once.
+ private static readonly HashSet notifiedKilledVictims = new();
+
+ ///
+ /// Clears the set of notified victims. This must be called at the end of each game.
+ ///
+ public static void ClearNotifiedKilledVictims() => notifiedKilledVictims.Clear();
+
+ // A Prefix runs *before* the original method. This lets us check conditions before the kill happens.
+ public static void Prefix(PlayerControl __instance, PlayerControl target)
+ {
+ if (target == null)
+ {
+ return;
+ }
+
+ // Check if the target is protected by a Guardian Angel.
+ if (target.protectedByGuardianId != -1)
+ {
+ // This is a "save" event. Show the notification but do not add the player to the
+ // notifiedKilledVictims set, allowing a future kill notification to appear.
+ NotificationHandler.HandleGuardianAngelSave(__instance, target);
+ }
+ else
+ {
+ // This is a potential kill event. Check if we've already notified for this victim's death.
+ if (notifiedKilledVictims.Contains(target.PlayerId))
+ {
+ return;
+ }
+
+ // If not protected and not already notified, the kill is successful.
+ NotificationHandler.HandlePlayerKill(__instance, target);
+
+ // Add the victim's ID to the set ONLY on a successful kill to prevent duplicate kill notifications.
+ notifiedKilledVictims.Add(target.PlayerId);
+ }
+ }
+}
From 13b361ba0305f90287c628e569e5c5082899797c Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 15:02:25 +0100
Subject: [PATCH 11/12] Update MeetingHudPatches.cs
---
src/Patches/MeetingHudPatches.cs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/Patches/MeetingHudPatches.cs b/src/Patches/MeetingHudPatches.cs
index 275c31da..8deb0db7 100644
--- a/src/Patches/MeetingHudPatches.cs
+++ b/src/Patches/MeetingHudPatches.cs
@@ -96,5 +96,6 @@ public static void Prefix(MeetingHud __instance)
voteSpreader.Votes.Clear();
}
MeetingHud_Update.votedPlayers.Clear();
+ PlayerPhysics_LateUpdate.ClearAllStates();
}
-}
\ No newline at end of file
+}
From 140e6b60cfe920b19ded2afee2420ac3b6c44360 Mon Sep 17 00:00:00 2001
From: ReactorCoreDev <165254059+ReactorCoreDev@users.noreply.github.com>
Date: Tue, 18 Nov 2025 15:03:00 +0100
Subject: [PATCH 12/12] Update OtherPatches.cs
---
src/Patches/OtherPatches.cs | 47 ++++++++++++++++++++++++++++++++++++-
1 file changed, 46 insertions(+), 1 deletion(-)
diff --git a/src/Patches/OtherPatches.cs b/src/Patches/OtherPatches.cs
index c8fb3c36..3d7c579f 100644
--- a/src/Patches/OtherPatches.cs
+++ b/src/Patches/OtherPatches.cs
@@ -3,6 +3,7 @@
using UnityEngine;
using System;
using System.Security.Cryptography;
+using System.Collections.Generic;
namespace MalumMenu;
@@ -227,4 +228,48 @@ public static void Postfix(Vent __instance, NetworkedPlayerInfo pc, ref bool can
}
}
}
-}
\ No newline at end of file
+}
+
+[HarmonyPatch(typeof(GameData), nameof(GameData.RemovePlayer))]
+public static class GameData_RemovePlayer_Patch
+{
+ private static readonly HashSet notifiedDisconnects = new();
+
+ public static void ClearNotifiedDisconnects() => notifiedDisconnects.Clear();
+
+ // Use a Prefix patch to capture the PlayerInfo *before* it gets removed from the game's data lists.
+ public static void Prefix(GameData __instance, byte playerId)
+ {
+ // Only notify during an active game, not in lobby or post-game.
+ if (CheatToggles.notifyOnDisconnect && Utils.isInGame)
+ {
+ // If we've already notified for this player, don't do it again.
+ if (notifiedDisconnects.Contains(playerId))
+ {
+ return;
+ }
+
+ var player = __instance.GetPlayerById(playerId);
+ // The check for `!player.Disconnected` was preventing this from ever firing. It's removed.
+ if (player != null)
+ {
+ NotificationHandler.HandlePlayerDisconnect(player);
+ // Add the player to the set so we don't notify again for this game session.
+ notifiedDisconnects.Add(playerId);
+ }
+ }
+ }
+}
+
+[HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.OnGameEnd))]
+public static class AmongUsClient_OnGameEnd_Patch
+{
+ public static void Postfix()
+ {
+ // Clear the set of notified disconnected players when a game ends.
+ GameData_RemovePlayer_Patch.ClearNotifiedDisconnects();
+
+ // Clear the set of notified killed victims when a game ends.
+ PlayerControl_MurderPlayer_Patch.ClearNotifiedKilledVictims();
+ }
+}