diff --git a/EHR.csproj b/EHR.csproj index 6fd4fe060..3c8da82eb 100644 --- a/EHR.csproj +++ b/EHR.csproj @@ -7,7 +7,7 @@ EHR Gurge44 preview - D:\AmongUs + C:\Program Files\Epic Games\AmongUs true True $(MSBuildProjectName) diff --git a/Modules/AntiBlackout.cs b/Modules/AntiBlackout.cs index e3fbb63a4..bf19807cf 100644 --- a/Modules/AntiBlackout.cs +++ b/Modules/AntiBlackout.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.CompilerServices; using AmongUs.GameOptions; using EHR.Modules; @@ -53,12 +54,12 @@ public static class AntiBlackout if (Options.CurrentGameMode is CustomGameMode.Speedrun or CustomGameMode.SoloKombat or CustomGameMode.FFA or CustomGameMode.CaptureTheFlag or CustomGameMode.KingOfTheZones) { - sender.RpcSetRole(seer, RoleTypes.Impostor, seer.OwnerId, noRpcForSelf: true); + sender.RpcSetRole(seer, RoleTypes.Impostor, seer.OwnerId, noRpcForSelf: false); foreach (PlayerControl target in Main.AllPlayerControls) { if (target.PlayerId != seer.PlayerId) - sender.RpcSetRole(target, RoleTypes.Crewmate, seer.OwnerId, noRpcForSelf: true); + sender.RpcSetRole(target, RoleTypes.Crewmate, seer.OwnerId, noRpcForSelf: false); } hasValue = true; @@ -72,9 +73,9 @@ public static class AntiBlackout foreach (PlayerControl target in Main.AllPlayerControls) { if (seerIsAliveAndHasKillButton) - sender.RpcSetRole(target, target.PlayerId != seer.PlayerId ? RoleTypes.Crewmate : selfRoleType, seer.GetClientId(), noRpcForSelf: true); + sender.RpcSetRole(target, target.PlayerId != seer.PlayerId ? RoleTypes.Crewmate : selfRoleType, seer.GetClientId(), noRpcForSelf: false); else - sender.RpcSetRole(target, target.PlayerId == dummyImp.PlayerId ? RoleTypes.Impostor : RoleTypes.Crewmate, seer.GetClientId(), noRpcForSelf: true); + sender.RpcSetRole(target, target.PlayerId == dummyImp.PlayerId ? RoleTypes.Impostor : RoleTypes.Crewmate, seer.GetClientId(), noRpcForSelf: false); hasValue = true; RestartMessageIfTooLong(); @@ -186,9 +187,9 @@ public static class AntiBlackout { if (CustomWinnerHolder.WinnerTeam != CustomWinner.Default) return; - var hasValue = false; - - var sender = CustomRpcSender.Create("AntiBlackout.SetRealPlayerRoles", SendOption.Reliable); + byte[] keys = Main.AllPlayerControls.Select(x => x.PlayerId).Concat(Main.PlayerStates.Keys).Append(byte.MaxValue).ToArray(); + Dictionary senders = keys.ToDictionary(x => x, _ => CustomRpcSender.Create("AntiBlackout.SetRealPlayerRoles", SendOption.Reliable)); + Dictionary hasValue = keys.ToDictionary(x => x, _ => false); List selfExiled = []; @@ -230,28 +231,32 @@ public static class AntiBlackout continue; } - sender.RpcSetRole(target, changedRoleType, seer.OwnerId, noRpcForSelf: true); - hasValue = true; - RestartMessageIfTooLong(); + senders[seer.PlayerId].RpcSetRole(target, changedRoleType, seer.OwnerId, noRpcForSelf: false); + hasValue[seer.PlayerId] = true; + RestartMessageIfTooLong(seer.PlayerId); } foreach (PlayerControl pc in selfExiled) { + CustomRpcSender sender = senders[byte.MaxValue]; sender.AutoStartRpc(pc.NetId, (byte)RpcCalls.Exiled); sender.EndRpc(); - hasValue = true; + hasValue[byte.MaxValue] = true; if (!pc.IsModdedClient() && pc.PlayerId == ExileControllerWrapUpPatch.LastExiled?.PlayerId) { + sender = senders[pc.PlayerId]; sender.AutoStartRpc(pc.NetId, (byte)RpcCalls.MurderPlayer, pc.OwnerId); sender.WriteNetObject(pc); sender.Write((int)MurderResultFlags.Succeeded); sender.EndRpc(); + + hasValue[pc.PlayerId] = true; pc.ReactorFlash(0.2f); } - RestartMessageIfTooLong(); + RestartMessageIfTooLong(byte.MaxValue, pc.PlayerId); } break; @@ -265,25 +270,28 @@ public static class AntiBlackout { foreach (PlayerControl pc in Main.AllPlayerControls) { - sender.RpcSetRole(pc, RoleTypes.Crewmate, pc.OwnerId, noRpcForSelf: true); - RestartMessageIfTooLong(); + senders[pc.PlayerId].RpcSetRole(pc, RoleTypes.Crewmate, pc.OwnerId, noRpcForSelf: false); + hasValue[pc.PlayerId] = true; + RestartMessageIfTooLong(pc.PlayerId); if (pc.IsModdedClient()) continue; if (!pc.IsAlive()) { + CustomRpcSender sender = senders[pc.PlayerId]; sender.AutoStartRpc(pc.NetId, (byte)RpcCalls.MurderPlayer, pc.OwnerId); sender.WriteNetObject(pc); sender.Write((int)MurderResultFlags.Succeeded); sender.EndRpc(); + + hasValue[pc.PlayerId] = true; pc.ReactorFlash(0.2f); } - RestartMessageIfTooLong(); + RestartMessageIfTooLong(pc.PlayerId); } - hasValue = true; break; } case CustomGameMode.FFA: @@ -291,13 +299,19 @@ public static class AntiBlackout case CustomGameMode.CaptureTheFlag: case CustomGameMode.KingOfTheZones: { - sender.RpcSetRole(PlayerControl.LocalPlayer, RoleTypes.Crewmate, noRpcForSelf: true); - RestartMessageIfTooLong(); + senders[byte.MaxValue].RpcSetRole(PlayerControl.LocalPlayer, RoleTypes.Crewmate, noRpcForSelf: false); + hasValue[byte.MaxValue] = true; + RestartMessageIfTooLong(byte.MaxValue); foreach (PlayerControl pc in Main.AllPlayerControls) { + CustomRpcSender sender = senders[pc.PlayerId]; + if (pc.IsAlive()) - sender.RpcSetRole(pc, RoleTypes.Impostor, pc.OwnerId, noRpcForSelf: true); + { + sender.RpcSetRole(pc, RoleTypes.Impostor, pc.OwnerId, noRpcForSelf: false); + hasValue[pc.PlayerId] = true; + } else { if (pc.IsModdedClient()) continue; @@ -305,37 +319,45 @@ public static class AntiBlackout sender.WriteNetObject(pc); sender.Write((int)MurderResultFlags.Succeeded); sender.EndRpc(); + + hasValue[pc.PlayerId] = true; pc.ReactorFlash(0.2f); } - RestartMessageIfTooLong(); + RestartMessageIfTooLong(pc.PlayerId); } - hasValue = true; break; } } foreach (PlayerControl pc in Main.AllPlayerControls) { - hasValue |= sender.RpcResetAbilityCooldown(pc); - hasValue |= sender.SetKillCooldown(pc); - RestartMessageIfTooLong(); + CustomRpcSender sender = senders[pc.PlayerId]; + hasValue[pc.PlayerId] |= sender.RpcResetAbilityCooldown(pc); + hasValue[pc.PlayerId] |= sender.SetKillCooldown(pc); + RestartMessageIfTooLong(pc.PlayerId); } - sender.SendMessage(!hasValue); + senders.Do(x => x.Value.SendMessage(dispose: !hasValue[x.Key])); return; - void RestartMessageIfTooLong() + void RestartMessageIfTooLong(params List ids) { - if (sender.stream.Length > 800) + foreach (var kvp in senders) { - sender.SendMessage(); - sender = CustomRpcSender.Create("AntiBlackout.SetRealPlayerRoles", SendOption.Reliable); - hasValue = false; + if (!ids.Contains(kvp.Key)) continue; + + if (kvp.Value.stream.Length > 800) + { + kvp.Value.SendMessage(); + hasValue[kvp.Key] = false; + } } + + ids.ForEach(x => senders[x] = CustomRpcSender.Create("AntiBlackout.SetRealPlayerRoles", SendOption.Reliable)); } } diff --git a/Modules/Utils.cs b/Modules/Utils.cs index ba084f294..4efca35fe 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -1053,7 +1053,9 @@ public static class Utils switch (Options.CurrentGameMode) { case CustomGameMode.MoveAndStop: return GetTaskCount(playerId, comms, AmongUsClient.Instance.AmHost); - case CustomGameMode.Speedrun: return string.Empty; + case CustomGameMode.Speedrun: + case CustomGameMode.Standard when Forger.Forges.ContainsKey(playerId) && Main.PlayerStates.TryGetValue(playerId, out var state) && state.IsDead: + return string.Empty; } StringBuilder progressText = new(); @@ -1072,7 +1074,8 @@ public static class Utils progressText.Append($" <#00ffa5>{totalCompleted}<#ffffff>/{GameData.Instance.TotalTasks}"); } - if (progressText.Length != 0 && !progressText.ToString().RemoveHtmlTags().StartsWith(' ')) progressText.Insert(0, ' '); + if (progressText.Length != 0 && !progressText.ToString().RemoveHtmlTags().StartsWith(' ')) + progressText.Insert(0, ' '); return progressText.ToString(); } @@ -2345,8 +2348,6 @@ public static class Utils if (!GameStates.IsLobby) { - if (AntiBlackout.SkipTasks && seer.IsAlive()) SelfSuffix.AppendLine(GetString("AntiBlackoutSkipTasks")); - if (!CustomGameMode.Standard.IsActiveOrIntegrated()) goto GameMode0; SelfMark.Append(Snitch.GetWarningArrow(seer)); diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index 47e590e65..7029ae837 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -417,9 +417,10 @@ internal static class ChatCommands if (!player.IsLocalPlayer()) ChatManager.SendPreviousMessagesToAll(); - Forger.Forges[targetId] = forgeRole; - player.RpcRemoveAbilityUse(); + + Forger.Forges[targetId] = forgeRole; + Utils.SendMessage("\n", player.PlayerId, string.Format(GetString("ForgeSuccess"), (int)Math.Round(player.GetAbilityUseLimit(), 1), targetId.ColoredPlayerName(), forgeRole.ToColoredString())); } private static void ChemistInfoCommand(PlayerControl player, string text, string[] args) diff --git a/Patches/ClientPatch.cs b/Patches/ClientPatch.cs index 0634a0609..64560a831 100644 --- a/Patches/ClientPatch.cs +++ b/Patches/ClientPatch.cs @@ -283,9 +283,8 @@ public static class InnerNetClientPatch { if (playerinfo.IsIncomplete) { - Logger.Info($"Disconnecting Client [{client.Id}]{client.PlayerName} {client.FriendCode} for playerinfo timeout", "DelayedNetworkedData"); - AmongUsClient.Instance.SendLateRejection(client.Id, DisconnectReasons.ClientTimeout); - __instance.OnPlayerLeft(client, DisconnectReasons.ClientTimeout); + Logger.Warn($"Disconnecting Client [{client.Id}]{client.PlayerName} {client.FriendCode} for playerinfo timeout", "DelayedNetworkedData"); + AmongUsClient.Instance.KickPlayer(client.Id, false); } } } @@ -304,8 +303,7 @@ public static class InnerNetClientPatch if (player.Data == null || player.Data.IsIncomplete) { Logger.Info($"Disconnecting Client [{client.Id}]{client.PlayerName} {client.FriendCode} for playercontrol timeout", "DelayedNetworkedData"); - AmongUsClient.Instance.SendLateRejection(client.Id, DisconnectReasons.ClientTimeout); - __instance.OnPlayerLeft(client, DisconnectReasons.ClientTimeout); + AmongUsClient.Instance.KickPlayer(client.Id, false); } } } diff --git a/Patches/PhantomRolePatch.cs b/Patches/PhantomRolePatch.cs index df073ee64..e05016a52 100644 --- a/Patches/PhantomRolePatch.cs +++ b/Patches/PhantomRolePatch.cs @@ -96,7 +96,7 @@ public static class PhantomRolePatch foreach (PlayerControl target in Main.AllPlayerControls) { - if (!target.IsAlive() || phantom == target || target.AmOwner || !target.HasDesyncRole()) continue; + if (!target.IsAlive() || phantom.PlayerId == target.PlayerId || target.AmOwner || !target.HasDesyncRole()) continue; int clientId = target.GetClientId(); @@ -107,10 +107,7 @@ public static class PhantomRolePatch } else { - writer.AutoStartRpc(phantom.NetId, (byte)RpcCalls.SetRole, clientId); - writer.Write((ushort)RoleTypes.Phantom); - writer.Write(true); - writer.EndRpc(); + writer.RpcSetRole(phantom, RoleTypes.Phantom, clientId); writer.AutoStartRpc(phantom.NetId, (byte)RpcCalls.CheckVanish, clientId); writer.Write(0); // not used, lol @@ -129,7 +126,7 @@ public static class PhantomRolePatch foreach (PlayerControl target in Main.AllPlayerControls) { - if (GameStates.IsMeeting || phantom == null) return; + if (GameStates.IsMeeting || phantom == null || target.PlayerId == phantom.PlayerId) return; int clientId = target.GetClientId(); string petId = phantom.Data.DefaultOutfit.PetId; @@ -198,7 +195,7 @@ public static class PhantomRolePatch foreach (PlayerControl target in Main.AllPlayerControls) { - if (!target.IsAlive() || phantom == target || target.AmOwner || !target.HasDesyncRole()) continue; + if (!target.IsAlive() || phantom.PlayerId == target.PlayerId || target.AmOwner || !target.HasDesyncRole()) continue; sender.RpcSetRole(phantom, RoleTypes.Phantom, target.GetClientId()); hasValue = true; } @@ -238,16 +235,16 @@ public static class PhantomRolePatch foreach (PlayerControl target in Main.AllPlayerControls) { - if (GameStates.IsMeeting || phantom == null) return; + if (GameStates.IsMeeting || phantom == null || target.PlayerId == phantom.PlayerId) return; + + int clientId = target.GetClientId(); InvisibilityList.Remove(phantom); - sender.RpcSetRole(phantom, RoleTypes.Scientist, target.GetClientId()); + sender.RpcSetRole(phantom, RoleTypes.Scientist, clientId); hasValue = true; if (PetsList.TryGetValue(phantom.PlayerId, out string petId)) { - int clientId = target.GetClientId(); - if (clientId != -1) { if (AmongUsClient.Instance.ClientId == clientId) diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json index b3028fe4e..ee52e1493 100644 --- a/Resources/Lang/en_US.json +++ b/Resources/Lang/en_US.json @@ -2577,6 +2577,7 @@ "XORSameRole": "<#ff0000>X XOR combinations must have 2 different roles.", "XORAdditionRole": "<#ff0000>X XOR combinations don't support add-ons. Use <#ffff00>/combo for that.", "XORAdded": "<#00ffa5>✓ XOR combination added successfully.", + "ForgeSuccess": "<#00ffa5>✓ Successfully forged {1} as {2}.\\nYou have {0} ability uses left.", "ThankYouForUsingEHR": "Thank you for using EHR!", "GMRoles": "【 ★ Roles ★ 】", "ImpostorRoles": "【 ★ Impostor Roles ★ 】", diff --git a/Roles/Coven/CovenLeader.cs b/Roles/Coven/CovenLeader.cs index 6ac5c7696..4bcefaccf 100644 --- a/Roles/Coven/CovenLeader.cs +++ b/Roles/Coven/CovenLeader.cs @@ -48,6 +48,16 @@ public class CovenLeader : Coven protected override void OnReceiveNecronomicon() { - CovenLeaderId.GetPlayer().ResetKillCooldown(); + CovenLeaderId.GetPlayer()?.ResetKillCooldown(); + } + + public override void AfterMeetingTasks() + { + if (!HasNecronomicon) return; + + float kcd = Options.CovenLeaderKillCooldown.GetFloat() / 2f; + + if (Main.KillTimers[CovenLeaderId] > kcd) + CovenLeaderId.GetPlayer()?.SetKillCooldown(kcd); } } \ No newline at end of file