diff --git a/BAUPlugin.cs b/BAUPlugin.cs index 4eaa94f..9c7b316 100644 --- a/BAUPlugin.cs +++ b/BAUPlugin.cs @@ -67,7 +67,7 @@ internal class BAUPlugin : BasePlugin internal static string[] SupportedAmongUsVersions = [ - "2025.10.14", + "2025.11.18", ]; internal static List AllPlayerControls = []; @@ -165,6 +165,7 @@ internal class BAUPlugin : BasePlugin internal static ConfigEntry? UnlockFPS { get; private set; } internal static ConfigEntry? ShowFPS { get; private set; } internal static ConfigEntry? CommandPrefix { get; set; } + internal static ConfigEntry? FavoriteColor { get; set; } private void LoadOptions() { PrivateOnlyLobby = Config.Bind("Mod", "PrivateOnlyLobby", false); @@ -179,6 +180,7 @@ internal class BAUPlugin : BasePlugin UnlockFPS = Config.Bind("Better Options", "UnlockFPS", false); ShowFPS = Config.Bind("Better Options", "ShowFPS", false); CommandPrefix = Config.Bind("Client Options", "CommandPrefix", "/"); + FavoriteColor = Config.Bind("Mod", "FavoriteColor", -1); } internal static string GetDataPathToAmongUs() => Application.persistentDataPath; diff --git a/Items/Structs/RPCData.cs b/Items/Structs/RPCData.cs index 01040ef..072a5f9 100644 --- a/Items/Structs/RPCData.cs +++ b/Items/Structs/RPCData.cs @@ -3,7 +3,7 @@ using InnerNet; namespace BetterAmongUs.Items.Structs; -internal struct RPCData(InnerNetObject sender, SendOption sendOption, int targetId, RpcCalls callId, MessageReader reader) +internal readonly struct RPCData(InnerNetObject sender, SendOption sendOption, int targetId, RpcCalls callId, MessageReader reader) { public readonly InnerNetObject Sender = sender; public readonly SendOption SendOption = sendOption; diff --git a/Managers/UpdateManager.cs b/Managers/UpdateManager.cs index 79021f2..0767351 100644 --- a/Managers/UpdateManager.cs +++ b/Managers/UpdateManager.cs @@ -1,6 +1,7 @@ using BepInEx.Unity.IL2CPP.Utils; using BetterAmongUs.Helpers; using BetterAmongUs.Network.Loaders; +using Il2CppInterop.Runtime.Attributes; using System.Collections; using System.Reflection; using TMPro; @@ -68,6 +69,7 @@ internal class UpdateManager : MonoBehaviour private GameObject? mainMenu; private GameObject? ambience; + [HideFromIl2Cpp] private IEnumerator CoPressDownload(DoNotPressButton button) { AmUpdateing = true; diff --git a/ModInfo.cs b/ModInfo.cs index 614937a..23d9355 100644 --- a/ModInfo.cs +++ b/ModInfo.cs @@ -2,14 +2,14 @@ internal static class ModInfo { - internal static readonly ReleaseTypes ReleaseBuildType = ReleaseTypes.Release; - internal const string BetaNum = "0"; - internal const string HotfixNum = "3"; - internal const bool IsHotFix = true; + internal static readonly ReleaseTypes ReleaseBuildType = ReleaseTypes.Beta; + internal const string BetaNum = "1"; + internal const string HotfixNum = "0"; + internal const bool IsHotFix = false; internal const string PluginName = "BetterAmongUs"; internal const string PluginGuid = "com.d1gq.betteramongus"; - internal const string PluginVersion = "1.3.0"; - internal const string ReleaseDate = "10.28.2025"; // mm/dd/yyyy + internal const string PluginVersion = "1.3.1"; + internal const string ReleaseDate = "12.04.2025"; // mm/dd/yyyy internal const string Github = "https://github.com/D1GQ/BetterAmongUs-Public"; internal const string Discord = "https://discord.gg/vjYrXpzNAn"; } \ No newline at end of file diff --git a/Modules/FileChecker.cs b/Modules/FileChecker.cs index ea256ef..900130f 100644 --- a/Modules/FileChecker.cs +++ b/Modules/FileChecker.cs @@ -18,7 +18,7 @@ class FileChecker "MonoMod", "netstandard", "mscorlib", "AssetRipper", "Cpp2IL", "AsmResolver", "Iced", "CsvHelper", "SemanticVersioning", "Mono.Cecil", "Assembly-CSharp", "StableNameDotNet", "AmongUsCaching", "Disarm", "Gee.External.Capstone", "Rewired_Core", "AddressablesPlayAssetDelivery", "Newtonsoft.Json", - "Assembly-CSharp-firstpass", "Sentry", "Rewired_Windows", "__Generated", + "Assembly-CSharp-firstpass", "Sentry", "Rewired_Windows", "__Generated", "XGamingRuntime", "BetterAmongUs", "MCI", "CrowdedMod", "Mini.RegionInstall", "Unlock", "Skin" }); diff --git a/Mono/BetterPingTracker.cs b/Mono/BetterPingTracker.cs index 1540eab..f1c6c94 100644 --- a/Mono/BetterPingTracker.cs +++ b/Mono/BetterPingTracker.cs @@ -60,7 +60,7 @@ internal class BetterPingTracker : MonoBehaviour } // Add Host Info if not in lobby - if (GameState.IsInGamePlay && !GameState.IsFreePlay && AmongUsClient.Instance != null) + if (GameState.IsInGamePlay && !GameState.IsFreePlay && AmongUsClient.Instance != null && !GameState.IsMeeting) { var hostInfo = AmongUsClient.Instance.GetHost(); if (hostInfo?.Character != null) diff --git a/Mono/PlayerInfoDisplay.cs b/Mono/PlayerInfoDisplay.cs index a3d3c51..d55614a 100644 --- a/Mono/PlayerInfoDisplay.cs +++ b/Mono/PlayerInfoDisplay.cs @@ -32,7 +32,6 @@ internal class PlayerInfoDisplay : MonoBehaviour // Cached regex patterns private static readonly Regex _friendCodePattern = new(@"^[a-zA-Z0-9#]+$", RegexOptions.Compiled); - private static readonly Regex _hashtagPattern = new(@"^#[0-9]{4}$", RegexOptions.Compiled); private CachedTranslations _cachedTranslations = new(); @@ -206,25 +205,48 @@ internal class PlayerInfoDisplay : MonoBehaviour string friendCode = _player.Data.FriendCode; - bool isValidFriendCode = !string.IsNullOrEmpty(friendCode) && - _friendCodePattern.IsMatch(friendCode) && - _hashtagPattern.IsMatch(friendCode) && - !friendCode.Contains(' ') && - Regex.Replace(friendCode, @"^#[0-9]{4}$", string.Empty).Length is > 10 or < 5; - - color = isValidFriendCode ? "#ff0000" : "#00f7ff"; + // Proper friend code validation + bool isValidFriendCode = true; if (string.IsNullOrEmpty(friendCode)) { friendCode = _cachedTranslations.NoFriendCode; color = "#ff0000"; + isValidFriendCode = false; TryKick(); } - else if (!isValidFriendCode) + else { - TryKick(); + // Check if it matches the basic pattern (alphanumeric and # only) + if (!_friendCodePattern.IsMatch(friendCode) || friendCode.Contains(' ')) + { + isValidFriendCode = false; + TryKick(); + } + else + { + // Check if it ends with # followed by exactly 4 digits + var hashtagMatch = Regex.Match(friendCode, @"#\d{4}$"); + if (!hashtagMatch.Success) + { + isValidFriendCode = false; + TryKick(); + } + else + { + // The part before the # should be reasonable length + string namePart = friendCode[..^5]; + if (namePart.Length < 5 || namePart.Length > 10) + { + isValidFriendCode = false; + TryKick(); + } + } + } } + color = isValidFriendCode ? "#00f7ff" : "#ff0000"; + if (DataManager.Settings.Gameplay.StreamerMode) { friendCode = new string('*', friendCode.Length); diff --git a/Patches/Client/AnnouncementPanelPatch.cs b/Patches/Client/AnnouncementPanelPatch.cs index 63a374f..fb92617 100644 --- a/Patches/Client/AnnouncementPanelPatch.cs +++ b/Patches/Client/AnnouncementPanelPatch.cs @@ -5,6 +5,7 @@ using BetterAmongUs.Items; using BetterAmongUs.Items.Enums; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes.Arrays; +using System.Globalization; using UnityEngine; namespace BetterAmongUs.Patches.Client; @@ -29,7 +30,11 @@ internal static class AnnouncementPanelPatch } } - finalAllNews.Sort((a1, a2) => DateTime.Compare(DateTime.Parse(a2.Date), DateTime.Parse(a1.Date))); + finalAllNews.Sort((a1, a2) => + DateTime.Compare( + DateTime.Parse(a2.Date, null, DateTimeStyles.RoundtripKind), + DateTime.Parse(a1.Date, null, DateTimeStyles.RoundtripKind) + )); aRange = new Il2CppReferenceArray(finalAllNews.Count); for (int i = 0; i < finalAllNews.Count; i++) diff --git a/Patches/Gameplay/Player/PlayerControlPatch.cs b/Patches/Gameplay/Player/PlayerControlPatch.cs index 1c7a7e1..c8e1397 100644 --- a/Patches/Gameplay/Player/PlayerControlPatch.cs +++ b/Patches/Gameplay/Player/PlayerControlPatch.cs @@ -1,9 +1,11 @@ -using BetterAmongUs.Helpers; +using BepInEx.Unity.IL2CPP.Utils.Collections; +using BetterAmongUs.Helpers; using BetterAmongUs.Items.Enums; using BetterAmongUs.Items.OptionItems; using BetterAmongUs.Managers; using BetterAmongUs.Mono; using HarmonyLib; +using System.Collections; namespace BetterAmongUs.Patches.Gameplay.Player; @@ -12,10 +14,25 @@ internal static class PlayerControlPatch { [HarmonyPatch(nameof(PlayerControl.Start))] [HarmonyPostfix] - private static void Start_Postfix(PlayerControl __instance) + private static void Start_Postfix(PlayerControl __instance, ref Il2CppSystem.Collections.IEnumerator __result) { BAUPlugin.AllPlayerControls.Add(__instance); OptionPlayerItem.UpdateAllValues(); + + __result = Effects.Sequence(__result, CoSetFavoriteColor(__instance).WrapToIl2Cpp()); + } + + private static IEnumerator CoSetFavoriteColor(PlayerControl player) + { + if (player.AmOwner) + { + if (BAUPlugin.FavoriteColor.Value >= 0 && player.cosmetics.ColorId != (byte)BAUPlugin.FavoriteColor.Value) + { + player.CmdCheckColor((byte)BAUPlugin.FavoriteColor.Value); + } + } + + yield break; } [HarmonyPatch(nameof(PlayerControl.OnDestroy))] diff --git a/Patches/Gameplay/Player/PlayerJoinAndLeftPatch.cs b/Patches/Gameplay/Player/PlayerJoinAndLeftPatch.cs index 724afa0..d06132e 100644 --- a/Patches/Gameplay/Player/PlayerJoinAndLeftPatch.cs +++ b/Patches/Gameplay/Player/PlayerJoinAndLeftPatch.cs @@ -2,6 +2,7 @@ using BetterAmongUs.Data; using BetterAmongUs.Helpers; using BetterAmongUs.Modules; using BetterAmongUs.Mono; +using BetterAmongUs.Patches.Gameplay.UI; using BetterAmongUs.Patches.Gameplay.UI.Settings; using HarmonyLib; using InnerNet; @@ -32,29 +33,34 @@ internal static class OnPlayerJoinedPatch { _ = new LateTask(() => { - if (GameState.IsInGame) + if (GameState.IsHost) { - var player = Utils.PlayerFromClientId(client.Id); - - // Auto ban player on ban list - if (BetterGameSettings.UseBanPlayerList.GetBool()) + if (GameState.IsInGame) { - if (player != null) + var player = Utils.PlayerFromClientId(client.Id); + + // Auto ban player on ban list + if (BetterGameSettings.UseBanPlayerList.GetBool()) { - if (TextFileHandler.CompareStringMatch(BetterDataManager.banPlayerListFile, - BAUPlugin.AllPlayerControls.Select(player => player.Data.FriendCode) - .Concat(BAUPlugin.AllPlayerControls.Select(player => player.GetHashPuid())).ToArray())) + if (player != null) { - player.Kick(true, Translator.GetString("AntiCheat.BanPlayerListMessage"), bypassDataCheck: true); + if (TextFileHandler.CompareStringMatch(BetterDataManager.banPlayerListFile, + BAUPlugin.AllPlayerControls.Select(player => player.Data.FriendCode) + .Concat(BAUPlugin.AllPlayerControls.Select(player => player.GetHashPuid())).ToArray())) + { + player.Kick(true, Translator.GetString("AntiCheat.BanPlayerListMessage"), bypassDataCheck: true); + } } } - } - - if (BetterGameSettings.UseBanNameList.GetBool()) - { - if (TextFileHandler.CompareStringFilters(BetterDataManager.banNameListFile, [player.Data.PlayerName])) + if (BetterGameSettings.UseBanNameList.GetBool()) { - player?.Kick(true, Translator.GetString("AntiCheat.BanPlayerListMessage"), bypassDataCheck: true); + if (player != null) + { + if (TextFileHandler.CompareStringFilters(BetterDataManager.banNameListFile, [player.Data.PlayerName])) + { + player?.Kick(true, Translator.GetString("AntiCheat.BanPlayerListMessage"), bypassDataCheck: true); + } + } } } } @@ -67,6 +73,19 @@ internal static class OnPlayerLeftPatch { private static void Postfix(/*AmongUsClient __instance,*/ [HarmonyArgument(0)] ClientData data, [HarmonyArgument(1)] DisconnectReasons reason) { + if (GameState.IsLobby) + { + var favColorId = (byte)BAUPlugin.FavoriteColor.Value; + if (BAUPlugin.FavoriteColor.Value >= 0) + { + if (PlayerControl.LocalPlayer.cosmetics.ColorId != favColorId && data.ColorId == favColorId) + { + PlayerControl.LocalPlayer.CmdCheckColor(favColorId); + } + } + } + + MeetingHudPatch.UpdateHostIcon(); } } diff --git a/Patches/Gameplay/UI/MeetingHudPatch.cs b/Patches/Gameplay/UI/MeetingHudPatch.cs index 18f93de..7173891 100644 --- a/Patches/Gameplay/UI/MeetingHudPatch.cs +++ b/Patches/Gameplay/UI/MeetingHudPatch.cs @@ -5,6 +5,7 @@ using BetterAmongUs.Modules; using BetterAmongUs.Mono; using BetterAmongUs.Patches.Gameplay.UI.Chat; using HarmonyLib; +using TMPro; using UnityEngine; namespace BetterAmongUs.Patches.Gameplay.UI; @@ -22,9 +23,29 @@ internal static class MeetingHudPatch pva.gameObject.AddComponent().Init(target, pva); } + if (!GameState.IsOnlineGame) return; + + // Add host icon to meeting hud + __instance.ProceedButton.gameObject.transform.localPosition = new(-2.5f, 2.2f, 0); + __instance.ProceedButton.gameObject.GetComponent().enabled = false; + __instance.ProceedButton.GetComponent().enabled = false; + __instance.HostIcon.enabled = true; + __instance.HostIcon.gameObject.SetActive(true); + __instance.ProceedButton.gameObject.SetActive(true); + MeetingHud.Instance.ProceedButton.DestroyTextTranslators(); + UpdateHostIcon(); + Logger.LogHeader("Meeting Has Started"); } + internal static void UpdateHostIcon() + { + if (MeetingHud.Instance == null) return; + + PlayerMaterial.SetColors(GameData.Instance.GetHost().Color, MeetingHud.Instance.HostIcon); + MeetingHud.Instance.ProceedButton.gameObject.GetComponentInChildren().text = string.Format(Translator.GetString("HostInMeeting"), GameData.Instance.GetHost().BetterData().RealName); + } + internal static float timeOpen = 0f; // Set player meeting info diff --git a/Patches/Gameplay/UI/PlayerTabPatch.cs b/Patches/Gameplay/UI/PlayerTabPatch.cs index de5af12..3d24df6 100644 --- a/Patches/Gameplay/UI/PlayerTabPatch.cs +++ b/Patches/Gameplay/UI/PlayerTabPatch.cs @@ -16,7 +16,7 @@ internal static class PlayerTabPatch [HarmonyPatch(nameof(PlayerTab.OnEnable))] [HarmonyPrefix] - private static void OnEnable_Postfix(PlayerTab __instance) + private static void OnEnable_Prefix(PlayerTab __instance) { foreach (var button in presetButtons.ToArray()) { @@ -59,6 +59,58 @@ internal static class PlayerTabPatch } } + private static readonly List _favoriteIcons = []; + + [HarmonyPatch(nameof(PlayerTab.OnEnable))] + [HarmonyPostfix] + private static void OnEnable_Postfix(PlayerTab __instance) + { + _favoriteIcons.Clear(); + + for (int i = 0; i < __instance.ColorChips.Count; i++) + { + var index = i; + var colorChip = __instance.ColorChips[i]; + colorChip.Button.OnClick = new(); + colorChip.Button.OnClick.AddListener((Action)(() => + { + if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) + { + if (BAUPlugin.FavoriteColor.Value == index) + { + BAUPlugin.FavoriteColor.Value = -1; + } + else + { + BAUPlugin.FavoriteColor.Value = index; + } + + UpdateFavorite(); + return; + } + + __instance.ClickEquip(); + })); + + var checkBox = colorChip.PlayerEquippedForeground.transform.Find("CheckMark").GetComponentInChildren(); + var favoriteIcon = UnityEngine.Object.Instantiate(checkBox, colorChip.transform); + favoriteIcon.color = Color.yellow; + favoriteIcon.transform.localPosition -= new Vector3(0f, 0f, 15f); + _favoriteIcons.Add(favoriteIcon); + } + + UpdateFavorite(); + } + + private static void UpdateFavorite() + { + for (int i = 0; i < _favoriteIcons.Count; i++) + { + SpriteRenderer? fav = _favoriteIcons[i]; + fav.gameObject.SetActive(i == BAUPlugin.FavoriteColor.Value); + } + } + private static bool LoadPlayerOutfit(OutfitData data) { var player = PlayerControl.LocalPlayer; diff --git a/Patches/Gameplay/UI/Settings/GameSettingMenuPatch.cs b/Patches/Gameplay/UI/Settings/GameSettingMenuPatch.cs index cd2aa09..3f2c843 100644 --- a/Patches/Gameplay/UI/Settings/GameSettingMenuPatch.cs +++ b/Patches/Gameplay/UI/Settings/GameSettingMenuPatch.cs @@ -73,7 +73,7 @@ internal static class GameSettingMenuPatch OptionTitleItem.Create(BetterSettingsTab, "BetterSetting.TextHeader.Detections"); BetterGameSettings.CensorDetectionReason = OptionCheckboxItem.Create(1300, BetterSettingsTab, "BetterSetting.Setting.CensorDetectionReason", false); - BetterGameSettings.DetectedLevelAbove = OptionIntItem.Create(600, BetterSettingsTab, "BetterSetting.Setting.DetectedLevelAbove", (100, 5000, 5), 200, ("Lv ", "")); + BetterGameSettings.DetectedLevelAbove = OptionIntItem.Create(600, BetterSettingsTab, "BetterSetting.Setting.DetectedLevelAbove", (100, 10000, 5), 500, ("Lv ", "")); BetterGameSettings.DetectCheatClients = OptionCheckboxItem.Create(700, BetterSettingsTab, "BetterSetting.Setting.DetectCheatClients", true); BetterGameSettings.DetectInvalidRPCs = OptionCheckboxItem.Create(800, BetterSettingsTab, "BetterSetting.Setting.DetectInvalidRPCs", true); } diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json index 895ed9e..e2752d9 100644 --- a/Resources/Lang/en_US.json +++ b/Resources/Lang/en_US.json @@ -16,6 +16,7 @@ "SystemMessage": "System Message", "SystemNotification": "System Notification", "ModdedLobbyMsg": "{0} does not support\nModded Lobbies", + "HostInMeeting": "Host: {0}", "Player.Loading": "Loading", "Player.NoFriendCode": "No Friend Code",