From e2ab725fd82fc50ffdf699f4a047b2dac140e2fa Mon Sep 17 00:00:00 2001 From: D1GQ Date: Thu, 11 Dec 2025 01:24:55 -0600 Subject: [PATCH 1/4] Fix memory leak and rework zoom --- Managers/NetworkManager.cs | 4 +- Modules/AntiCheat/BetterAntiCheat.cs | 34 +++++-- Modules/AntiCheat/RPCHandler.cs | 12 +-- .../RPCHandlers/UpdateSystemHandler.cs | 3 + Modules/Zoom.cs | 95 ------------------- Patches/Gameplay/ZoomPatch.cs | 81 ++++++++++++++++ 6 files changed, 117 insertions(+), 112 deletions(-) delete mode 100644 Modules/Zoom.cs create mode 100644 Patches/Gameplay/ZoomPatch.cs diff --git a/Managers/NetworkManager.cs b/Managers/NetworkManager.cs index 39c5136..f92beef 100644 --- a/Managers/NetworkManager.cs +++ b/Managers/NetworkManager.cs @@ -111,7 +111,9 @@ internal class NetworkManager MessageReader messageReader = parentReader.ReadMessageAsNewBuffer(); int currentMessageNumber = InnerNetClient.msgNum++; InnerNetClient.StartCoroutine(HandleGameDataInner(messageReader, currentMessageNumber)); - RPCHandler.HandleRPC(parentReader.Tag, null, MessageReader.Get(parentReader), HandlerFlag.HandleGameDataTag); + var oldReader = MessageReader.Get(messageReader); + RPCHandler.HandleRPC(parentReader.Tag, null, oldReader, HandlerFlag.HandleGameDataTag); + oldReader.Recycle(); } } finally diff --git a/Modules/AntiCheat/BetterAntiCheat.cs b/Modules/AntiCheat/BetterAntiCheat.cs index d53ed3d..2168b55 100644 --- a/Modules/AntiCheat/BetterAntiCheat.cs +++ b/Modules/AntiCheat/BetterAntiCheat.cs @@ -113,23 +113,23 @@ class BetterAntiCheat // Handle RPC before anti cheat detection internal static void HandleCheatRPCBeforeCheck(PlayerControl player, byte callId, MessageReader oldReader) { - MessageReader reader = MessageReader.Get(oldReader); - if (!IsEnabled) return; + MessageReader reader = MessageReader.Get(oldReader); RPCHandler.HandleRPC(callId, player, reader, HandlerFlag.CheatRpcCheck); + reader.Recycle(); } // Check and notify for invalid rpcs internal static void CheckRPC(PlayerControl player, byte callId, MessageReader oldReader) { - MessageReader reader = MessageReader.Get(oldReader); - - if (player == null || player?.Data == null || reader == null) return; + if (player == null || player?.Data == null) return; if (!IsEnabled || !BAUPlugin.AntiCheat.Value || (GameState.IsBetterHostLobby && !GameState.IsHost) || !BetterGameSettings.DetectInvalidRPCs.GetBool()) return; if (player.IsLocalPlayer() && player.IsHost()) return; + MessageReader reader = MessageReader.Get(oldReader); RPCHandler.HandleRPC(callId, player, reader, HandlerFlag.AntiCheat); + reader.Recycle(); } // Check notify and cancel out request for invalid rpcs @@ -137,20 +137,22 @@ class BetterAntiCheat { try { - MessageReader reader = MessageReader.Get(oldReader); - - if (player == null || player?.Data == null || reader == null) return true; + if (player == null || player?.Data == null) return true; if (!IsEnabled || !BAUPlugin.AntiCheat.Value || (GameState.IsBetterHostLobby && !GameState.IsHost) || !BetterGameSettings.DetectInvalidRPCs.GetBool()) return true; if (player.IsLocalPlayer() && player.IsHost()) return true; + MessageReader reader = MessageReader.Get(oldReader); + if (TrustedRPCs(callId) != true && !player.IsHost()) { BetterNotificationManager.NotifyCheat(player, $"Unregistered RPC received: {callId}"); + reader.Recycle(); return false; } if (RPCHandler.HandleRPC(callId, player, reader, HandlerFlag.AntiCheatCancel) == false) { + reader.Recycle(); return false; } @@ -164,6 +166,8 @@ class BetterAntiCheat { Logger.LogCheat($"{player.BetterData().RealName} {Enum.GetName((RpcCalls)callId)}: {!player.IsHost()}"); } + + reader.Recycle(); return false; } } @@ -181,6 +185,8 @@ class BetterAntiCheat { Logger.LogCheat($"{player.BetterData().RealName} {Enum.GetName((RpcCalls)callId)}: {GameState.IsInGamePlay}"); } + + reader.Recycle(); return false; } } @@ -219,10 +225,14 @@ class BetterAntiCheat { Logger.LogCheat($"{player.BetterData().RealName} {Enum.GetName((RpcCalls)callId)}: {GameState.IsInGame} && {GameState.IsLobby}"); } + + reader.Recycle(); return false; } } + reader.Recycle(); + return true; } catch (Exception ex) @@ -238,8 +248,8 @@ class BetterAntiCheat if (player == null || player?.Data == null || player.IsLocalPlayer()) return; MessageReader reader = MessageReader.Get(oldReader); - RPCHandler.HandleRPC(callId, player, reader, HandlerFlag.Handle); + reader.Recycle(); } // Check game states when sabotaging @@ -256,8 +266,12 @@ class BetterAntiCheat bool notCanceled = RPCHandler.HandleRPC((byte)RpcCalls.UpdateSystem, player, reader, HandlerFlag.AntiCheatCancel); if (!notCanceled) { - Logger.LogCheat($"RPC canceled by Anti-Cheat: {Enum.GetName(typeof(SystemTypes), (int)systemType)} - {MessageReader.Get(reader).ReadByte()}"); + var tempReader = MessageReader.Get(reader); + Logger.LogCheat($"RPC canceled by Anti-Cheat: {Enum.GetName(typeof(SystemTypes), (int)systemType)} - {tempReader.ReadByte()}"); + tempReader.Recycle(); } + + reader.Recycle(); return notCanceled; } diff --git a/Modules/AntiCheat/RPCHandler.cs b/Modules/AntiCheat/RPCHandler.cs index 7ef8160..2256641 100644 --- a/Modules/AntiCheat/RPCHandler.cs +++ b/Modules/AntiCheat/RPCHandler.cs @@ -48,11 +48,11 @@ internal abstract class RPCHandler { try { - if (handlerFlag == HandlerFlag.Handle) handler.Handle(sender, MessageReader.Get(reader)); - else if (handlerFlag == HandlerFlag.AntiCheatCancel) cancel = !handler.HandleAntiCheatCancel(sender, MessageReader.Get(reader)); - else if (handlerFlag == HandlerFlag.AntiCheat) handler.HandleAntiCheat(sender, MessageReader.Get(reader)); - else if (handlerFlag == HandlerFlag.CheatRpcCheck) handler.HandleCheatRpcCheck(sender, MessageReader.Get(reader)); - else if (handlerFlag == HandlerFlag.BetterHost) cancel = !handler.BetterHandle(sender, MessageReader.Get(reader)); + if (handlerFlag == HandlerFlag.Handle) handler.Handle(sender, reader); + else if (handlerFlag == HandlerFlag.AntiCheatCancel) cancel = !handler.HandleAntiCheatCancel(sender, reader); + else if (handlerFlag == HandlerFlag.AntiCheat) handler.HandleAntiCheat(sender, reader); + else if (handlerFlag == HandlerFlag.CheatRpcCheck) handler.HandleCheatRpcCheck(sender, reader); + else if (handlerFlag == HandlerFlag.BetterHost) cancel = !handler.BetterHandle(sender, reader); if (!(cancel)) break; } catch @@ -63,7 +63,7 @@ internal abstract class RPCHandler { try { - handler.HandleGameData(MessageReader.Get(reader)); + handler.HandleGameData(reader); } catch (Exception ex) { diff --git a/Modules/AntiCheat/RPCHandlers/UpdateSystemHandler.cs b/Modules/AntiCheat/RPCHandlers/UpdateSystemHandler.cs index 5bc0b0e..730f487 100644 --- a/Modules/AntiCheat/RPCHandlers/UpdateSystemHandler.cs +++ b/Modules/AntiCheat/RPCHandlers/UpdateSystemHandler.cs @@ -62,10 +62,13 @@ internal sealed class UpdateSystemHandler : RPCHandler if (systemHandlers.TryGetValue(systemKey, out var handler)) { + oldReader.Recycle(); return handler.Invoke(sender, system, oldReader, count); } } + oldReader.Recycle(); + return true; } diff --git a/Modules/Zoom.cs b/Modules/Zoom.cs deleted file mode 100644 index 70030e3..0000000 --- a/Modules/Zoom.cs +++ /dev/null @@ -1,95 +0,0 @@ -using AmongUs.GameOptions; -using BetterAmongUs.Helpers; -using HarmonyLib; -using UnityEngine; - -namespace BetterAmongUs.Modules; - -[HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))] -internal static class Zoom -{ - private static bool resetButtons = false; - - internal static void Postfix() - { - if (GameState.IsCanMove && !PlayerControl.LocalPlayer.Is(RoleTypes.GuardianAngel) && (!GameState.IsInGamePlay || !PlayerControl.LocalPlayer.IsAlive())) - { - if (Camera.main.orthographicSize > 3.0f) - resetButtons = true; - - if (Input.mouseScrollDelta.y > 0 && Camera.main.orthographicSize > 3.0f) - { - SetZoomSize(times: false); - } - else if (Input.mouseScrollDelta.y < 0 && (GameState.IsDead || GameState.IsFreePlay || GameState.IsLobby) && - Camera.main.orthographicSize < 18.0f) - { - SetZoomSize(times: true); - } - - Flag.NewFlag("Zoom"); - } - else - { - Flag.Run(() => SetZoomSize(reset: true), "Zoom"); - } - } - - private static void SetZoomSize(bool times = false, bool reset = false) - { - float size = times ? 1.5f : 1 / 1.5f; - - if (reset) - { - Camera.main.orthographicSize = 3.0f; - HudManager.Instance.UICamera.orthographicSize = 3.0f; - HudManager.Instance.Chat.transform.localScale = Vector3.one; - if (GameState.IsMeeting) - MeetingHud.Instance.transform.localScale = Vector3.one; - } - else - { - Camera.main.orthographicSize *= size; - HudManager.Instance.UICamera.orthographicSize *= size; - } - - HudManager.Instance?.ShadowQuad?.gameObject?.SetActive((reset || Camera.main.orthographicSize == 3.0f) && PlayerControl.LocalPlayer.IsAlive()); - - if (resetButtons) - { - ResolutionManager.ResolutionChanged.Invoke((float)Screen.width / Screen.height, Screen.width, Screen.height, Screen.fullScreen); - resetButtons = false; - } - } - - internal static void OnFixedUpdate() => HudManager.Instance?.ShadowQuad?.gameObject?.SetActive(Camera.main.orthographicSize == 3.0f && PlayerControl.LocalPlayer.IsAlive()); -} - -internal static class Flag -{ - private static readonly List oneTimeList = []; - private static readonly List firstRunList = []; - - internal static void Run(Action action, string type, bool firstrun = false) - { - if (oneTimeList.Contains(type) || firstrun && !firstRunList.Contains(type)) - { - if (!firstRunList.Contains(type)) - firstRunList.Add(type); - - oneTimeList.Remove(type); - action(); - } - } - - internal static void NewFlag(string type) - { - if (!oneTimeList.Contains(type)) - oneTimeList.Add(type); - } - - internal static void DeleteFlag(string type) - { - oneTimeList.Remove(type); - } -} \ No newline at end of file diff --git a/Patches/Gameplay/ZoomPatch.cs b/Patches/Gameplay/ZoomPatch.cs new file mode 100644 index 0000000..2d1e488 --- /dev/null +++ b/Patches/Gameplay/ZoomPatch.cs @@ -0,0 +1,81 @@ +using AmongUs.GameOptions; +using BetterAmongUs.Helpers; +using BetterAmongUs.Modules; +using HarmonyLib; +using UnityEngine; + +namespace BetterAmongUs.Patches.Gameplay; + +[HarmonyPatch] +internal class ZoomPatch +{ + private static bool _wasZooming = false; + private static bool _shouldResetButtons = false; + + [HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))] + [HarmonyPostfix] + private static void Update_Postfix() + { + bool canZoom = GameState.IsCanMove && + !PlayerControl.LocalPlayer.Is(RoleTypes.GuardianAngel) && + (!GameState.IsInGamePlay || !PlayerControl.LocalPlayer.IsAlive()); + + bool shouldReset = !canZoom && _wasZooming; + + if (shouldReset) + { + SetZoomSize(reset: true); + _wasZooming = false; + } + else if (canZoom) + { + _wasZooming = true; + + if (Camera.main.orthographicSize > 3.0f) + _shouldResetButtons = true; + + if (Input.mouseScrollDelta.y > 0 && Camera.main.orthographicSize > 3.0f) + { + SetZoomSize(zoomIn: true); + } + else if (Input.mouseScrollDelta.y < 0 && + (GameState.IsDead || GameState.IsFreePlay || GameState.IsLobby) && + Camera.main.orthographicSize < 18.0f) + { + SetZoomSize(zoomOut: true); + } + } + } + + private static void SetZoomSize(bool zoomIn = false, bool zoomOut = false, bool reset = false) + { + if (reset) + { + Camera.main.orthographicSize = 3.0f; + HudManager.Instance.UICamera.orthographicSize = 3.0f; + HudManager.Instance.Chat.transform.localScale = Vector3.one; + + if (GameState.IsMeeting) + MeetingHud.Instance.transform.localScale = Vector3.one; + } + else if (zoomIn || zoomOut) + { + float size = zoomIn ? 1 / 1.5f : 1.5f; + Camera.main.orthographicSize *= size; + HudManager.Instance.UICamera.orthographicSize *= size; + } + + HudManager.Instance?.ShadowQuad?.gameObject?.SetActive( + (reset || Camera.main.orthographicSize == 3.0f) && + PlayerControl.LocalPlayer.IsAlive()); + + if (_shouldResetButtons) + { + ResolutionManager.ResolutionChanged.Invoke( + (float)Screen.width / Screen.height, + Screen.width, Screen.height, + Screen.fullScreen); + _shouldResetButtons = false; + } + } +} From a23982e5519f66af1c4d0951d50d21edbdbee2dd Mon Sep 17 00:00:00 2001 From: D1GQ Date: Mon, 5 Jan 2026 20:51:58 -0600 Subject: [PATCH 2/4] Update AU Version and add trust Itch.io assembly --- BetterAmongUs.csproj | 2 +- Modules/FileChecker.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BetterAmongUs.csproj b/BetterAmongUs.csproj index f5c6958..f503ee8 100644 --- a/BetterAmongUs.csproj +++ b/BetterAmongUs.csproj @@ -12,7 +12,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Modules/FileChecker.cs b/Modules/FileChecker.cs index 900130f..94b5946 100644 --- a/Modules/FileChecker.cs +++ b/Modules/FileChecker.cs @@ -17,7 +17,7 @@ class FileChecker "System", "Unity", "Harmony", "BepInEx", "Microsoft", "Il2Cpp", "Hazel", "AppleAuth", "QRCoder", "MonoMod", "netstandard", "mscorlib", "AssetRipper", "Cpp2IL", "AsmResolver", "Iced", "CsvHelper", "SemanticVersioning", "Mono.Cecil", "Assembly-CSharp", "StableNameDotNet", "AmongUsCaching", - "Disarm", "Gee.External.Capstone", "Rewired_Core", "AddressablesPlayAssetDelivery", "Newtonsoft.Json", + "Disarm", "Gee.External.Capstone", "Rewired_Core", "AddressablesPlayAssetDelivery", "Newtonsoft.Json", "Purchasing.Common", "Assembly-CSharp-firstpass", "Sentry", "Rewired_Windows", "__Generated", "XGamingRuntime", "BetterAmongUs", "MCI", "CrowdedMod", "Mini.RegionInstall", "Unlock", "Skin" }); From 38d5ad178f91809927917ea19960aecde4e2d959 Mon Sep 17 00:00:00 2001 From: D1GQ Date: Mon, 5 Jan 2026 20:55:19 -0600 Subject: [PATCH 3/4] Fix cheater label bypassing shapeshift --- ModInfo.cs | 4 ++-- Mono/PlayerInfoDisplay.cs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ModInfo.cs b/ModInfo.cs index 2967ec8..0bd015c 100644 --- a/ModInfo.cs +++ b/ModInfo.cs @@ -3,13 +3,13 @@ internal static class ModInfo { internal static readonly ReleaseTypes ReleaseBuildType = ReleaseTypes.Beta; - internal const string BetaNum = "2"; + internal const string BetaNum = "3"; internal const string HotfixNum = "0"; internal const bool IsHotFix = false; internal const string PluginName = "BetterAmongUs"; internal const string PluginGuid = "com.d1gq.betteramongus"; internal const string PluginVersion = "1.3.1"; - internal const string ReleaseDate = "12.05.2025"; // mm/dd/yyyy + internal const string ReleaseDate = "01.05.2026"; // mm/dd/yyyy internal const string Github = "https://github.com/D1GQ/BetterAmongUs-Public"; internal const string Discord = "https://discord.gg/vjYrXpzNAn"; } \ No newline at end of file diff --git a/Mono/PlayerInfoDisplay.cs b/Mono/PlayerInfoDisplay.cs index d55614a..07059ff 100644 --- a/Mono/PlayerInfoDisplay.cs +++ b/Mono/PlayerInfoDisplay.cs @@ -140,7 +140,10 @@ internal class PlayerInfoDisplay : MonoBehaviour platform = _cachedTranslations.PlatformHidden; } - SetPlayerOutline(_sbTag); + if (!_player.IsInShapeshift()) + { + SetPlayerOutline(_sbTag); + } if (GameState.IsInGame && GameState.IsLobby && !GameState.IsFreePlay) { From 7d7fdc12c99251d3cdce13fc4ca2782f58f94560 Mon Sep 17 00:00:00 2001 From: D1GQ Date: Thu, 8 Jan 2026 14:26:55 -0600 Subject: [PATCH 4/4] update info --- ModInfo.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ModInfo.cs b/ModInfo.cs index 0bd015c..8c2886f 100644 --- a/ModInfo.cs +++ b/ModInfo.cs @@ -3,13 +3,13 @@ internal static class ModInfo { internal static readonly ReleaseTypes ReleaseBuildType = ReleaseTypes.Beta; - internal const string BetaNum = "3"; - internal const string HotfixNum = "0"; - internal const bool IsHotFix = false; + internal const string BetaNum = "2"; + internal const string HotfixNum = "1"; + internal const bool IsHotFix = true; internal const string PluginName = "BetterAmongUs"; internal const string PluginGuid = "com.d1gq.betteramongus"; internal const string PluginVersion = "1.3.1"; - internal const string ReleaseDate = "01.05.2026"; // mm/dd/yyyy + internal const string ReleaseDate = "01.08.2026"; // mm/dd/yyyy internal const string Github = "https://github.com/D1GQ/BetterAmongUs-Public"; internal const string Discord = "https://discord.gg/vjYrXpzNAn"; } \ No newline at end of file