From 3a276c481ee1c5a29759e428cf1bee903cb80604 Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Sun, 25 Jan 2026 12:01:08 +0100 Subject: [PATCH] new welcome template & return unicode digit replacement + fixes --- Modules/CustomNetObject.cs | 9 +++++-- Modules/TemplateManager.cs | 4 ++- Modules/Utils.cs | 36 ++++++++++++++++++++++++++- Patches/ChatCommandPatch.cs | 8 +++--- Patches/MeetingHudPatch.cs | 14 +++++------ Resources/Config/template/English.txt | 2 +- 6 files changed, 56 insertions(+), 17 deletions(-) diff --git a/Modules/CustomNetObject.cs b/Modules/CustomNetObject.cs index f61c0470a..906c5b893 100644 --- a/Modules/CustomNetObject.cs +++ b/Modules/CustomNetObject.cs @@ -377,8 +377,13 @@ namespace EHR try { - AmongUsClient.Instance.RemoveNetObject(playerControl); - Object.Destroy(playerControl.gameObject); + try + { + AmongUsClient.Instance.RemoveNetObject(playerControl); + Object.Destroy(playerControl.gameObject); + } + catch (Exception e) { Utils.ThrowException(e); } + playerControl = Object.Instantiate(AmongUsClient.Instance.PlayerPrefab, Vector2.zero, Quaternion.identity); playerControl.PlayerId = 254; playerControl.isNew = false; diff --git a/Modules/TemplateManager.cs b/Modules/TemplateManager.cs index ce46c6da0..545ff6104 100644 --- a/Modules/TemplateManager.cs +++ b/Modules/TemplateManager.cs @@ -81,8 +81,10 @@ public static class TemplateManager } else { + const string oldWelcomeTemplate = "welcome:Welcome!\\nThis is a Modded Lobby.\\nThe mod is Endless Host Roles (EHR) v{{ModVersion}}.\\nThe mod was made by Gurge44.\\n\\n/r → Show all active roles\\n/r [role name] → Show description & settings for that role"; + const string newWelcomeTemplate = "welcome:Welcome!\\nThis is a Modded Lobby.\\nYou're playing Endless Host Roles (EHR) v{{ModVersion}}.\\nThe mod was made by Gurge44.\\n\\n/r → Show all active roles\\n/r [role name] → Show description & settings for that role"; string text = File.ReadAllText(TemplateFilePath, Encoding.GetEncoding("UTF-8")); - File.WriteAllText(TemplateFilePath, text.Replace("5PNwUaN5", "hkk2p9ggv4")); + File.WriteAllText(TemplateFilePath, text.Replace("5PNwUaN5", "hkk2p9ggv4").Replace(oldWelcomeTemplate, newWelcomeTemplate)); } } diff --git a/Modules/Utils.cs b/Modules/Utils.cs index c2d453528..013cecdb8 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -1865,7 +1865,10 @@ public static class Utils title = title.Replace("color=", string.Empty); if (GameStates.CurrentServerType == GameStates.ServerType.Vanilla) + { text = ReplaceHexColorsWithSafeColors(text); + text = ReplaceDigitsOutsideRichText(text); + } PlayerControl sender = !addToHistory || GameStates.CurrentServerType == GameStates.ServerType.Vanilla ? PlayerControl.LocalPlayer : Main.AllAlivePlayerControls.MinBy(x => x.PlayerId) ?? Main.AllPlayerControls.MinBy(x => x.PlayerId) ?? PlayerControl.LocalPlayer; @@ -2182,7 +2185,7 @@ public static class Utils foreach (char c in text) { - if (char.IsDigit(c) && digitCount == 5) + if (c is >= '0' and <= '9' && digitCount == 5) { int lastNewline = sb.ToString().LastIndexOf('\n'); @@ -2319,6 +2322,37 @@ public static class Utils return CachedLetterOnlyHexColors; } + + static string ReplaceDigitsOutsideRichText(string text) + { + if (string.IsNullOrWhiteSpace(text)) return text; + + StringBuilder sb = new(text.Length); + bool insideTag = false; + + foreach (char c in text) + { + switch (c) + { + case '<': + insideTag = true; + sb.Append(c); + continue; + case '>': + insideTag = false; + sb.Append(c); + continue; + case >= '0' and <= '9' when !insideTag: + sb.Append((char)('0' + (c - '0'))); + break; + default: + sb.Append(c); + break; + } + } + + return sb.ToString(); + } } public static HashSet DirtyName = []; diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index c2611d0fc..f35715c32 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -382,7 +382,6 @@ internal static class ChatCommands ChatControllerUpdatePatch.CurrentHistorySelection = ChatHistory.Count; - string[] args = text.Split(' '); var canceled = false; Main.IsChatCommand = true; @@ -403,8 +402,8 @@ internal static class ChatCommands if (text.StartsWith('/')) { - if (AmongUsClient.Instance.AmHost && text.StartsWith("/cmd")) - text = "/" + text[4..].TrimStart(); + Utils.CheckServerCommand(ref text, out _); + string[] args = text.Split(' '); foreach ((string key, Command command) in Command.AllCommands) { @@ -3637,8 +3636,6 @@ internal static class ChatCommands } } - string[] args = text.Split(' '); - if (!Starspawn.IsDayBreak) { if (GuessManager.GuesserMsg(player, text) || @@ -3664,6 +3661,7 @@ internal static class ChatCommands if (text.StartsWith('/') && !player.IsModdedClient() && (!GameStates.IsMeeting || MeetingHud.Instance.state is not MeetingHud.VoteStates.Results and not MeetingHud.VoteStates.Proceeding)) { Utils.CheckServerCommand(ref text, out bool spamRequired); + string[] args = text.Split(' '); foreach ((string key, Command command) in Command.AllCommands) { diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index 252e652ea..79c28eede 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -982,17 +982,17 @@ internal static class MeetingHudStartPatch if (AmongUsClient.Instance.AmHost) { - if (Options.SyncButtonMode.GetBool()) - { - Utils.SendMessage(string.Format(GetString("Message.SyncButtonLeft"), Options.SyncedButtonCount.GetFloat() - Options.UsedButtonCount)); - Logger.Info("The ship has " + (Options.SyncedButtonCount.GetFloat() - Options.UsedButtonCount) + " buttons left", "SyncButtonMode"); - } - LateTask.New(() => { + if (Options.SyncButtonMode.GetBool()) + { + Utils.SendMessage(string.Format(GetString("Message.SyncButtonLeft"), Options.SyncedButtonCount.GetFloat() - Options.UsedButtonCount)); + Logger.Info("The ship has " + (Options.SyncedButtonCount.GetFloat() - Options.UsedButtonCount) + " buttons left", "SyncButtonMode"); + } + TemplateManager.SendTemplate("OnMeeting", noErr: true, sendOption: SendOption.None); if (MeetingStates.FirstMeeting) TemplateManager.SendTemplate("OnFirstMeeting", noErr: true, sendOption: SendOption.None); - }, 6f, log: false); + }, 6.5f, log: false); NotifyRoleSkillOnMeetingStart(); diff --git a/Resources/Config/template/English.txt b/Resources/Config/template/English.txt index 50632cfd4..458db7baf 100644 --- a/Resources/Config/template/English.txt +++ b/Resources/Config/template/English.txt @@ -1,3 +1,3 @@ -welcome:Welcome!\nThis is a Modded Lobby.\nThe mod is Endless Host Roles (EHR) v{{ModVersion}}.\nThe mod was made by Gurge44.\n\n/r → Show all active roles\n/r [role name] → Show description & settings for that role +welcome:Welcome!\nThis is a Modded Lobby.\nYou're playing Endless Host Roles (EHR) v{{ModVersion}}.\nThe mod was made by Gurge44.\n\n/r → Show all active roles\n/r [role name] → Show description & settings for that role OnMeeting:/m → See what your role does\n/r → Show all active roles\n/r [role name] → Show description & settings for that role\n/bt [ID] [role name] → Guess that player's role help:ENDLESS HOST ROLES\nQUICK GUIDE\n(Guide by @fluxwux on Discord)\nTake notes, class.\n\nEHR is a pretty complicated mod, but don't worry! I'm here to teach you all the basics of the game so you can become the best player there is! First off, let's start with the most integral part of the mod...\n\nROLES\nEach player will be assigned a role at the start of the game. There are 4 role types. Impostor, Crewmate, Neutral, & Add-Ons.\n\nImpostors & Crewmates\nSelf explanatory. These roles are given to the impostors or crewmates.\n\nNeutrals\nThis isn't a team. These roles are for any roles that don't side with the impostors or crewmates. Usually, they work alone toward a goal, depending on what their role does. that goal can range from getting their target voted out to win alone, killing everyone in the game, simply staying alive until the end to win with the winning team, and more.\n\nAdd-Ons\nAdd-Ons are roles that you can get on top of your team role.Usually, they provide minor benefits, such as your killer automatically self-reporting your body, giving you a red screen flash when a body dies, and more. Some are even major additions, like being able to kill people after your death. But be weary, as you may be assigned a harmful Add-On!These roles may give you reduced vision, an inability to report bodies, an inability to fix sabotages, and more. Remember that most (not all) Add-Ons are not team specific, and can be assigned to anyone unless the host individually choses which roles go on what.\n\nIt is important to remember that nobody should reveal their role unless they have a reason to (eg. Snitch finishing their tasks to out the impostors)\n\nCHAT COMMANDS\nChat commands are a very useful asset, and each one has its own very useful effect. Examples of some meeting commands can be found below vvvv\n\n/m: Explains your role and Add-On(s) in detail. A MUST USE if you don't know what your role does.\n/r [role name]: Shows you what any role in the game does. Just type in the role. Typing /r on its own shows every role enabled in the host's settings.\n/kcount (can be disabled by host): Displays the amount of impostors and neutral killers remaining.\n/l (not i, L): Used in the lobby to show the results of the previous game. Displays who died to whom, everyone's roles, and who won the last game. Usually, hosts will make this message appear automatically after the round ends.\n\nGUESSING\nGuessing, or variants of guessing, are abilities that can be used by a select few roles. Usually, they involve guessing a certain player's role in order to kill them during a meeting, or achieve other effects. Sometimes, hosts will make it so entire teams or even all players can guess.\n\nHOW TO GUESS\nThis guide will show the most common way to guess using the /bt command.\n\n#1. Figure out the player's role\nBefore you can guess, you need to find out what their role is. If you've found out what their role is, you can guess them in the next meeting. For example, I know blue is the Snitch, so moving on to step 2...\n\n#2. Type /id\nTyping /id will show a list of everyone and their respective ID, represented by a number from 1-15. I type /id and blue's ID is 7. Sometimes, you may already see the IDs of all players without having to type this command. Now all that's left is...\n\n#3. Type /bt [player ID] [role}\nIn my case, it would be /bt 7 snitch. Now, if correct, I have killed blue, and now blue will have to wallow in their shame as a ghost. How sad. But if I misguess, I have to wallow in my shame as I die if I guess wrong. How embarrasing.\n\nNow, you should be caught up on all things EHR related. Now go out there and win some games! \ No newline at end of file