From cbc1bce63ddff5619ec488f162e15a567539a9a7 Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Sun, 2 Jun 2024 18:04:35 +0200 Subject: [PATCH] Fixes + add extensions --- GameMode/HnSManager.cs | 23 +++++- Modules/Debugger.cs | 6 +- Modules/ExtendedPlayerControl.cs | 6 +- Modules/Extensions/CollectionExtensions.cs | 41 +++++++++ Modules/GuessManager.cs | 2 +- Modules/Utils.cs | 11 +-- Patches/HudPatch.cs | 14 +--- Roles/Crewmate/CopyCat.cs | 96 +++++++++++----------- Roles/Neutral/Necromancer.cs | 2 + 9 files changed, 122 insertions(+), 79 deletions(-) diff --git a/GameMode/HnSManager.cs b/GameMode/HnSManager.cs index db5ea4e42..64fd9bfe4 100644 --- a/GameMode/HnSManager.cs +++ b/GameMode/HnSManager.cs @@ -114,7 +114,14 @@ namespace EHR { Dictionary result = []; List allPlayers = [.. Main.AllAlivePlayerControls]; - if (Main.GM.Value) allPlayers.RemoveAll(x => x.IsHost()); + + if (Main.GM.Value) + { + allPlayers.RemoveAll(x => x.IsHost()); + PlayerRoles[0] = (new Hider(), CustomRoles.GM); + PlayerControl.LocalPlayer.RpcSetCustomRole(CustomRoles.GM); + } + allPlayers = allPlayers.Shuffle(); Dictionary memberNum = new() @@ -237,7 +244,14 @@ namespace EHR var targetRole = PlayerRoles[target.PlayerId]; var seerRole = PlayerRoles[seer.PlayerId]; - if (targetRole.Interface.Team == Team.Impostor && (PlayersSeeRoles.GetBool() || targetRole.Role != CustomRoles.Agent || seerRole.Interface.Team == Team.Impostor)) + if (PlayersSeeRoles.GetBool()) + { + color = Main.RoleColors[targetRole.Role]; + if (targetRole.Role == CustomRoles.Agent) color = Main.RoleColors[CustomRoles.Hider]; + return true; + } + + if (targetRole.Interface.Team == Team.Impostor && (targetRole.Role != CustomRoles.Agent || seerRole.Interface.Team == Team.Impostor)) { color = Main.RoleColors[CustomRoles.Seeker]; return true; @@ -254,7 +268,10 @@ namespace EHR public static bool IsRoleTextEnabled(PlayerControl seer, PlayerControl target) { - return seer.PlayerId == target.PlayerId || PlayersSeeRoles.GetBool(); + if (seer.PlayerId == target.PlayerId || PlayersSeeRoles.GetBool()) return true; + var targetRole = PlayerRoles[target.PlayerId]; + var seerRole = PlayerRoles[seer.PlayerId]; + return targetRole.Interface.Team == Team.Impostor && (targetRole.Role != CustomRoles.Agent || seerRole.Interface.Team == Team.Impostor); } public static string GetSuffixText(PlayerControl seer, PlayerControl target, bool isHUD = false) diff --git a/Modules/Debugger.cs b/Modules/Debugger.cs index c09c0a138..aa1448ed7 100644 --- a/Modules/Debugger.cs +++ b/Modules/Debugger.cs @@ -33,6 +33,8 @@ class Logger private static readonly List DisableList = []; private static readonly List SendToGameList = []; public static bool IsAlsoInGame; + + private static readonly HashSet NowDetailedErrorLog = []; public static void Enable() => IsEnable = true; public static void Disable() => IsEnable = false; @@ -69,13 +71,15 @@ class Logger } string log_text; - if (level is LogLevel.Error or LogLevel.Fatal && !multiLine) + if (level is LogLevel.Error or LogLevel.Fatal && !multiLine && !NowDetailedErrorLog.Contains(tag)) { string t = DateTime.Now.ToString("HH:mm:ss"); StackFrame stack = new(2); string className = stack.GetMethod()?.ReflectedType?.Name; string memberName = stack.GetMethod()?.Name; log_text = $"[{t}][{className}.{memberName}({Path.GetFileName(fileName)}:{lineNumber})][{tag}]{text}"; + NowDetailedErrorLog.Add(tag); + LateTask.New(() => NowDetailedErrorLog.Remove(tag), 5f, log: false); } else { diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs index 8acea9568..d8abd5320 100644 --- a/Modules/ExtendedPlayerControl.cs +++ b/Modules/ExtendedPlayerControl.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Text; using AmongUs.GameOptions; using EHR.Modules; -using EHR.Patches; using EHR.Roles.AddOns.Crewmate; using EHR.Roles.AddOns.Impostor; using EHR.Roles.Crewmate; @@ -136,8 +135,6 @@ static class ExtendedPlayerControl Main.LastNotifyNames[(player.PlayerId, seer.PlayerId)] = name; } - HudManagerPatch.LastSetNameDesyncCount++; - Logger.Info($"Set:{player?.Data?.PlayerName}:{name} for All", "RpcSetNameEx"); player?.RpcSetName(name); } @@ -149,7 +146,6 @@ static class ExtendedPlayerControl if (!force && Main.LastNotifyNames[(player.PlayerId, seer.PlayerId)] == name) return; Main.LastNotifyNames[(player.PlayerId, seer.PlayerId)] = name; - HudManagerPatch.LastSetNameDesyncCount++; Logger.Info($"Set:{player.Data?.PlayerName}:{name} for {seer.GetNameWithRole().RemoveHtmlTags()}", "RpcSetNamePrivate"); var clientId = seer.GetClientId(); @@ -661,7 +657,7 @@ static class ExtendedPlayerControl public static bool CanUseImpostorVentButton(this PlayerControl pc) { if (!pc.IsAlive() || pc.Data.Role.Role == RoleTypes.GuardianAngel || Penguin.IsVictim(pc)) return false; - if (CopyCat.PlayerIdList.Contains(pc.PlayerId)) return true; + if (CopyCat.Instances.Any(x => x.CopyCatPC.PlayerId == pc.PlayerId)) return true; if ((pc.Is(CustomRoles.Nimble) || Options.EveryoneCanVent.GetBool()) && pc.GetCustomRole().GetVNRole() != CustomRoles.Engineer) return true; if (pc.Is(CustomRoles.Bloodlust)) return true; diff --git a/Modules/Extensions/CollectionExtensions.cs b/Modules/Extensions/CollectionExtensions.cs index 7ff5d414a..05015f51a 100644 --- a/Modules/Extensions/CollectionExtensions.cs +++ b/Modules/Extensions/CollectionExtensions.cs @@ -115,5 +115,46 @@ namespace EHR { return collection.Where(x => !x.Equals(element)); } + + /// + /// Partitions a collection into a specified number of parts + /// + /// The collection to partition + /// The number of parts to partition the collection into + /// The type of the elements in the collection + /// A collection of collections, each containing a part of the original collection + public static IEnumerable> Partition(this IEnumerable collection, int parts) + { + var list = collection.ToList(); + int size = list.Count / parts; + int remainder = list.Count % parts; + int index = 0; + for (int i = 0; i < parts; i++) + { + int partSize = size + (i < remainder ? 1 : 0); + yield return list.GetRange(index, partSize); + index += partSize; + } + } + + /// + /// Partitions an array into a specified number of parts + /// + /// The array to partition + /// The number of parts to partition the array into + /// The type of the elements in the array + /// An array of arrays, each containing a part of the original array + public static IEnumerable> Partition(this T[] collection, int parts) + { + int size = collection.Length / parts; + int remainder = collection.Length % parts; + int index = 0; + for (int i = 0; i < parts; i++) + { + int partSize = size + (i < remainder ? 1 : 0); + yield return collection.Skip(index).Take(partSize); + index += partSize; + } + } } } \ No newline at end of file diff --git a/Modules/GuessManager.cs b/Modules/GuessManager.cs index b491c213c..5e35c238c 100644 --- a/Modules/GuessManager.cs +++ b/Modules/GuessManager.cs @@ -179,7 +179,7 @@ public static class GuessManager if (target != null) { bool guesserSuicide = false; - if (CopyCat.PlayerIdList.Contains(pc.PlayerId)) + if (CopyCat.Instances.Any(x => x.CopyCatPC.PlayerId == pc.PlayerId)) { if (!isUI) Utils.SendMessage(GetString("GuessDisabled"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDisabled")); diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 650f7628c..86b1f4baa 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -12,7 +12,6 @@ using AmongUs.GameOptions; using EHR.Crewmate; using EHR.Modules; using EHR.Neutral; -using EHR.Patches; using EHR.Roles.AddOns.Common; using EHR.Roles.AddOns.Crewmate; using EHR.Roles.AddOns.GhostRoles; @@ -572,7 +571,7 @@ public static class Utils StackFrame firstFrame = stFrames.FirstOrDefault(); var sb = new StringBuilder(); - sb.Append($" Exception: {ex.Message} ----"); + sb.Append($" Exception: {ex.Message}"); bool skip = true; foreach (StackFrame sf in stFrames) @@ -765,7 +764,7 @@ public static class Utils } } - if (CopyCat.PlayerIdList.Contains(p.PlayerId) && ForRecompute && (!Options.UsePets.GetBool() || CopyCat.UsePet.GetBool())) hasTasks = false; + if (CopyCat.Instances.Any(x => x.CopyCatPC.PlayerId == p.PlayerId) && ForRecompute && (!Options.UsePets.GetBool() || CopyCat.UsePet.GetBool())) hasTasks = false; hasTasks |= role.UsesPetInsteadOfKill(); @@ -1690,7 +1689,7 @@ public static class Utils public static void CheckAndSpawnAdditionalRefugee(GameData.PlayerInfo deadPlayer) { - if (Options.CurrentGameMode != CustomGameMode.Standard || deadPlayer == null || !Options.SpawnAdditionalRefugeeOnImpsDead.GetBool() || Main.AllAlivePlayerControls.Length < Options.SpawnAdditionalRefugeeMinAlivePlayers.GetInt() || CustomRoles.Refugee.RoleExist(countDead: true) || Main.AllAlivePlayerControls.Any(x => x.PlayerId != deadPlayer.PlayerId && (x.Is(CustomRoleTypes.Impostor) || (x.IsNeutralKiller() && !Options.SpawnAdditionalRefugeeWhenNKAlive.GetBool())))) return; + if (Options.CurrentGameMode != CustomGameMode.Standard || deadPlayer == null || deadPlayer.Object.Is(CustomRoles.Refugee) || !Options.SpawnAdditionalRefugeeOnImpsDead.GetBool() || Main.AllAlivePlayerControls.Length < Options.SpawnAdditionalRefugeeMinAlivePlayers.GetInt() || CustomRoles.Refugee.RoleExist(countDead: true) || Main.AllAlivePlayerControls.Any(x => x.PlayerId != deadPlayer.PlayerId && (x.Is(CustomRoleTypes.Impostor) || (x.IsNeutralKiller() && !Options.SpawnAdditionalRefugeeWhenNKAlive.GetBool())))) return; PlayerControl[] ListToChooseFrom = Options.UsePets.GetBool() ? Main.AllAlivePlayerControls.Where(x => x.PlayerId != deadPlayer.PlayerId && x.Is(CustomRoleTypes.Crewmate)).ToArray() : Main.AllAlivePlayerControls.Where(x => x.PlayerId != deadPlayer.PlayerId && x.Is(CustomRoleTypes.Crewmate) && x.GetCustomRole().GetRoleTypes() == RoleTypes.Impostor).ToArray(); @@ -1896,8 +1895,6 @@ public static class Utils //string callerMethodName = callerMethod.Name; //string callerClassName = callerMethod.DeclaringType.FullName; //Logger.Info("NotifyRoles was called from " + callerClassName + "." + callerMethodName, "NotifyRoles"); - HudManagerPatch.NowCallNotifyRolesCount++; - HudManagerPatch.LastSetNameDesyncCount = 0; PlayerControl[] seerList = SpecifySeer != null ? ( [SpecifySeer]) : Main.AllPlayerControls; PlayerControl[] targetList = SpecifyTarget != null ? ( [SpecifyTarget]) : Main.AllPlayerControls; @@ -2509,7 +2506,7 @@ public static class Utils Main.CheckShapeshift[pc.PlayerId] = false; } - CopyCat.ResetRole(); + CopyCat.ResetRoles(); if (Options.DiseasedCDReset.GetBool()) { diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index 3fdab64ee..d52430b64 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -17,22 +17,10 @@ namespace EHR.Patches; [HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))] class HudManagerPatch { - //public static bool ShowDebugText; - //public static int LastCallNotifyRolesPerSecond; - public static int NowCallNotifyRolesCount; - - public static int LastSetNameDesyncCount; - - //public static int LastFPS; - //public static int NowFrameCount; - //public static float FrameRateTimer; - public static TextMeshPro LowerInfoText; - + private static TextMeshPro LowerInfoText; private static TextMeshPro OverriddenRolesText; - private static long LastNullError; - //public static GameObject TempLowerInfoText; public static void Postfix(HudManager __instance) { try diff --git a/Roles/Crewmate/CopyCat.cs b/Roles/Crewmate/CopyCat.cs index 0abacf813..49730cb5d 100644 --- a/Roles/Crewmate/CopyCat.cs +++ b/Roles/Crewmate/CopyCat.cs @@ -8,16 +8,19 @@ namespace EHR.Roles.Crewmate; public class CopyCat : RoleBase { private const int Id = 666420; - public static List PlayerIdList = []; + public static List Instances = []; - public float CurrentKillCooldown = DefaultKillCooldown; + private static OptionItem KillCooldown; + private static OptionItem CanKill; + private static OptionItem CopyCrewVar; + private static OptionItem MiscopyLimitOpt; + public static OptionItem UsePet; + + public PlayerControl CopyCatPC; + private float CurrentKillCooldown = DefaultKillCooldown; private float TempLimit; - public static OptionItem KillCooldown; - public static OptionItem CanKill; - public static OptionItem CopyCrewVar; - public static OptionItem MiscopyLimitOpt; - public static OptionItem UsePet; + public override bool IsEnable => Instances.Count > 0; public static void SetupCustomOption() { @@ -33,13 +36,14 @@ public class CopyCat : RoleBase public override void Init() { - PlayerIdList = []; + Instances = []; CurrentKillCooldown = DefaultKillCooldown; } public override void Add(byte playerId) { - PlayerIdList.Add(playerId); + Instances.Add(this); + CopyCatPC = Utils.GetPlayerById(playerId); CurrentKillCooldown = KillCooldown.GetFloat(); playerId.SetAbilityUseLimit(MiscopyLimitOpt.GetInt()); @@ -48,52 +52,46 @@ public class CopyCat : RoleBase Main.ResetCamPlayerList.Add(playerId); } - public override bool IsEnable => PlayerIdList.Count > 0; - public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = Utils.GetPlayerById(id).IsAlive() ? CurrentKillCooldown : 0f; + public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = CurrentKillCooldown; + public override bool CanUseKillButton(PlayerControl pc) => pc.IsAlive(); - public override bool CanUseKillButton(PlayerControl pc) + void ResetRole() { - return pc.IsAlive(); - } - - public static void ResetRole() - { - foreach (var player in PlayerIdList) + var role = CopyCatPC.GetCustomRole(); + // Remove the settings for current role + switch (role) { - var pc = Utils.GetPlayerById(player); - var role = pc.GetCustomRole(); - //////////// /*remove the settings for current role*/ ///////////////////// - switch (role) - { - case CustomRoles.Cleanser: - Cleanser.DidVote.Remove(pc.PlayerId); - break; - case CustomRoles.Merchant: - Merchant.addonsSold.Remove(player); - Merchant.bribedKiller.Remove(player); - break; - case CustomRoles.Paranoia: - Paranoia.ParaUsedButtonCount.Remove(player); - break; - case CustomRoles.Snitch: - Snitch.IsExposed.Remove(player); - Snitch.IsComplete.Remove(player); - break; - case CustomRoles.Mayor: - Mayor.MayorUsedButtonCount.Remove(player); - break; - } - - pc.RpcSetCustomRole(CustomRoles.CopyCat); - if (Main.PlayerStates[player].Role is CopyCat cc) - { - pc.SetAbilityUseLimit(cc.TempLimit); - cc.SetKillCooldown(player); - } + case CustomRoles.Cleanser: + Cleanser.DidVote.Remove(CopyCatPC.PlayerId); + break; + case CustomRoles.Merchant: + Merchant.addonsSold.Remove(CopyCatPC.PlayerId); + Merchant.bribedKiller.Remove(CopyCatPC.PlayerId); + break; + case CustomRoles.Paranoia: + Paranoia.ParaUsedButtonCount.Remove(CopyCatPC.PlayerId); + break; + case CustomRoles.Snitch: + Snitch.IsExposed.Remove(CopyCatPC.PlayerId); + Snitch.IsComplete.Remove(CopyCatPC.PlayerId); + break; + case CustomRoles.Mayor: + Mayor.MayorUsedButtonCount.Remove(CopyCatPC.PlayerId); + break; } + + Main.PlayerStates[CopyCatPC.PlayerId].MainRole = CustomRoles.CopyCat; + Main.PlayerStates[CopyCatPC.PlayerId].Role = this; + CopyCatPC.SetAbilityUseLimit(TempLimit); + SetKillCooldown(CopyCatPC.PlayerId); } - public static bool BlacklList(CustomRoles role) => role is + public static void ResetRoles() + { + Instances.Do(x => x.ResetRole()); + } + + private static bool BlacklList(CustomRoles role) => role is CustomRoles.CopyCat or // can't copy due to vent cooldown CustomRoles.Grenadier or diff --git a/Roles/Neutral/Necromancer.cs b/Roles/Neutral/Necromancer.cs index 226e046d4..caf97bbdd 100644 --- a/Roles/Neutral/Necromancer.cs +++ b/Roles/Neutral/Necromancer.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using AmongUs.GameOptions; +using EHR.Modules; using static EHR.Options; using static EHR.Translator; @@ -153,6 +154,7 @@ namespace EHR.Roles.Neutral { DeathknightId = playerId; Deathknight_ = Utils.GetPlayerById(playerId); + if (!UsePets.GetBool()) Deathknight_.ChangeRoleBasis(RoleTypes.Impostor); if (!AmongUsClient.Instance.AmHost) return; if (!Main.ResetCamPlayerList.Contains(playerId))