diff --git a/Main.cs b/Main.cs index 6d11e6199..b62b6e63f 100644 --- a/Main.cs +++ b/Main.cs @@ -201,6 +201,7 @@ public class Main : BasePlugin public static ConfigEntry UnlockFps { get; private set; } public static ConfigEntry ShowFps { get; private set; } public static ConfigEntry AutoStart { get; private set; } + public static ConfigEntry AutoPlayAgain { get; private set; } public static ConfigEntry ForceOwnLanguage { get; private set; } public static ConfigEntry ForceOwnLanguageRoleName { get; private set; } public static ConfigEntry EnableCustomButton { get; private set; } @@ -359,6 +360,7 @@ public class Main : BasePlugin UnlockFps = Config.Bind("Client Options", "UnlockFPS", false); ShowFps = Config.Bind("Client Options", "ShowFPS", false); AutoStart = Config.Bind("Client Options", "AutoStart", false); + AutoPlayAgain = Config.Bind("Client Options", "AutoPlayAgain", false); ForceOwnLanguage = Config.Bind("Client Options", "ForceOwnLanguage", false); ForceOwnLanguageRoleName = Config.Bind("Client Options", "ForceOwnLanguageRoleName", false); EnableCustomButton = Config.Bind("Client Options", "EnableCustomButton", true); diff --git a/Modules/Debugger.cs b/Modules/Debugger.cs index dfeae04b9..9ba56cbb5 100644 --- a/Modules/Debugger.cs +++ b/Modules/Debugger.cs @@ -106,7 +106,7 @@ internal static class Logger if (!Main.Loaded) { - LateTask.New(() => CustomLogger.Instance.Log(level.ToString(), LogText, multiLine), 1f, "Log Retry"); + LateTask.New(() => CustomLogger.Instance.Log(level.ToString(), LogText, multiLine), 1f, log: false); return; } diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index d69675e1f..3e9b41f8d 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -436,7 +436,7 @@ public static class Options public static OptionItem MareHasIncreasedSpeed; public static OptionItem MareSpeedDuringLightsOut; - public static OptionItem AutoPlayAgain; + //public static OptionItem AutoPlayAgain; public static OptionItem AutoPlayAgainCountdown; public static OptionItem AutoStartTimer; @@ -1682,10 +1682,10 @@ public static class Options AutoStartTimer = new IntegerOptionItem(44423, "AutoStartTimer", new(10, 600, 1), 20, TabGroup.SystemSettings) .SetValueFormat(OptionFormat.Seconds); - AutoPlayAgain = new BooleanOptionItem(44424, "AutoPlayAgain", false, TabGroup.SystemSettings); + //AutoPlayAgain = new BooleanOptionItem(44424, "AutoPlayAgain", false, TabGroup.SystemSettings); - AutoPlayAgainCountdown = new IntegerOptionItem(44425, "AutoPlayAgainCountdown", new(1, 90, 1), 10, TabGroup.SystemSettings) - .SetParent(AutoPlayAgain); + AutoPlayAgainCountdown = new IntegerOptionItem(44425, "AutoPlayAgainCountdown", new(1, 90, 1), 10, TabGroup.SystemSettings); + //.SetParent(AutoPlayAgain); AutoGMPollCommandAfterJoin = new BooleanOptionItem(19309, "AutoGMPollCommandAfterJoin", false, TabGroup.SystemSettings) .SetHeader(true); diff --git a/Patches/ClientOptionsPatch.cs b/Patches/ClientOptionsPatch.cs index b71a384b6..039ecf340 100644 --- a/Patches/ClientOptionsPatch.cs +++ b/Patches/ClientOptionsPatch.cs @@ -15,6 +15,7 @@ public static class OptionsMenuBehaviourStartPatch private static ClientOptionItem UnlockFPS; private static ClientOptionItem ShowFPS; private static ClientOptionItem AutoStart; + private static ClientOptionItem AutoPlayAgain; private static ClientOptionItem ForceOwnLanguage; private static ClientOptionItem ForceOwnLanguageRoleName; private static ClientOptionItem EnableCustomButton; @@ -88,6 +89,9 @@ public static class OptionsMenuBehaviourStartPatch } } + if (AutoPlayAgain == null || !AutoPlayAgain.ToggleButton) + AutoPlayAgain = ClientOptionItem.Create("AutoPlayAgain", Main.AutoPlayAgain, __instance); + if (ForceOwnLanguage == null || !ForceOwnLanguage.ToggleButton) ForceOwnLanguage = ClientOptionItem.Create("ForceOwnLanguage", Main.ForceOwnLanguage, __instance); diff --git a/Patches/EndGameManagerPatch.cs b/Patches/EndGameManagerPatch.cs index 754908745..ae230ce3a 100644 --- a/Patches/EndGameManagerPatch.cs +++ b/Patches/EndGameManagerPatch.cs @@ -1,3 +1,5 @@ +using System; +using System.Linq; using HarmonyLib; using InnerNet; using TMPro; @@ -7,62 +9,74 @@ using static EHR.Translator; namespace EHR.Patches; [HarmonyPatch(typeof(EndGameManager), nameof(EndGameManager.ShowButtons))] -public static class EndGameManagerPatch +public static class EndGameManagerPatch { private static GameObject CountdownText; private static bool IsRestarting { get; set; } - public static void Postfix(EndGameManager __instance) + public static void Postfix(EndGameManager __instance) { GameEndChecker.LoadingEndScreen = false; - if (!AmongUsClient.Instance.AmHost || !Options.AutoPlayAgain.GetBool()) return; + if (!Main.AutoPlayAgain.Value) return; - IsRestarting = false; - - LateTask.New(() => - { + if (CountdownText != null) GameObject.Destroy(CountdownText); + IsRestarting = true; + + int startSeconds = AmongUsClient.Instance.AmHost ? Options.AutoPlayAgainCountdown.GetInt() : 10; + + LateTask.New(() => { Logger.Msg("Beginning Auto Play Again Countdown!", "AutoPlayAgain"); - IsRestarting = true; - BeginAutoPlayAgainCountdown(__instance, Options.AutoPlayAgainCountdown.GetInt()); - }, 0.5f, "Auto Play Again"); + BeginAutoPlayAgainCountdown(__instance, startSeconds); + }, AmongUsClient.Instance.AmHost ? 0.5f : 1.5f, "Auto Play Again"); } - private static void BeginAutoPlayAgainCountdown(EndGameManager endGameManager, int seconds) + private static void BeginAutoPlayAgainCountdown(EndGameManager endGameManager, int seconds) { - if (!IsRestarting) return; + if (!IsRestarting || endGameManager == null || endGameManager.Navigation == null) { CleanupText(); return; } - if (endGameManager == null) return; - - EndGameNavigation navigation = endGameManager.Navigation; - if (navigation == null) return; - - if (seconds == Options.AutoPlayAgainCountdown.GetInt()) + if (CountdownText == null) { - CountdownText = new("CountdownText") - { - transform = - { - position = new(0f, 2.5f, 10f) - } - }; - - var countdownTextTMP = CountdownText.AddComponent(); - countdownTextTMP.text = string.Format(GetString("CountdownText"), seconds); - countdownTextTMP.alignment = TextAlignmentOptions.Center; - countdownTextTMP.fontSize = 3f; - } - else - { - var countdownTextTMP = CountdownText.GetComponent(); - countdownTextTMP.text = string.Format(GetString("CountdownText"), seconds); + CountdownText = new GameObject("CountdownText") { transform = { position = new Vector3(0f, 2.5f, 10f) } }; + var tmp = CountdownText.AddComponent(); + tmp.alignment = TextAlignmentOptions.Center; + tmp.fontSize = 3f; } - if (seconds == 0) + CountdownText.GetComponent().text = string.Format(GetString("CountdownText"), seconds); + + if (seconds <= 0) { - navigation.NextGame(); - CountdownText.transform.DestroyChildren(); + if (AmongUsClient.Instance.AmHost) endGameManager.Navigation.NextGame(); + else ClickPlayAgain(); + + CleanupText(); + } + else LateTask.New(() => BeginAutoPlayAgainCountdown(endGameManager, seconds - 1), 1f, log: false); + } + + private static void ClickPlayAgain() + { + var btn = Object.FindObjectsOfType().FirstOrDefault(x => x.gameObject.name == "PlayAgainButton"); + if (btn == null) { Logger.Warn("PlayAgainButton not found.", "AutoPlayAgain"); return; } + + try + { + btn.OnClick.Invoke(); + Logger.Info("Successfully invoked PlayAgainButton click event.", "AutoPlayAgain"); } - else LateTask.New(() => { BeginAutoPlayAgainCountdown(endGameManager, seconds - 1); }, 1f, log: false); + catch (Exception ex) + { + Logger.Warn($"Direct click invocation failed: {ex.Message}. Attempting mechanical click fallback.", "AutoPlayAgain"); + try { btn.ReceiveClickDown(); btn.ReceiveClickUp(); } catch { } + } + } + + private static void CleanupText() + { + IsRestarting = false; + if (CountdownText == null) return; + GameObject.Destroy(CountdownText); + CountdownText = null; } } diff --git a/README.md b/README.md index 22f0bee34..acf8ba612 100644 --- a/README.md +++ b/README.md @@ -180,26 +180,27 @@ You can also report bugs and suggest features in the #bug-reports and #suggestio | Rabbit | Trapster | Stalker | | Stressed | | Randomizer | Trickster | Starspawn | | Swift | | Retributionist | Twister | Cultist | | Sunglasses | -| Rhapsode | Undertaker | Sunnyboy | | Talkative | -| Ricochet | Vampire | Tank | | Taskcounter | -| Safeguard | Venerer | Technician | | Task Master | -| Scanner | Ventriloquist | Terrorist | | Tiebreaker | -| Scout | Vindicator | Thanos | | Tired | -| Security Guard | Visionary | Thief | | Torch | -| Sensor | Warlock | Tiger | | Truant | -| Sentinel | Wasp | Traitor | | Unbound | -| Sentry | Wildling | Tremor | | Undead | -| Sheriff | Wiper | Vector | | Underdog | -| Shiftguard | Witch | Vengeance | | Unlucky | -| Snitch | Yin Yanger | Vengeful Romantic | | Urgent | -| Socialite | Zombie | Virus | | Venom | -| Soothsayer | | Vortex | | Warden | -| Spiritualist | | Vulture | | Watcher | -| Speedrunner | | Wraith | | Workhorse | -| Speed Booster | | Werewolf | | YouTuber | -| Spy | | Weapon Master | | | -| Super Star | | Weatherman | | | -| Survivor | | Workaholic | | | +| Revenant | Undertaker | Sunnyboy | | Talkative | +| Rhapsode | Vampire | Tank | | Taskcounter | +| Ricochet | Venerer | Technician | | Task Master | +| Safeguard | Ventriloquist | Terrorist | | Tiebreaker | +| Scanner | Vindicator | Thanos | | Tired | +| Scout | Visionary | Thief | | Torch | +| Security Guard | Warlock | Tiger | | Truant | +| Sensor | Wasp | Traitor | | Unbound | +| Sentinel | Wildling | Tremor | | Undead | +| Sentry | Wiper | Vector | | Underdog | +| Sheriff | Witch | Vengeance | | Unlucky | +| Shiftguard | Yin Yanger | Vengeful Romantic | | Urgent | +| Snitch | Zombie | Virus | | Venom | +| Socialite | | Vortex | | Warden | +| Soothsayer | | Vulture | | Watcher | +| Spiritualist | | Wraith | | Workhorse | +| Speedrunner | | Werewolf | | YouTuber | +| Speed Booster | | Weapon Master | | | +| Spy | | Weatherman | | | +| Super Star | | Workaholic | | | +| Survivor | | | | | | Swapper | | | | | | Tar | | | | | | Task Manager | | | | | @@ -224,7 +225,7 @@ You can also report bugs and suggest features in the #bug-reports and #suggestio | Witness | | | | | | Wizard | | | | | | | | | | | -| 143 | 113 | 120 | 21 | 117 | +| 144 | 113 | 120 | 21 | 117 | ## VIP, Moderator, and Admin perks @@ -398,7 +399,8 @@ Click this badge to view our translation project: | /xor | Specify 2 roles that will never spawn in the same game. | 🔸 **role** – A main role that will never spawn in the same game with the other role
🔸 **role** – A main role that will never spawn in the same game with the other role
| :purple_circle: Everyone | :purple_square: Always | :x: | | /ci
/chemistinfo | Show all processes available for the Chemist role. | – | :purple_circle: Everyone | :purple_square: Always | :x: | | /forge | As the Forger, forge a fake role for a player. | 🔸 **id** – The player's ID to forge a fake role for
🔸 **role** – The fake role to forge
| :purple_circle: Everyone | :yellow_square: In Meetings | :heavy_check_mark: | -| /choose
/pick | Choose your role as the Pawn after completing all tasks. | 🔸 **role** – The role to choose
| :purple_circle: Everyone | :yellow_square: In Meetings | :heavy_check_mark: | +| /choose
/pick | Choose your role as the Changeling, or as the Pawn after completing all tasks. | 🔸 **role** – The role to choose
| :purple_circle: Everyone | :yellow_square: In Meetings | :heavy_check_mark: | +| /mark | Mark a target as the Markseeker. | 🔸 **id** – The player's ID to mark as the target
| :purple_circle: Everyone | :yellow_square: In Meetings | :heavy_check_mark: | | /copypreset
/presetcopy
/cpp | Copy all settings from a preset to another preset. | 🔸 **sourcepreset** – The preset to copy all settings from
🔸 **targetpreset** – The preset to paste all settings to
| :yellow_circle: Host | :green_square: In Lobby | :x: | | /addadmin | Add a player to the list of admins | 🔸 **id** – The player's ID to add to the list of admins
| :yellow_circle: Host | :purple_square: Always | :x: | | /deleteadmin | Remove a player from the list of admins | 🔸 **id** – The player's ID to remove from the list of admins
| :yellow_circle: Host | :purple_square: Always | :x: | @@ -552,6 +554,12 @@ Click this badge to view our translation project: > - Reference: Custom Region Installer (adding modded regions) > +### :star: [AutoRejoin](https://github.com/Maxi0fc/AutoRejoin) : + +> +> - Reference: Auto Rejoin +> + ### :star: [Crowded](https://github.com/CrowdedMods/CrowdedMod) > diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json index bef779122..bc12b4e76 100644 --- a/Resources/Lang/en_US.json +++ b/Resources/Lang/en_US.json @@ -8686,8 +8686,8 @@ "MaxWaitAutoStart": "Force start when Lobby Timer goes below (in minutes)", "PlayerAutoStart": "Minimum Player Threshold to auto-start", "AutoStartTimer": "Initial Countdown for auto-starting", - "AutoPlayAgain": "Auto Re-Enter Lobby after Game End", - "AutoPlayAgainCountdown": "Delay before Auto Re-Entering Lobby", + "AutoPlayAgain": "Auto Rejoin", + "AutoPlayAgainCountdown": "Delay before Auto Rejoining Lobby (Only works as the Host)", "AutoGMPollCommandAfterJoin": "Auto Execute /gmpoll After Joining The Lobby", "AutoGMPollCommandCooldown": "Delay Before Auto Executing /gmpoll (After Joining The Lobby)", "AutoMPollCommandAfterJoin": "Auto Execute /mpoll After Joining The Lobby", diff --git a/Roles/Standard/Crewmate/Investigate/Inquirer.cs b/Roles/Standard/Crewmate/Investigate/Inquirer.cs index 7d3acaf88..1fb27816e 100644 --- a/Roles/Standard/Crewmate/Investigate/Inquirer.cs +++ b/Roles/Standard/Crewmate/Investigate/Inquirer.cs @@ -74,7 +74,7 @@ public class Inquirer : RoleBase public static void ProcessGuesserUI(byte playerId, CustomRoles role) { PlayerControl pc = Utils.GetPlayerById(playerId); - if (!pc || !pc.IsAlive() || !pc.Is(CustomRoles.Inquirer) || Starspawn.IsDayBreak) return; + if (!pc || !pc.IsAlive() || !PlayerControl.LocalPlayer.Is(CustomRoles.Inquirer) || Starspawn.IsDayBreak) return; var command = $"/check {playerId} {GetString(role.ToString())}"; diff --git a/Roles/Standard/Impostor/Concealing/Forger.cs b/Roles/Standard/Impostor/Concealing/Forger.cs index 278707b0f..24375082a 100644 --- a/Roles/Standard/Impostor/Concealing/Forger.cs +++ b/Roles/Standard/Impostor/Concealing/Forger.cs @@ -67,7 +67,7 @@ public class Forger : RoleBase public static void ProcessGuesserUI(byte playerId, CustomRoles role) { PlayerControl pc = Utils.GetPlayerById(playerId); - if (!pc || !pc.IsAlive() || !pc.Is(CustomRoles.Forger) || Starspawn.IsDayBreak) return; + if (!pc || !pc.IsAlive() || !PlayerControl.LocalPlayer.Is(CustomRoles.Forger) || Starspawn.IsDayBreak) return; var command = $"/forge {playerId} {GetString(role.ToString())}"; diff --git a/Roles/Standard/Impostor/Miscellaneous/Loner.cs b/Roles/Standard/Impostor/Miscellaneous/Loner.cs index fb698b68e..9b7a3cb6b 100644 --- a/Roles/Standard/Impostor/Miscellaneous/Loner.cs +++ b/Roles/Standard/Impostor/Miscellaneous/Loner.cs @@ -90,7 +90,7 @@ public class Loner : RoleBase public static void ProcessGuesserUI(byte playerId, CustomRoles role) { PlayerControl pc = Utils.GetPlayerById(playerId); - if (!pc || !pc.IsAlive() || !pc.Is(CustomRoles.Loner) || Starspawn.IsDayBreak) return; + if (!pc || !pc.IsAlive() || !PlayerControl.LocalPlayer.Is(CustomRoles.Loner) || Starspawn.IsDayBreak) return; var command = $"/select {playerId} {GetString(role.ToString())}";