From ff8637c05b8ead4dd816aa1d43cf9d32527ca8de Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Fri, 15 May 2026 21:40:18 +0200 Subject: [PATCH] fine-tune rpc size limit handling --- Modules/CustomRolesHelper.cs | 3 - Modules/CustomSounds.cs | 2 +- Modules/DataFlagRateLimiter.cs | 34 +- Modules/Extensions/HazelExtensions.cs | 25 +- .../PlayerGameOptionsSender.cs | 2 + Modules/OptionHolder.cs | 2 +- Modules/Utils.cs | 422 +++++++++++------- Patches/PlayerControlPatch.cs | 7 +- Roles/Standard/Neutral/Evil/Vector.cs | 14 +- 9 files changed, 316 insertions(+), 195 deletions(-) diff --git a/Modules/CustomRolesHelper.cs b/Modules/CustomRolesHelper.cs index d670114f1..2138c0aaf 100644 --- a/Modules/CustomRolesHelper.cs +++ b/Modules/CustomRolesHelper.cs @@ -42,9 +42,6 @@ internal static class CustomRolesHelper CustomRoles.Empress, CustomRoles.Tar, - // Add-ons - CustomRoles.Energetic, - // HnS CustomRoles.Jet, CustomRoles.Dasher diff --git a/Modules/CustomSounds.cs b/Modules/CustomSounds.cs index 4ef887e44..f2ffc2008 100644 --- a/Modules/CustomSounds.cs +++ b/Modules/CustomSounds.cs @@ -18,7 +18,7 @@ public static class CustomSoundsManager { if (!force && (!AmongUsClient.Instance.AmHost || !pc.IsModdedClient())) return; - if (!pc || PlayerControl.LocalPlayer.PlayerId == pc.PlayerId) + if (!pc || pc.AmOwner) { Play(sound, volume, pitch); return; diff --git a/Modules/DataFlagRateLimiter.cs b/Modules/DataFlagRateLimiter.cs index 9f9bfef14..96c240226 100644 --- a/Modules/DataFlagRateLimiter.cs +++ b/Modules/DataFlagRateLimiter.cs @@ -65,6 +65,12 @@ public static class DataFlagRateLimiter return qa; } + if (GameStates.IsEnded && !GameStates.IsLobby) + { + Drop(qa); + return qa; + } + switch (channel) { case SendOption.Reliable: @@ -169,18 +175,22 @@ public static class DataFlagRateLimiter while (queue.Count > 0) { var qa = queue.Dequeue(); - - try - { - qa.Cleanup?.Invoke(); - } - catch (Exception e) - { - Utils.ThrowException(e); - } - - qa.Dropped = true; - qa.Done = true; + Drop(qa); } } + + private static void Drop(QueuedAction qa) + { + try + { + qa.Cleanup?.Invoke(); + } + catch (Exception e) + { + Utils.ThrowException(e); + } + + qa.Dropped = true; + qa.Done = true; + } } \ No newline at end of file diff --git a/Modules/Extensions/HazelExtensions.cs b/Modules/Extensions/HazelExtensions.cs index 24d598c3f..8845f8cbd 100644 --- a/Modules/Extensions/HazelExtensions.cs +++ b/Modules/Extensions/HazelExtensions.cs @@ -1,4 +1,5 @@ -using Hazel; +using System.Text; +using Hazel; using UnityEngine; namespace EHR; @@ -56,4 +57,26 @@ public static class HazelExtensions return new(r, g, b, a); } } + + // ------------------------------------------------------------------------------------------------------------------------- + + private static int GetPackedUIntSize(uint value) + { + int count = 0; + + do + { + value >>= 7; + count++; + } + while (value != 0); + + return count; + } + + private static int GetStringWriteSize(string text) + { + int byteCount = Encoding.UTF8.GetByteCount(text); + return GetPackedUIntSize((uint)byteCount) + byteCount; + } } \ No newline at end of file diff --git a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs index 7fed79f69..34e143a26 100644 --- a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs +++ b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs @@ -269,6 +269,8 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS PackedWriter.EndMessage(); } PackedWriter.EndMessage(); + + Logger.Info($"PackedWriter message write complete - Length: {PackedWriter.Length}, Messages: {PackedWriterMessages}", "GameOptionsSender"); } public static void RemoveSender(PlayerControl player) diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index cefe79264..32fd06527 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -1781,7 +1781,7 @@ public static class Options AllCrewRolesHaveVanillaColor = new BooleanOptionItem(19424, "AllCrewRolesHaveVanillaColor", false, TabGroup.SystemSettings) .SetHeader(true); - MessageRpcSizeLimit = new IntegerOptionItem(19425, "MessageRpcSizeLimit", new(500, 100000, 100), 1400, TabGroup.SystemSettings) + MessageRpcSizeLimit = new IntegerOptionItem(19425, "MessageRpcSizeLimit", new(500, 100000, 100), 1200, TabGroup.SystemSettings) .SetHeader(true); KickSlowJoiningPlayers = new BooleanOptionItem(19428, "KickSlowJoiningPlayers", false, TabGroup.SystemSettings) diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 6bf7c54f6..00bc79e5e 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -267,7 +267,7 @@ public static class Utils return mapId switch { 2 => false, - 4 => ShipStatusSystem.HeliSabotageSystem != null && ShipStatusSystem.HeliSabotageSystem.IsActive, + 4 => ShipStatusSystem.HeliSabotageSystem && ShipStatusSystem.HeliSabotageSystem.IsActive, _ => ShipStatusSystem.ReactorSystemType != null && ShipStatusSystem.ReactorSystemType.IsActive }; } @@ -291,12 +291,12 @@ public static class Utils case SystemTypes.HeliSabotage: { if (mapId != 4) return false; - return ShipStatusSystem.HeliSabotageSystem != null && ShipStatusSystem.HeliSabotageSystem.IsActive; + return ShipStatusSystem.HeliSabotageSystem && ShipStatusSystem.HeliSabotageSystem.IsActive; } case SystemTypes.MushroomMixupSabotage: { if (mapId != 5) return false; - return ShipStatusSystem.MushroomMixupSabotageSystem != null && ShipStatusSystem.MushroomMixupSabotageSystem.IsActive; + return ShipStatusSystem.MushroomMixupSabotageSystem && ShipStatusSystem.MushroomMixupSabotageSystem.IsActive; } default: return false; @@ -782,15 +782,13 @@ public static class Utils for (int i = 0; i < alive.Count; i++) { var role = alive[i].GetCustomRole(); - if (role == CustomRoles.Altruist || - role == CustomRoles.Occultist || - role == CustomRoles.TimeMaster) + if (role is CustomRoles.Altruist or CustomRoles.Occultist or CustomRoles.TimeMaster) return true; } foreach (var state in Main.PlayerStates.Values) { - if (state.Role is Altruist alt && alt.ReviveTimer != null) + if (state.Role is Altruist { ReviveTimer: not null }) return true; } return false; @@ -1760,6 +1758,7 @@ public static class Utils } } + private const int RpcBaseOverhead = 16; public static bool TempReviveHostRunning; private static Stopwatch TempReviveHostRevertStopwatch = new(); private static Stopwatch TempReviveHostTimeSinceRevivalStopwatch = new(); @@ -1920,68 +1919,211 @@ public static class Utils if (writer == null || writer.CurrentState == CustomRpcSender.State.Finished) writer = CustomRpcSender.Create("Utils.SendMessage(1)", sendOption); + // ============================================================================ + // EXACT Hazel-based size calculation and splitting logic. + // ============================================================================ + int fullRpcSizeLimit = Options.MessageRpcSizeLimit.GetInt(); - int textRpcSize = text.Length * 2; - int titleRpcSize = title.Length * 2 + 4; - int resetNameRpcSize = sender.Data.PlayerName.Length * 2 + 4; - int fullRpcSize = textRpcSize + titleRpcSize + resetNameRpcSize; + string resetName = Main.AllPlayerNames.GetValueOrDefault(sender.PlayerId, string.Empty); + + // -------------------------------------------------------------------------- + // Helper methods + // -------------------------------------------------------------------------- + + static int GetPackedUInt32Size(uint value) + { + int count = 0; + do + { + value >>= 7; + count++; + } while (value != 0); + + return count; + } + + static int GetStringWriteSize(string value) + { + value ??= string.Empty; + int byteCount = Encoding.UTF8.GetByteCount(value); + return GetPackedUInt32Size((uint)byteCount) + byteCount; + } + + static int EstimateSetNameRpcSize(string name) + { + return RpcBaseOverhead + + 4 // Write(sender.Data.NetId) + + GetStringWriteSize(name); + } + + static int EstimateSendChatRpcSize(string message) + { + return RpcBaseOverhead + + GetStringWriteSize(message); + } + + bool FitsInLimit(params int[] rpcSizes) + { + int total = rpcSizes.Sum(); + return total <= fullRpcSizeLimit; + } + + string ExtractOpenSizeTag(string value) + { + MatchCollection opens = Regex.Matches(value, @""); + MatchCollection closes = Regex.Matches(value, ""); + return opens.Count > closes.Count ? opens[^1].Value : string.Empty; + } + + List SplitIntoFittingChunks(string source, Func fits) + { + List result = []; + + if (string.IsNullOrEmpty(source)) + { + result.Add(source); + return result; + } + + int index = 0; + string prefix = string.Empty; + + while (index < source.Length) + { + int low = 1; + int high = source.Length - index; + int best = 0; + + // ----------------------------------------------------------------- + // Step 1: Binary search to find the maximum number of characters + // that fit into one chunk. + // ----------------------------------------------------------------- + while (low <= high) + { + int mid = (low + high) / 2; + string candidate = string.Concat(prefix, source.AsSpan(index, mid)); + + if (fits(candidate)) + { + best = mid; + low = mid + 1; + } + else + high = mid - 1; + } + + if (best == 0) + { + // Even one character doesn't fit. + // This should only happen if the title itself exceeds the limit. + return []; + } + + // ----------------------------------------------------------------- + // Step 2: Prefer splitting at the last '\n' that fits. + // If no newline exists, keep the full "best" hard split. + // ----------------------------------------------------------------- + int splitLength = best; + + ReadOnlySpan fittedSpan = source.AsSpan(index, best); + int lastNewline = fittedSpan.LastIndexOf('\n'); + + // Only use the newline if: + // - one exists + // - it is not the very first character (to avoid zero-length chunks) + if (lastNewline > 0) + splitLength = lastNewline + 1; // include the newline + + // ----------------------------------------------------------------- + // Step 3: Emit the chunk. + // ----------------------------------------------------------------- + string chunk = string.Concat(prefix, source.AsSpan(index, splitLength)); + result.Add(chunk); + + // ----------------------------------------------------------------- + // Step 4: Advance and preserve open tags. + // ----------------------------------------------------------------- + index += splitLength; + prefix = ExtractOpenSizeTag(chunk); + } + + return result; + } + + CustomRpcSender SendTempTitleMessage(string tempTitle) + { + if (writer.CurrentState == CustomRpcSender.State.Finished) + writer = CustomRpcSender.Create("Utils.SendMessage.SendTempTitleMessage", sendOption); + + writer.AutoStartRpc(sender.NetId, RpcCalls.SetName, targetClientId) + .Write(sender.Data.NetId) + .Write(tempTitle) + .EndRpc(); + + writer.AutoStartRpc(sender.NetId, RpcCalls.SendChat, targetClientId) + .Write("\n") + .EndRpc(); + + writer.AutoStartRpc(sender.NetId, RpcCalls.SetName, targetClientId) + .Write(sender.Data.NetId) + .Write(resetName) + .EndRpc(); + + writer.SendMessage(); + + try + { + string pureTitle = tempTitle.RemoveHtmlTags(); + Logger.Info($" Message: \\n - To: {(sendTo == byte.MaxValue ? "Everyone" : $"{GetPlayerById(sendTo)?.GetRealName()}")} - Title: {pureTitle[..Math.Min(pureTitle.Length, 300)]}", "SendMessage"); + } + catch + { + Logger.Info(" Message sent", "SendMessage"); + } + + if (addToHistory) + ChatUpdatePatch.LastMessages.Add(("\n", sendTo, tempTitle, TimeStamp)); + + return writer; + } + + // -------------------------------------------------------------------------- + // TITLE SPLITTING + // -------------------------------------------------------------------------- if (!noSplit) { - int titleRpcSizeLimit = fullRpcSizeLimit - textRpcSize - resetNameRpcSize; + bool fullMessageFits = FitsInLimit( + EstimateSetNameRpcSize(title), + EstimateSendChatRpcSize(text), + EstimateSetNameRpcSize(resetName)); - if ((fullRpcSize <= fullRpcSizeLimit && titleRpcSizeLimit <= titleRpcSize) || title.Length <= 100) + if (!fullMessageFits && title.Length > 100) { - writer.AutoStartRpc(sender.NetId, RpcCalls.SetName, targetClientId) - .Write(sender.Data.NetId) - .Write(title) - .EndRpc(); - } - else - { - titleRpcSizeLimit = (fullRpcSizeLimit - 8 - resetNameRpcSize) * 2; + List titleChunks = SplitIntoFittingChunks( + title, + chunk => FitsInLimit( + EstimateSetNameRpcSize(chunk), + EstimateSendChatRpcSize("\n"), + EstimateSetNameRpcSize(resetName))); - if (titleRpcSizeLimit - 4 < 1) + if (titleChunks.Count == 0) { Logger.SendInGame(GetString("MessageTooLong"), Color.red); - if (!multiple) writer.SendMessage(dispose: true); + + if (!multiple) + writer.SendMessage(dispose: true); + return writer; } - string[] lines = title.Split('\n'); - var shortenedTitle = string.Empty; + foreach (string chunk in titleChunks) + writer = SendTempTitleMessage(chunk); - foreach (string line in lines) - { - if (shortenedTitle.Length * 2 + line.Length * 2 + 4 < titleRpcSizeLimit) - { - shortenedTitle += line + "\n"; - continue; - } - - if (shortenedTitle.Length * 2 >= titleRpcSizeLimit - 4) - { - foreach (char[] chars in shortenedTitle.Chunk(titleRpcSizeLimit - 4)) - writer = SendTempTitleMessage(new string(chars)); - } - else - writer = SendTempTitleMessage(shortenedTitle); - - string sentText = shortenedTitle; - shortenedTitle = line + "\n"; - - if (Regex.Matches(sentText, " Regex.Matches(sentText, "").Count) - { - string sizeTag = Regex.Matches(sentText, @"")[^1].Value; - shortenedTitle = sizeTag + shortenedTitle; - } - } - - if (shortenedTitle.Length > 0 && !shortenedTitle.IsNullOrWhiteSpace()) - writer = SendTempTitleMessage(shortenedTitle); - - if (text == "\n") return writer; + if (text == "\n") + return writer; + // After long title was sent separately, use invisible title. title = "‎"; if (writer.CurrentState == CustomRpcSender.State.Finished) @@ -1991,91 +2133,55 @@ public static class Utils .Write(sender.Data.NetId) .Write(title) .EndRpc(); + } + } - CustomRpcSender SendTempTitleMessage(string tempTitle) + // -------------------------------------------------------------------------- + // TEXT SPLITTING + // -------------------------------------------------------------------------- + + if (!noSplit) + { + bool finalMessageFits = FitsInLimit( + EstimateSetNameRpcSize(title), + EstimateSendChatRpcSize(text), + EstimateSetNameRpcSize(resetName)); + + if (!finalMessageFits) + { + List textChunks = SplitIntoFittingChunks( + text, + chunk => FitsInLimit( + EstimateSetNameRpcSize(title), + EstimateSendChatRpcSize(chunk), + EstimateSetNameRpcSize(resetName))); + + if (textChunks.Count == 0) { - if (writer.CurrentState == CustomRpcSender.State.Finished) - writer = CustomRpcSender.Create("Utils.SendMessage.SendTempTitleMessage", sendOption); + Logger.SendInGame(GetString("MessageTooLong"), Color.red); - writer.AutoStartRpc(sender.NetId, RpcCalls.SetName, targetClientId) - .Write(sender.Data.NetId) - .Write(tempTitle) - .EndRpc(); + if (!multiple) + writer.SendMessage(dispose: true); - writer.AutoStartRpc(sender.NetId, RpcCalls.SendChat, targetClientId) - .Write("\n") - .EndRpc(); - - writer.AutoStartRpc(sender.NetId, RpcCalls.SetName, targetClientId) - .Write(sender.Data.NetId) - .Write(Main.AllPlayerNames.GetValueOrDefault(sender.PlayerId, string.Empty)) - .EndRpc(); - - writer.SendMessage(); - - try - { - string pureTitle = tempTitle.RemoveHtmlTags(); - Logger.Info($" Message: \\n - To: {(sendTo == byte.MaxValue ? "Everyone" : $"{GetPlayerById(sendTo)?.GetRealName()}")} - Title: {pureTitle[..(pureTitle.Length <= 300 ? pureTitle.Length : 300)]}", "SendMessage"); - } - catch { Logger.Info(" Message sent", "SendMessage"); } - - if (addToHistory) ChatUpdatePatch.LastMessages.Add(("\n", sendTo, tempTitle, TimeStamp)); return writer; } - } - } - titleRpcSize = title.Length * 2 + 4; - int textRpcSizeLimit = fullRpcSizeLimit - titleRpcSize - resetNameRpcSize; - - if (textRpcSizeLimit < 1 && textRpcSize >= textRpcSizeLimit && !noSplit) - { - Logger.SendInGame(GetString("MessageTooLong"), Color.red); - if (!multiple) writer.SendMessage(dispose: true); - return writer; - } - - if (textRpcSize >= textRpcSizeLimit && !noSplit) - { - string[] lines = text.Split('\n'); - var shortenedText = string.Empty; - - foreach (string line in lines) - { - if (shortenedText.Length * 2 + line.Length * 2 + 4 < textRpcSizeLimit) + for (int i = 0; i < textChunks.Count; i++) { - shortenedText += line + "\n"; - continue; + writer = SendMessage( + textChunks[i], + sendTo, + title, + noSplit: true, + writer: writer, + final: i == textChunks.Count - 1, + multiple: multiple, + importance: importance, + addToHistory: addToHistory); } - writer = shortenedText.Length * 2 >= textRpcSizeLimit - ? shortenedText.Chunk(textRpcSizeLimit).Aggregate(writer, (current, chunk) => SendMessage(new(chunk), sendTo, title, true, current, importance: importance)) - : SendMessage(shortenedText, sendTo, title, true, writer, importance: importance); - - string sentText = shortenedText; - shortenedText = line + "\n"; - - if (Regex.Matches(sentText, " Regex.Matches(sentText, "").Count) - { - string sizeTag = Regex.Matches(sentText, @"")[^1].Value; - shortenedText = sizeTag + shortenedText; - } + return writer; } - - if (shortenedText.Length > 0 && !shortenedText.IsNullOrWhiteSpace()) writer = SendMessage(shortenedText, sendTo, title, true, writer, true, importance: importance); - else - { - writer.AutoStartRpc(sender.NetId, RpcCalls.SetName, targetClientId) - .Write(sender.Data.NetId) - .Write(Main.AllPlayerNames.GetValueOrDefault(sender.PlayerId, string.Empty)) - .EndRpc(); - - if (!multiple) writer.SendMessage(); - else RestartMessageIfTooLong(sendOption); - } - - return writer; } try @@ -2645,20 +2751,14 @@ public static class Utils for (int seerIndex = 0; seerIndex < aapc.Count; seerIndex++) { PlayerControl seer = aapc[seerIndex]; - for (int targetIndex = 0; targetIndex < aapc.Count; targetIndex++) + NotifyRoles(SpecifySeer: seer, NoCache: noCache, SendOption: sendOption); + + if (stopwatch.ElapsedMilliseconds >= frameBudget) { + stopwatch.Reset(); + yield return null; if (GameStates.IsMeeting || ReportDeadBodyPatch.MeetingStarted) yield break; - PlayerControl target = aapc[targetIndex]; - var sender = CustomRpcSender.Create("Utils.NotifyEveryoneAsync", sendOption, log: false); - var hasValue = WriteSetNameRpcsToSender(ref sender, false, noCache, false, false, false, false, seer, [seer], [target], out bool senderWasCleared, sendOption) && !senderWasCleared; - sender.SendMessage(!hasValue || sender.stream.Length <= 3); - - if (stopwatch.ElapsedMilliseconds >= frameBudget) - { - stopwatch.Reset(); - yield return null; - stopwatch.Start(); - } + stopwatch.Start(); } } } @@ -2771,7 +2871,6 @@ public static class Utils var lovers = Main.LoversPlayers; bool seerIsLover = false; - bool targetIsLover = false; if (!GameStates.IsLobby) { @@ -2780,7 +2879,6 @@ public static class Utils SelfMark.Append(Snitch.GetWarningArrow(seer)); seerIsLover = false; - targetIsLover = false; if (lovers.Count == 2) { @@ -3150,7 +3248,7 @@ public static class Utils TargetMark.Append(Snitch.GetWarningMark(seer, target)); - targetIsLover = false; + var targetIsLover = false; if (lovers.Count == 2) { byte loverIdFirst = lovers[0].PlayerId; @@ -3508,18 +3606,14 @@ public static class Utils return true; } - var gameMode = Options.CurrentGameMode; - - if (gameMode == CustomGameMode.FFA || - gameMode == CustomGameMode.StopAndGo || - gameMode == CustomGameMode.HotPotato || - gameMode == CustomGameMode.Speedrun) - return true; - - if (gameMode == CustomGameMode.HideAndSeek && CustomHnS.IsRoleTextEnabled(seer, target)) - return true; - - return false; + switch (Options.CurrentGameMode) + { + case CustomGameMode.FFA or CustomGameMode.StopAndGo or CustomGameMode.HotPotato or CustomGameMode.Speedrun: + case CustomGameMode.HideAndSeek when CustomHnS.IsRoleTextEnabled(seer, target): + return true; + default: + return false; + } } public static bool IsRoleTextEnabled(PlayerControl target) @@ -4720,16 +4814,16 @@ public static class Utils for (int i = start; i < length; i++) { char c = str[i]; - if (c == '<') + switch (c) { - insideTag = true; - continue; - } - if (c == '>') - { - insideTag = false; - continue; + case '<': + insideTag = true; + continue; + case '>': + insideTag = false; + continue; } + if (!insideTag) { buffer[idx++] = c; diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index 95a9f510e..2de6fc432 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -1630,7 +1630,7 @@ internal static class FixedUpdatePatch bool self = playerId == lpId; // Updates that are independent of the player are only executed for the local player. bool inTask = GameStates.IsInTask; - bool IsInGame = GameStates.IsInGame; + bool isInGame = GameStates.IsInGame; bool isLobby = GameStates.IsLobby; bool alive = player.IsAlive(); @@ -1853,7 +1853,7 @@ internal static class FixedUpdatePatch player.cosmetics.nameText.text = Main.ShowPlayerInfoInLobby.Value && !player.AmOwner ? $"<#888888>{player.GetClient().PlatformData.Platform} | {player.FriendCode} | {player.GetClient().GetHashedPuid()}\n{player.Data?.PlayerName}" : player.Data?.PlayerName; } - if (IsInGame) + if (isInGame) { if (!AmongUsClient.Instance.AmHost && Options.CurrentGameMode != CustomGameMode.Standard) return; @@ -2282,6 +2282,9 @@ internal static class EnterVentPatch if (AmongUsClient.Instance.AmHost) pc.MyPhysics?.RpcBootFromVent(__instance.Id); pc.ReportDeadBody(null); break; + case CustomRoles.Vector when !AmongUsClient.Instance.AmHost: + Main.PlayerStates[pc.PlayerId].Role.OnEnterVent(pc, __instance); + break; } if (!AmongUsClient.Instance.AmHost) return; diff --git a/Roles/Standard/Neutral/Evil/Vector.cs b/Roles/Standard/Neutral/Evil/Vector.cs index 4ea639013..49ac22c16 100644 --- a/Roles/Standard/Neutral/Evil/Vector.cs +++ b/Roles/Standard/Neutral/Evil/Vector.cs @@ -69,13 +69,12 @@ internal class Vector : RoleBase hud.AbilityButton.buttonLabelText.text = Translator.GetString("VectorVentButtonText"); } - public override void OnEnterVent(PlayerControl pc, Vent vent) + public override void OnEnterVent(PlayerControl pc, Vent vent) // called as non-host modded client too! { VectorVentCount.TryAdd(pc.PlayerId, 0); VectorVentCount[pc.PlayerId]++; - Utils.SendRPC(CustomRPC.SyncRoleData, pc.PlayerId, pc.PlayerId); - Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc); - pc.RPCPlayCustomSound("MarioJump"); + if (!pc.IsModdedClient()) Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc); + if (pc.AmOwner) CustomSoundsManager.Play("MarioJump"); if (AmongUsClient.Instance.AmHost && VectorVentCount[pc.PlayerId] >= VectorVentNumWin) { @@ -84,11 +83,4 @@ internal class Vector : RoleBase CustomWinnerHolder.WinnerIds.Add(pc.PlayerId); } } - - public void ReceiveRPC(MessageReader reader) - { - byte id = reader.ReadByte(); - VectorVentCount.TryAdd(id, 0); - VectorVentCount[id]++; - } }