From 00c7cb29c424f265bdd040b10d170948296009d8 Mon Sep 17 00:00:00 2001 From: D1GQ Date: Fri, 28 Mar 2025 22:04:40 -0500 Subject: [PATCH] BetterPingTracker and Mono Extensions --- .editorconfig | 3 + Helpers/ExtendedPlayerControl.cs | 32 +++----- Helpers/ExtendedPlayerInfo.cs | 30 +++---- Modules/BetterPingTracker.cs | 112 ++++++++++++++++++++++++++ Modules/MonoExtension.cs | 134 +++++++++++++++++++++++++++++++ Modules/MonoExtensions.cs | 111 ------------------------- Patches/ClientPatch.cs | 6 +- Patches/PingTrackerPatch.cs | 103 ++---------------------- Patches/VersionShowerPatch.cs | 2 +- main.cs | 5 +- 10 files changed, 282 insertions(+), 256 deletions(-) create mode 100644 Modules/BetterPingTracker.cs create mode 100644 Modules/MonoExtension.cs delete mode 100644 Modules/MonoExtensions.cs diff --git a/.editorconfig b/.editorconfig index 795fb33..7b91373 100644 --- a/.editorconfig +++ b/.editorconfig @@ -24,6 +24,9 @@ dotnet_diagnostic.CS8604.severity = silent # CS8602: Dereference of a possibly null reference. dotnet_diagnostic.CS8602.severity = none +# IDE0051: Remove unused private members +dotnet_diagnostic.IDE0051.severity = none + [*.{cs,vb}] #### Naming styles #### diff --git a/Helpers/ExtendedPlayerControl.cs b/Helpers/ExtendedPlayerControl.cs index f322ea9..145ddf4 100644 --- a/Helpers/ExtendedPlayerControl.cs +++ b/Helpers/ExtendedPlayerControl.cs @@ -1,37 +1,27 @@ -using HarmonyLib; +using BetterAmongUs.Modules; +using HarmonyLib; using TMPro; using UnityEngine; namespace BetterAmongUs.Helpers; -internal class ExtendedPlayerControl : MonoBehaviour +[MonoExtension(typeof(PlayerControl))] +internal class ExtendedPlayerControl : MonoBehaviour, IMonoExtension { - internal static readonly HashSet<(PlayerControl player, ExtendedPlayerControl extendedPlayer)> AllExtendedPlayerControl = []; - + public MonoBehaviour? BaseMono { get; set; } internal PlayerControl? _Player { get; set; } internal TextMeshPro? InfoTextInfo { get; set; } internal TextMeshPro? InfoTextTop { get; set; } internal TextMeshPro? InfoTextBottom { get; set; } - internal void Start() + private void Start() { - var player = gameObject.GetComponent(); - if (player != null) - { - if (!AllExtendedPlayerControl.Any(items => items.extendedPlayer == this)) - { - AllExtendedPlayerControl.Add((player, this)); - } - } - else - { - Destroy(this); - } + MonoExtensionManager.RegisterExtension(this); } - internal void OnDestroy() + private void OnDestroy() { - AllExtendedPlayerControl.RemoveWhere(items => items.extendedPlayer == this); + MonoExtensionManager.UnregisterExtension(this); } } @@ -84,11 +74,11 @@ internal static class PlayerControlExtension internal static ExtendedPlayerControl? BetterPlayerControl(this PlayerControl player) { - return ExtendedPlayerControl.AllExtendedPlayerControl.FirstOrDefault(items => items.player == player).extendedPlayer ?? null; + return MonoExtensionManager.Get(player); } internal static ExtendedPlayerControl? BetterPlayerControl(this PlayerPhysics playerPhysics) { - return ExtendedPlayerControl.AllExtendedPlayerControl.FirstOrDefault(items => items.player == playerPhysics.myPlayer).extendedPlayer ?? null; + return MonoExtensionManager.Get(playerPhysics.myPlayer); } } \ No newline at end of file diff --git a/Helpers/ExtendedPlayerInfo.cs b/Helpers/ExtendedPlayerInfo.cs index c56263c..e2fe935 100644 --- a/Helpers/ExtendedPlayerInfo.cs +++ b/Helpers/ExtendedPlayerInfo.cs @@ -8,9 +8,10 @@ using UnityEngine; namespace BetterAmongUs.Helpers; -internal class ExtendedPlayerInfo : MonoBehaviour +[MonoExtension(typeof(NetworkedPlayerInfo))] +internal class ExtendedPlayerInfo : MonoBehaviour, IMonoExtension { - internal static readonly HashSet<(NetworkedPlayerInfo data, ExtendedPlayerInfo extendedData)> AllExtendedPlayerInfo = []; + public MonoBehaviour? BaseMono { get; set; } private bool hasSet = false; internal void SetInfo(NetworkedPlayerInfo data) @@ -24,25 +25,14 @@ internal class ExtendedPlayerInfo : MonoBehaviour private float timeAccumulator = 0f; - internal void Start() + private void Start() { - var data = gameObject.GetComponent(); - if (data != null) - { - if (!AllExtendedPlayerInfo.Any(items => items.extendedData == this)) - { - AllExtendedPlayerInfo.Add((data, this)); - } - } - else - { - Destroy(this); - } + MonoExtensionManager.RegisterExtension(this); } - internal void OnDestroy() + private void OnDestroy() { - AllExtendedPlayerInfo.RemoveWhere(items => items.extendedData == this); + MonoExtensionManager.UnregisterExtension(this); } internal void Update() @@ -161,19 +151,19 @@ internal static class PlayerControlDataExtension // Get BetterData from PlayerControl internal static ExtendedPlayerInfo? BetterData(this PlayerControl player) { - return ExtendedPlayerInfo.AllExtendedPlayerInfo.FirstOrDefault(items => items.data == player.Data).extendedData ?? null; + return MonoExtensionManager.Get(player.Data); } // Get BetterData from NetworkedPlayerInfo internal static ExtendedPlayerInfo? BetterData(this NetworkedPlayerInfo data) { - return ExtendedPlayerInfo.AllExtendedPlayerInfo.FirstOrDefault(items => items.data == data).extendedData ?? null; + return MonoExtensionManager.Get(data); } // Get BetterData from ClientData internal static ExtendedPlayerInfo? BetterData(this ClientData data) { var player = Utils.PlayerFromClientId(data.Id); - return ExtendedPlayerInfo.AllExtendedPlayerInfo.FirstOrDefault(items => items.data == player.Data).extendedData ?? null; + return MonoExtensionManager.Get(player.Data); } } diff --git a/Modules/BetterPingTracker.cs b/Modules/BetterPingTracker.cs new file mode 100644 index 0000000..f8a1de4 --- /dev/null +++ b/Modules/BetterPingTracker.cs @@ -0,0 +1,112 @@ +using BetterAmongUs.Helpers; +using System.Text; +using TMPro; +using UnityEngine; +using static BetterAmongUs.Patches.GamePlayManager; + +namespace BetterAmongUs.Modules; + +internal class BetterPingTracker : MonoBehaviour +{ + internal static BetterPingTracker? Instance { get; private set; } + private AspectPosition? aspectPosition; + private TextMeshPro? text; + internal void SetUp(TextMeshPro pingText, AspectPosition pingAspectPosition) + { + if (Instance != null) return; + Instance = this; + text = pingText; + aspectPosition = pingAspectPosition; + } + + private void Update() + { + aspectPosition.DistanceFromEdge = new Vector3(4f, 0.1f, -5); + aspectPosition.Alignment = AspectPosition.EdgeAlignments.RightTop; + text.outlineWidth = 0.3f; + + PlayerControl Host = AmongUsClient.Instance.GetHost().Character; + + StringBuilder sb = new(); + + if (!GameState.IsFreePlay) + { + sb.AppendFormat("{0}: {1}\n", Translator.GetString("Ping").ToUpper(), GetPingColor(AmongUsClient.Instance.Ping)); + } + + if (GameState.IsLobby && GameState.IsHost && GameState.IsVanillaServer && !GameState.IsLocalGame) + { + sb.AppendFormat("{0}: {1}\n", Translator.GetString("Timer").ToUpper(), GetTimeColor(GameStartManagerPatch.lobbyTimer)); + } + + sb.Append($"BetterAmongUs {Main.GetVersionText(true)}\n"); + sb.Append("By The Enhanced Network\n"); + // sb.Append($"{Main.Github}\n"); + + if (GameState.IsTOHEHostLobby) sb.Append($"TOHE Lobby\n"); + + if (Main.ShowFPS.Value) + { + float FPSNum = 1.0f / Time.deltaTime; + sb.AppendFormat("FPS: {0}\n", (int)FPSNum); + } + + // Add Host Info if not in lobby + if (GameState.IsInGamePlay && !GameState.IsFreePlay && Host != null) + { + sb.AppendFormat("{0}: {1}\n", Translator.GetString("Host"), Host.GetPlayerNameAndColor()); + } + + text.text = sb.ToString(); + } + + private static string GetPingColor(int ping) + { + string color; + switch (ping) + { + case int n when n > 250: + color = "#ff0000"; + break; + case int n when n > 100: + color = "#ffa200"; + break; + case int n when n > 50: + color = "#ffff00"; + break; + default: + color = "#00f04c"; + break; + } + + string newPing = $"{ping} ms"; + + return newPing; + } + + private static string GetTimeColor(float time) + { + float minutes = (int)time / 60 + 1f; + + string color; + switch (minutes) + { + case float n when n <= 1: + color = "#ff0000"; + break; + case float n when n <= 3.5f: + color = "#ffa200"; + break; + case float n when n <= 5f: + color = "#ffff00"; + break; + default: + color = "#00f04c"; + break; + } + + string newTime = $"{GameStartManagerPatch.lobbyTimerDisplay}"; + + return newTime; + } +} \ No newline at end of file diff --git a/Modules/MonoExtension.cs b/Modules/MonoExtension.cs new file mode 100644 index 0000000..3ef8f80 --- /dev/null +++ b/Modules/MonoExtension.cs @@ -0,0 +1,134 @@ +using Il2CppInterop.Runtime; +using System.Reflection; +using UnityEngine; + +namespace BetterAmongUs.Modules; + +[AttributeUsage(AttributeTargets.Class)] +internal class MonoExtensionAttribute : Attribute +{ + internal Type MonoType { get; } + internal Il2CppSystem.Type MonoIl2CppType { get; } + + internal MonoExtensionAttribute(Type monoType) + { + MonoType = monoType; + MonoIl2CppType = Il2CppType.From(monoType); + } +} + +internal interface IMonoExtension +{ + MonoBehaviour? BaseMono { get; set; } +} + +internal static class MonoExtensionManager +{ + private static readonly Dictionary> _extensionsByBaseType = []; + + internal static T? Get(MonoBehaviour mono) where T : class, IMonoExtension + { + if (_extensionsByBaseType.TryGetValue(mono.GetType(), out var extensions)) + { + foreach (var pair in extensions) + { + if (pair.Base == mono && pair.Extension is T result) + { + return result; + } + } + } + + return null; + } + + internal static void CleanAll() + { + foreach (var kvp in _extensionsByBaseType.ToArray()) + { + var extensions = kvp.Value; + for (int i = extensions.Count - 1; i >= 0; i--) + { + if (extensions[i].Base == null || extensions[i].Extension == null) + { + extensions.RemoveAt(i); + } + } + + if (extensions.Count == 0) + { + _extensionsByBaseType.Remove(kvp.Key); + } + } + } + + internal static bool RegisterExtension(IMonoExtension extension) + { + var monoAttribute = extension.GetType().GetCustomAttribute(); + + if (monoAttribute == null || !monoAttribute.MonoType.IsAssignableTo(typeof(MonoBehaviour))) + { + if (extension is MonoBehaviour mono) + { + UnityEngine.Object.Destroy(mono); + } + return false; + } + + var monoBehaviour = extension as MonoBehaviour; + if (monoBehaviour == null) return false; + + var baseComponent = monoBehaviour.GetComponent(monoAttribute.MonoIl2CppType) as MonoBehaviour; + if (baseComponent == null) + { + UnityEngine.Object.Destroy(monoBehaviour); + return false; + } + + var existingExtensions = monoBehaviour.GetComponents(Il2CppType.From(extension.GetType())); + if (existingExtensions.Length > 1) + { + UnityEngine.Object.Destroy(monoBehaviour); + return false; + } + + if (!_extensionsByBaseType.TryGetValue(monoAttribute.MonoType, out var extensions)) + { + extensions = []; + _extensionsByBaseType[monoAttribute.MonoType] = extensions; + } + + extensions.Add(new ExtensionPair { Base = baseComponent, Extension = extension }); + extension.BaseMono = baseComponent; + + return true; + } + + internal static void UnregisterExtension(IMonoExtension extension) + { + if (extension.BaseMono == null) return; + + if (_extensionsByBaseType.TryGetValue(extension.BaseMono.GetType(), out var extensions)) + { + for (int i = extensions.Count - 1; i >= 0; i--) + { + if (extensions[i].Extension == extension) + { + extensions.RemoveAt(i); + break; + } + } + + if (extensions.Count == 0) + { + _extensionsByBaseType.Remove(extension.BaseMono.GetType()); + } + } + } + + private struct ExtensionPair + { + public MonoBehaviour? Base; + public IMonoExtension? Extension; + } +} \ No newline at end of file diff --git a/Modules/MonoExtensions.cs b/Modules/MonoExtensions.cs deleted file mode 100644 index 44c999c..0000000 --- a/Modules/MonoExtensions.cs +++ /dev/null @@ -1,111 +0,0 @@ -using Il2CppInterop.Runtime; -using UnityEngine; - -namespace BetterAmongUs.Modules; - -internal abstract class MonoExtension : MonoBehaviour -{ - private static readonly Dictionary> _extensionsByBaseType = new(); - private MonoBehaviour? _baseMono; - - protected MonoBehaviour? BaseMono - { - get => _baseMono; - private set => _baseMono = value; - } - - private struct ExtensionPair - { - public MonoBehaviour? Base; - public MonoExtension? Extension; - } - - public static T? Get(MonoBehaviour mono) where T : MonoExtension - { - if (_extensionsByBaseType.TryGetValue(mono.GetType(), out var extensions)) - { - foreach (var pair in extensions) - { - if (pair.Base == mono && pair.Extension is T result) - { - return result; - } - } - } - - return null; - } - - protected bool RegisterExtension() where T : MonoBehaviour - { - var baseComponent = GetComponent(Il2CppType.From(typeof(T))) as T; - if (baseComponent == null) - { - Destroy(this); - return false; - } - - var existingExtensions = GetComponents(Il2CppType.From(GetType())); - if (existingExtensions.Length > 1) - { - Destroy(this); - return false; - } - - var baseType = typeof(T); - if (!_extensionsByBaseType.TryGetValue(baseType, out var extensions)) - { - extensions = new List(); - _extensionsByBaseType[baseType] = extensions; - } - - extensions.Add(new ExtensionPair { Base = baseComponent, Extension = this }); - BaseMono = baseComponent; - - return true; - } - - protected void UnregisterExtension() where T : MonoBehaviour - { - if (BaseMono == null) return; - - if (_extensionsByBaseType.TryGetValue(typeof(T), out var extensions)) - { - for (int i = extensions.Count - 1; i >= 0; i--) - { - if (extensions[i].Extension == this) - { - extensions.RemoveAt(i); - break; - } - } - - if (extensions.Count == 0) - { - _extensionsByBaseType.Remove(typeof(T)); - } - } - - BaseMono = null; - } - - public static void CleanAll() - { - foreach (var kvp in _extensionsByBaseType.ToArray()) - { - var extensions = kvp.Value; - for (int i = extensions.Count - 1; i >= 0; i--) - { - if (extensions[i].Base == null || extensions[i].Extension == null) - { - extensions.RemoveAt(i); - } - } - - if (extensions.Count == 0) - { - _extensionsByBaseType.Remove(kvp.Key); - } - } - } -} \ No newline at end of file diff --git a/Patches/ClientPatch.cs b/Patches/ClientPatch.cs index f3ce9f8..8470008 100644 --- a/Patches/ClientPatch.cs +++ b/Patches/ClientPatch.cs @@ -23,7 +23,7 @@ internal class ClientPatch UserData.TrySetLocalData(); var varSupportedVersions = Main.SupportedAmongUsVersions; - Version currentVersion = new Version(Main.AmongUsVersion); + Version currentVersion = new Version(Main.AppVersion); Version firstSupportedVersion = new Version(varSupportedVersions.First()); Version lastSupportedVersion = new Version(varSupportedVersions.Last()); @@ -36,7 +36,7 @@ internal class ClientPatch } Utils.ShowPopUp($"-= Warning =-\n\n" + $"Better Among Us {Main.GetVersionText()}\nsupports Among Us {verText},\n" + - $"Among Us {Main.AmongUsVersion} is above the supported versions!\n" + + $"Among Us {Main.AppVersion} is above the supported versions!\n" + $"You may encounter minor to game breaking bugs."); } else if (currentVersion < lastSupportedVersion) @@ -48,7 +48,7 @@ internal class ClientPatch } Utils.ShowPopUp($"-= Warning =-\n\n" + $"Better Among Us {Main.GetVersionText()}\nsupports Among Us {verText},\n" + - $"Among Us {Main.AmongUsVersion} is below the supported versions!\n" + + $"Among Us {Main.AppVersion} is below the supported versions!\n" + $"You may encounter minor to game breaking bugs."); } } diff --git a/Patches/PingTrackerPatch.cs b/Patches/PingTrackerPatch.cs index 62a6020..a17cbc7 100644 --- a/Patches/PingTrackerPatch.cs +++ b/Patches/PingTrackerPatch.cs @@ -1,9 +1,5 @@ -using BetterAmongUs.Helpers; -using BetterAmongUs.Modules; +using BetterAmongUs.Modules; using HarmonyLib; -using System.Text; -using UnityEngine; -using static BetterAmongUs.Patches.GamePlayManager; namespace BetterAmongUs.Patches; @@ -12,101 +8,12 @@ internal class PingTrackerPatch { [HarmonyPatch(nameof(PingTracker.Update))] [HarmonyPrefix] - internal static bool Prefix(PingTracker __instance) + private static bool Prefix(PingTracker __instance) { - try - { - PlayerControl Host = AmongUsClient.Instance.GetHost().Character; - - if (GameState.IsFreePlay) - { - __instance.gameObject.SetActive(false); - } - - StringBuilder sb = new(); - - sb.AppendFormat("{0}: {1}\n", Translator.GetString("Ping").ToUpper(), GetPingColor(AmongUsClient.Instance.Ping)); - - if (GameState.IsLobby && GameState.IsHost && GameState.IsVanillaServer && !GameState.IsLocalGame) - { - sb.AppendFormat("{0}: {1}\n", Translator.GetString("Timer").ToUpper(), GetTimeColor(GameStartManagerPatch.lobbyTimer)); - } - - sb.Append($"BetterAmongUs {Main.GetVersionText(true)}\n"); - sb.Append("By The Enhanced Network\n"); - // sb.Append($"{Main.Github}\n"); - - if (GameState.IsTOHEHostLobby) sb.Append($"TOHE Lobby\n"); - - if (Main.ShowFPS.Value) - { - float FPSNum = 1.0f / Time.deltaTime; - sb.AppendFormat("FPS: {0}\n", (int)FPSNum); - } - - // Add Host Info if not in lobby - if (GameState.IsInGamePlay && Host != null) - { - sb.AppendFormat("{0}: {1}\n", Translator.GetString("Host"), Host.GetPlayerNameAndColor()); - } - - __instance.aspectPosition.DistanceFromEdge = new Vector3(4f, 0.1f, -5); - __instance.aspectPosition.Alignment = AspectPosition.EdgeAlignments.RightTop; - __instance.text.outlineWidth = 0.3f; - __instance.text.text = sb.ToString(); - } - catch { } + var betterPingTracker = __instance.gameObject.AddComponent(); + betterPingTracker.SetUp(__instance.text, __instance.aspectPosition); + __instance.enabled = false; return false; } - - private static string GetPingColor(int ping) - { - string color; - switch (ping) - { - case int n when n > 250: - color = "#ff0000"; - break; - case int n when n > 100: - color = "#ffa200"; - break; - case int n when n > 50: - color = "#ffff00"; - break; - default: - color = "#00f04c"; - break; - } - - string newPing = $"{ping} ms"; - - return newPing; - } - - private static string GetTimeColor(float time) - { - float minutes = (int)time / 60 + 1f; - - string color; - switch (minutes) - { - case float n when n <= 1: - color = "#ff0000"; - break; - case float n when n <= 3.5f: - color = "#ffa200"; - break; - case float n when n <= 5f: - color = "#ffff00"; - break; - default: - color = "#00f04c"; - break; - } - - string newTime = $"{GameStartManagerPatch.lobbyTimerDisplay}"; - - return newTime; - } } diff --git a/Patches/VersionShowerPatch.cs b/Patches/VersionShowerPatch.cs index e1878d5..8b5c68e 100644 --- a/Patches/VersionShowerPatch.cs +++ b/Patches/VersionShowerPatch.cs @@ -13,6 +13,6 @@ internal class VersionShowerPatch { string mark = Translator.GetString("BAUMark"); string bau = Translator.GetString("BAU"); - __instance.text.text = $"{mark}{bau}{mark} {Main.GetVersionText()} ~ {Utils.GetPlatformName(Main.PlatformData.Platform)} v{Main.AmongUsVersion}"; + __instance.text.text = $"{mark}{bau}{mark} {Main.GetVersionText()} ~ {Utils.GetPlatformName(Main.PlatformData.Platform)} v{Main.AmongUsVersion} ({Main.AppVersion})"; } } diff --git a/main.cs b/main.cs index f2b421b..baed22a 100644 --- a/main.cs +++ b/main.cs @@ -82,7 +82,8 @@ internal class Main : BasePlugin internal static Harmony Harmony { get; } = new Harmony(PluginGuid); internal static string BetterAmongUsVersion => PluginVersion; - internal static string AmongUsVersion => Application.version; + internal static string AppVersion => Application.version; + internal static string AmongUsVersion => DestroyableSingleton.Instance.Refdata.userFacingVersion; internal static PlatformSpecificData PlatformData => Constants.GetPlatformData(); @@ -182,7 +183,7 @@ internal class Main : BasePlugin string SupportedVersions = string.Empty; foreach (string text in SupportedAmongUsVersions.ToArray()) SupportedVersions += $"{text} "; - BetterAmongUs.Logger.Log($"BetterAmongUs {BetterAmongUsVersion}-{ReleaseDate} - [{AmongUsVersion} --> {SupportedVersions.Substring(0, SupportedVersions.Length - 1)}] {Utils.GetPlatformName(PlatformData.Platform)}"); + BetterAmongUs.Logger.Log($"BetterAmongUs {BetterAmongUsVersion}-{ReleaseDate} - [{AppVersion} --> {SupportedVersions.Substring(0, SupportedVersions.Length - 1)}] {Utils.GetPlatformName(PlatformData.Platform)}"); } catch (Exception ex) {