From d5a64de858c9ebc01cedb6ac7fc0af4952b1bf89 Mon Sep 17 00:00:00 2001 From: D1GQ Date: Tue, 18 Aug 2026 22:15:44 -0500 Subject: [PATCH] Fix meeting info not properly being set up on disconnected players --- .../Extended/ExtendedPlayerInfo.cs | 5 +++ src/MonoScripts/MeetingInfoDisplay.cs | 18 +++++----- src/Patches/Gameplay/RolePatch.cs | 13 +++++++ src/Patches/Gameplay/UI/MeetingHudPatch.cs | 2 +- src/Utilities/PlayerControlUtils.cs | 34 ++++++++++++++++--- src/Utilities/RoleUtils.cs | 21 +++++++++--- 6 files changed, 72 insertions(+), 21 deletions(-) diff --git a/src/MonoScripts/Extended/ExtendedPlayerInfo.cs b/src/MonoScripts/Extended/ExtendedPlayerInfo.cs index 4979eb0..1784cd5 100644 --- a/src/MonoScripts/Extended/ExtendedPlayerInfo.cs +++ b/src/MonoScripts/Extended/ExtendedPlayerInfo.cs @@ -226,6 +226,11 @@ internal sealed class ExtendedRoleInfo /// internal int Kills { get; set; } = 0; + /// + /// Gets or sets the player that was judged. + /// + internal PlayerId Judged { get; set; } = PlayerId.Invalid; + /// /// Gets or sets whether noisemaker notification is enabled. /// diff --git a/src/MonoScripts/MeetingInfoDisplay.cs b/src/MonoScripts/MeetingInfoDisplay.cs index 2d54fd5..489f86b 100644 --- a/src/MonoScripts/MeetingInfoDisplay.cs +++ b/src/MonoScripts/MeetingInfoDisplay.cs @@ -17,6 +17,7 @@ namespace BetterAmongUs.MonoScripts; [RegisterInIl2Cpp] internal sealed class MeetingInfoDisplay : PlayerInfoDisplay { + private NetworkedPlayerInfo? _playerInfo; private PlayerVoteArea? _pva; private Vector3 _namePos; private Vector3 _infoPos; @@ -33,9 +34,9 @@ internal sealed class MeetingInfoDisplay : PlayerInfoDisplay /// /// The player to display info for. /// The PlayerVoteArea associated with the player. - internal void Init(PlayerControl? player, PlayerVoteArea pva) + internal void Init(NetworkedPlayerInfo? playerInfo, PlayerVoteArea pva) { - _player = player; + _playerInfo = playerInfo; _pva = pva; _nameText = pva.NameText; @@ -77,7 +78,7 @@ internal sealed class MeetingInfoDisplay : PlayerInfoDisplay _ssbTag.Clear(); _ssbInfo.Clear(); - if (_player != null) + if (_playerInfo.Object != null) { UpdateInfo(); } @@ -138,11 +139,11 @@ internal sealed class MeetingInfoDisplay : PlayerInfoDisplay /// private void UpdateInfo() { - if (_player == null || _player.Data == null || _player.ExtendedData() == null) + if (_playerInfo == null || _playerInfo.ExtendedData() == null) return; SetPlayerTags(_ssbTag); - _ssbInfo.Append(_player.GetRoleInfo(true)); + _ssbInfo.Append(_playerInfo.GetRoleInfo(true)); UpdateNameTextPosition(_ssbInfo.ToString(), _ssbInfo.ToString()); @@ -157,13 +158,10 @@ internal sealed class MeetingInfoDisplay : PlayerInfoDisplay [HideFromIl2Cpp] private void SetPlayerTags(SplitStringBuilder ssbTag) { - if (_player == null) + if (_playerInfo == null) return; - if (_player.Data == null) - return; - - if (BetterDataManager.Files.BetterDataFile.TryGetCheatInfo(_player.Data, out var info)) + if (BetterDataManager.Files.BetterDataFile.TryGetCheatInfo(_playerInfo, out var info)) { ssbTag.Append(info.title.ToColor(info.hexColor)); } diff --git a/src/Patches/Gameplay/RolePatch.cs b/src/Patches/Gameplay/RolePatch.cs index fe57389..e288366 100644 --- a/src/Patches/Gameplay/RolePatch.cs +++ b/src/Patches/Gameplay/RolePatch.cs @@ -1,5 +1,7 @@ using BetterAmongUs.MonoScripts.Extended; +using BetterAmongUs.Utilities; using HarmonyLib; +using InnerNet; namespace BetterAmongUs.Patches.Gameplay; @@ -21,4 +23,15 @@ internal static class RolePatch return true; } + + [HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.SetJudgeOverrule))] + [HarmonyPostfix] + private static void MeetingHud_SetJudgeOverrule_Postfix(MeetingHud __instance, PlayerId judgePlayerId, PlayerId targetPlayerId, ushort overruleNonce) + { + var judge = Utils.PlayerFromPlayerId(judgePlayerId); + if (judge != null) + { + judge.ExtendedData().RoleInfo.Judged = targetPlayerId; + } + } } \ No newline at end of file diff --git a/src/Patches/Gameplay/UI/MeetingHudPatch.cs b/src/Patches/Gameplay/UI/MeetingHudPatch.cs index bcbd944..60274e3 100644 --- a/src/Patches/Gameplay/UI/MeetingHudPatch.cs +++ b/src/Patches/Gameplay/UI/MeetingHudPatch.cs @@ -32,7 +32,7 @@ internal static class MeetingHudPatch { if (pva == null) continue; - var target = Utils.PlayerFromPlayerId(pva.PlayerId); + var target = Utils.PlayerDataFromPlayerId(pva.PlayerId); if (target == null) continue; pva.gameObject.AddComponent().Init(target, pva); diff --git a/src/Utilities/PlayerControlUtils.cs b/src/Utilities/PlayerControlUtils.cs index 128d3b9..709b281 100644 --- a/src/Utilities/PlayerControlUtils.cs +++ b/src/Utilities/PlayerControlUtils.cs @@ -160,7 +160,7 @@ internal static class PlayerControlUtils KickCooldownManager.Trigger(); player.PerformKick(shouldBan, setReasonInfo, antiCheatBan); } - + /// /// Kicks a player from the game immediately, regardless of cooldown. /// Only use this if the target player is extremely dangerous and must be removed immediately. @@ -217,7 +217,7 @@ internal static class PlayerControlUtils shouldBan = ban && BetterGameSettings.WhenCheating.GetStringIndex() == 2; return BetterGameSettings.WhenCheating.GetStringIndex() != 0; } - + /// /// Kicks a player from the game with optional ban and anti-cheat features. /// @@ -293,6 +293,13 @@ internal static class PlayerControlUtils /// True if the player is the local player. internal static bool IsLocalPlayer(this PlayerControl player) => player != null && PlayerControl.LocalPlayer != null && player == PlayerControl.LocalPlayer; + /// + /// Checks if a player data is the local player data. + /// + /// The player data to check. + /// True if the player data is the local player data. + internal static bool IsLocalData(this NetworkedPlayerInfo playerData) => playerData != null && PlayerControl.LocalPlayer != null && playerData == PlayerControl.LocalPlayer.Data; + /// /// Gets the ID of the vent the player is currently in. /// @@ -502,13 +509,30 @@ internal static class PlayerControlUtils /// True if the player is an impostor teammate. internal static bool IsImpostorTeammate(this PlayerControl player) { - if (player == null || PlayerControl.LocalPlayer == null) + if (player == null) + return false; + + var data = player.Data; + if (data == null) + return false; + + return data.IsImpostorTeammate(); + } + + /// + /// Checks if a player data is an impostor teammate of the local player data. + /// + /// The player data to check. + /// True if the player data is an impostor teammate. + internal static bool IsImpostorTeammate(this NetworkedPlayerInfo playerData) + { + if (playerData == null || PlayerControl.LocalPlayer == null) return false; bool localIsImpostor = PlayerControl.LocalPlayer.IsImpostorTeam(); - bool playerIsImpostor = player.IsImpostorTeam(); + bool playerIsImpostor = playerData.IsImpostorTeam(); - return (player.IsLocalPlayer() && localIsImpostor) || + return (playerData.IsLocalData() && localIsImpostor) || (localIsImpostor && playerIsImpostor); } diff --git a/src/Utilities/RoleUtils.cs b/src/Utilities/RoleUtils.cs index 23439ef..1aa33dd 100644 --- a/src/Utilities/RoleUtils.cs +++ b/src/Utilities/RoleUtils.cs @@ -90,13 +90,24 @@ internal static class RoleUtils /// Whether to display the player's task completion progress. /// Returns role info or if the player's role information cannot be displayed. internal static string GetRoleInfo(this PlayerControl player, bool displayTask) + { + return player.Data.GetRoleInfo(displayTask); + } + + /// + /// Gets the role information for a specified player, optionally including task progress. + /// + /// The player data to get role information for. + /// Whether to display the player's task completion progress. + /// Returns role info or if the player's role information cannot be displayed. + internal static string GetRoleInfo(this NetworkedPlayerInfo playerData, bool displayTask) { if (!GameState.IsInGamePlay) { return string.Empty; } - if (!player.IsLocalPlayer() && !player.IsImpostorTeammate()) + if (playerData.PlayerId != PlayerControl.LocalPlayer.PlayerId && !playerData.IsImpostorTeammate()) { if (PlayerControl.LocalPlayer.IsAlive()) { @@ -109,19 +120,19 @@ internal static class RoleUtils } } - string roleInfo = player.GetRoleName().ToColor(player.Data.Role.TeamColor); + string roleInfo = playerData.RoleType.GetRoleName().ToColor(playerData.Role.TeamColor); - if (!player.IsImpostorTeam() && player.myTasks.Count > 0) + if (!playerData.IsImpostorTeam() && playerData.Tasks.Count > 0) { if (displayTask) { int completedTasks = 0; - foreach (var task in player.Data.Tasks) + foreach (var task in playerData.Tasks) { if (task.Complete) completedTasks++; } - roleInfo += $" ({completedTasks}/{player.Data.Tasks.Count})"; + roleInfo += $" ({completedTasks}/{playerData.Tasks.Count})"; } }