BetterPingTracker and Mono Extensions

This commit is contained in:
D1GQ committed 2025-03-28 22:04:40 -05:00
1 parent 7e54af49d2
commit 00c7cb29c4
10 files changed
+282 -256

No files matched your search

+3
View File
@@ -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 ####
+11 -21
View File
@@ -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<PlayerControl>();
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<ExtendedPlayerControl>(player);
}
internal static ExtendedPlayerControl? BetterPlayerControl(this PlayerPhysics playerPhysics)
{
return ExtendedPlayerControl.AllExtendedPlayerControl.FirstOrDefault(items => items.player == playerPhysics.myPlayer).extendedPlayer ?? null;
return MonoExtensionManager.Get<ExtendedPlayerControl>(playerPhysics.myPlayer);
}
}
+10 -20
View File
@@ -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<NetworkedPlayerInfo>();
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<ExtendedPlayerInfo>(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<ExtendedPlayerInfo>(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<ExtendedPlayerInfo>(player.Data);
}
}
+112
View File
@@ -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}: <b>{1}</b>\n", Translator.GetString("Ping").ToUpper(), GetPingColor(AmongUsClient.Instance.Ping));
}
if (GameState.IsLobby && GameState.IsHost && GameState.IsVanillaServer && !GameState.IsLocalGame)
{
sb.AppendFormat("{0}: <b>{1}</b>\n", Translator.GetString("Timer").ToUpper(), GetTimeColor(GameStartManagerPatch.lobbyTimer));
}
sb.Append($"<color=#00dbdb><size=75%>BetterAmongUs {Main.GetVersionText(true)}</size></color>\n");
sb.Append("<size=68%><color=#8040bf>By</color> <color=#bc4345>The Enhanced Network</color></size>\n");
// sb.Append($"<size=50%><color=#b5b5b5>{Main.Github}</color></size>\n");
if (GameState.IsTOHEHostLobby) sb.Append($"<size=75%><color=#e197dc>TOHE Lobby</color></size>\n");
if (Main.ShowFPS.Value)
{
float FPSNum = 1.0f / Time.deltaTime;
sb.AppendFormat("<color=#0dff00><size=75%>FPS: <b>{0}</b></size></color>\n", (int)FPSNum);
}
// Add Host Info if not in lobby
if (GameState.IsInGamePlay && !GameState.IsFreePlay && Host != null)
{
sb.AppendFormat("<size=75%>{0}: {1}</size>\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 = $"<color={color}>{ping} ms</color>";
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 = $"<color={color}>{GameStartManagerPatch.lobbyTimerDisplay}</color>";
return newTime;
}
}
+134
View File
@@ -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<Type, List<ExtensionPair>> _extensionsByBaseType = [];
internal static T? Get<T>(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<MonoExtensionAttribute>();
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;
}
}
-111
View File
@@ -1,111 +0,0 @@
using Il2CppInterop.Runtime;
using UnityEngine;
namespace BetterAmongUs.Modules;
internal abstract class MonoExtension : MonoBehaviour
{
private static readonly Dictionary<Type, List<ExtensionPair>> _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<T>(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<T>() 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<ExtensionPair>();
_extensionsByBaseType[baseType] = extensions;
}
extensions.Add(new ExtensionPair { Base = baseComponent, Extension = this });
BaseMono = baseComponent;
return true;
}
protected void UnregisterExtension<T>() 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);
}
}
}
}
+3 -3
View File
@@ -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($"<size=200%>-= <color=#ff2200><b>Warning</b></color> =-</size>\n\n" +
$"<size=125%><color=#0dff00>Better Among Us {Main.GetVersionText()}</color>\nsupports <color=#4f92ff>Among Us {verText}</color>,\n" +
$"<color=#4f92ff>Among Us <b>{Main.AmongUsVersion}</b></color> is above the supported versions!\n" +
$"<color=#4f92ff>Among Us <b>{Main.AppVersion}</b></color> is above the supported versions!\n" +
$"<color=#ae1700>You may encounter minor to game breaking bugs.</color></size>");
}
else if (currentVersion < lastSupportedVersion)
@@ -48,7 +48,7 @@ internal class ClientPatch
}
Utils.ShowPopUp($"<size=200%>-= <color=#ff2200><b>Warning</b></color> =-</size>\n\n" +
$"<size=125%><color=#0dff00>Better Among Us {Main.GetVersionText()}</color>\nsupports <color=#4f92ff>Among Us {verText}</color>,\n" +
$"<color=#4f92ff>Among Us <b>{Main.AmongUsVersion}</b></color> is below the supported versions!\n" +
$"<color=#4f92ff>Among Us <b>{Main.AppVersion}</b></color> is below the supported versions!\n" +
$"<color=#ae1700>You may encounter minor to game breaking bugs.</color></size>");
}
}
+5 -98
View File
@@ -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}: <b>{1}</b>\n", Translator.GetString("Ping").ToUpper(), GetPingColor(AmongUsClient.Instance.Ping));
if (GameState.IsLobby && GameState.IsHost && GameState.IsVanillaServer && !GameState.IsLocalGame)
{
sb.AppendFormat("{0}: <b>{1}</b>\n", Translator.GetString("Timer").ToUpper(), GetTimeColor(GameStartManagerPatch.lobbyTimer));
}
sb.Append($"<color=#00dbdb><size=75%>BetterAmongUs {Main.GetVersionText(true)}</size></color>\n");
sb.Append("<size=68%><color=#8040bf>By</color> <color=#bc4345>The Enhanced Network</color></size>\n");
// sb.Append($"<size=50%><color=#b5b5b5>{Main.Github}</color></size>\n");
if (GameState.IsTOHEHostLobby) sb.Append($"<size=75%><color=#e197dc>TOHE Lobby</color></size>\n");
if (Main.ShowFPS.Value)
{
float FPSNum = 1.0f / Time.deltaTime;
sb.AppendFormat("<color=#0dff00><size=75%>FPS: <b>{0}</b></size></color>\n", (int)FPSNum);
}
// Add Host Info if not in lobby
if (GameState.IsInGamePlay && Host != null)
{
sb.AppendFormat("<size=75%>{0}: {1}</size>\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>();
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 = $"<color={color}>{ping} ms</color>";
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 = $"<color={color}>{GameStartManagerPatch.lobbyTimerDisplay}</color>";
return newTime;
}
}
+1 -1
View File
@@ -13,6 +13,6 @@ internal class VersionShowerPatch
{
string mark = Translator.GetString("BAUMark");
string bau = Translator.GetString("BAU");
__instance.text.text = $"<color=#0dff00>{mark}{bau}{mark} {Main.GetVersionText()}</color> <color=#ababab>~</color> {Utils.GetPlatformName(Main.PlatformData.Platform)} v{Main.AmongUsVersion}";
__instance.text.text = $"<color=#0dff00>{mark}{bau}{mark} {Main.GetVersionText()}</color> <color=#ababab>~</color> {Utils.GetPlatformName(Main.PlatformData.Platform)} v{Main.AmongUsVersion} ({Main.AppVersion})";
}
}
+3 -2
View File
@@ -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<ReferenceDataManager>.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)
{