using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using Character; using DisputeLib; using HarmonyLib; using Player; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AGDDebugHUD")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+d64b7691c3c7461419fce52522e421ee733440f6")] [assembly: AssemblyProduct("AGDDebugHUD")] [assembly: AssemblyTitle("AGDDebugHUD")] [assembly: AssemblyVersion("1.0.0.0")] namespace AGDDebugHUD; [HarmonyPatch] public static class DebugHUDInjector { [HarmonyPatch(typeof(GameSingleton), "Awake")] [HarmonyPostfix] private static void InjectDebugHUD() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if (!((Object)(object)GameObject.Find("AGD_DebugHUD") != (Object)null)) { GameObject val = new GameObject("AGD_DebugHUD"); Object.DontDestroyOnLoad((Object)val); val.AddComponent(); Debug.Log((object)"[[AGDDebugHUD]] Debug HUD injected successfully."); } } } public class DebugHUDBehaviour : MonoBehaviour { private Canvas _canvas; private GameObject _panel; private PlayerController _localPlayer; private CoreCharacterController _characterController; private CharacterMovementController _characterMovementController; private RagdollController _characterRagdollController; private Stopwatch HUDTimeStopwatch = new Stopwatch(); public double HUDTimeMs; private void Awake() { if (!Plugin.EnabledConfig.Value) { ((Behaviour)this).enabled = false; return; } RegisterDefaultLines(); CreateUI(); } private void EnsureControllers() { if (((Object)(object)_localPlayer != (Object)null && (Object)(object)_characterController != (Object)null && (Object)(object)_characterMovementController != (Object)null && (Object)(object)_characterRagdollController != (Object)null) || (Object)(object)SessionManager.Instance == (Object)null) { return; } _localPlayer = SessionManager.Instance.LocalPlayer; if (!((Object)(object)_localPlayer == (Object)null)) { _characterController = _localPlayer.serverSpawnedCharacter; if ((Object)(object)_characterController != (Object)null) { _characterMovementController = ((Component)_characterController).GetComponent(); _characterRagdollController = _characterController.Model.RagdollController; } } } private void RegisterDefaultLines() { if (Plugin.EnableGameSectionConfig.Value) { DebugHUDAPI.Header header = DebugHUDAPI.RegisterHeader("--- Game ---"); if (Plugin.EnableFPSConfig.Value) { DebugHUDAPI.RegisterCustomLine("FPS", () => $"Frame time: {Time.deltaTime * 1000f:F1}ms FPS: {1f / Time.deltaTime:F2}", header); } if (Plugin.EnableHUDFPSConfig.Value) { DebugHUDAPI.RegisterCustomLine("HUD Time", () => $"HUD time: {HUDTimeMs:F3}ms FPS impact: {1.0 / ((double)Time.deltaTime - HUDTimeMs / 1000.0) - (double)(1f / Time.deltaTime):F2}", header); } } if (Plugin.EnableNetworkSectionConfig.Value) { DebugHUDAPI.Header header2 = DebugHUDAPI.RegisterHeader("--- Network ---"); if (Plugin.EnablePingConfig.Value) { DebugHUDAPI.RegisterCustomLine("Ping", delegate { EnsureControllers(); return ((Object)(object)_localPlayer == (Object)null) ? null : $"Ping: {_localPlayer.CurrentPing.Value}"; }, header2); } } if (Plugin.EnableMovementSectionConfig.Value) { DebugHUDAPI.Header header3 = DebugHUDAPI.RegisterHeader("--- Movement ---"); if (Plugin.EnableVelocityConfig.Value) { DebugHUDAPI.RegisterCustomLine("Velocity", delegate { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) EnsureControllers(); if ((Object)(object)_characterMovementController == (Object)null) { return (string)null; } Vector3 velocity = _characterMovementController.Velocity; return $"Velocity: {((Vector3)(ref velocity)).magnitude:F2} m/s (X:{velocity.x:F2} Y:{velocity.y:F2} Z:{velocity.z:F2})"; }, header3); } if (Plugin.EnablePositionConfig.Value) { DebugHUDAPI.RegisterCustomLine("Position", delegate { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) EnsureControllers(); if ((Object)(object)_characterMovementController == (Object)null) { return (string)null; } Vector3 position = ((Component)_characterMovementController).transform.position; return $"Position: ({position.x:F2}, {position.y:F2}, {position.z:F2})"; }, header3); } } if (Plugin.EnablePhysicsSectionConfig.Value) { DebugHUDAPI.Header header4 = DebugHUDAPI.RegisterHeader("--- Physics ---"); if (Plugin.EnableRagdollStateConfig.Value) { DebugHUDAPI.RegisterCustomLine("Ragdoll State", delegate { EnsureControllers(); return ((Object)(object)_characterRagdollController == (Object)null) ? null : $"IsRagdoll: {_characterRagdollController.IsRagdollNetworked.Value} TimeInRagdollState: {_characterRagdollController.TimeInRagdollState.Elapsed}"; }, header4); } } if (!Plugin.EnableStatusSectionConfig.Value) { return; } DebugHUDAPI.Header header5 = DebugHUDAPI.RegisterHeader("--- Status ---"); if (Plugin.EnableStateConfig.Value) { DebugHUDAPI.RegisterCustomLine("State", delegate { EnsureControllers(); return ((Object)(object)_characterController == (Object)null) ? null : string.Format("Grounded: {0} Aiming: {1} Alive: {2} NoClip: {3}", ((Object)(object)_characterMovementController != (Object)null) ? _characterMovementController.IsGroundedNetworked.Value.ToString() : "?", _characterController.IsAiming, _characterController.IsAlive, _localPlayer.NoClip); }, header5); } if (!Plugin.EnableStatusEffectsConfig.Value) { return; } DebugHUDAPI.RegisterCustomLine("Status Effects", delegate { EnsureControllers(); if ((Object)(object)_characterController == (Object)null) { return (string)null; } StatusEffectController statusEffectController = _characterController.statusEffectController; if ((Object)(object)statusEffectController != (Object)null && statusEffectController.StatusEffects != null) { string[] array = (from e in (IEnumerable)statusEffectController.StatusEffects where e != null select ((object)Unsafe.As(ref e.Effect)/*cast due to .constrained prefix*/).ToString()).ToArray(); return string.Format("Status Effects ({0}): {1}", array.Length, (array.Length != 0) ? string.Join(", ", array) : "none"); } return "Status Effects (0): none"; }, header5); } private void CreateUI() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown _canvas = ((Component)this).gameObject.AddComponent(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 32767; CanvasScaler obj = ((Component)this).gameObject.AddComponent(); obj.uiScaleMode = (ScaleMode)1; obj.referenceResolution = new Vector2(1920f, 1080f); ((Component)this).gameObject.AddComponent(); _panel = new GameObject("Panel", new Type[4] { typeof(RectTransform), typeof(Image), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter) }); _panel.transform.SetParent(((Component)this).transform, false); RectTransform component = _panel.GetComponent(); component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(0f, 1f); component.pivot = new Vector2(0f, 1f); component.anchoredPosition = new Vector2(10f, -10f); ((Graphic)_panel.GetComponent()).color = new Color(0f, 0f, 0f, 0.6f); VerticalLayoutGroup component2 = _panel.GetComponent(); ((LayoutGroup)component2).padding = new RectOffset(10, 10, 6, 6); ((HorizontalOrVerticalLayoutGroup)component2).spacing = 2f; ((LayoutGroup)component2).childAlignment = (TextAnchor)0; ((HorizontalOrVerticalLayoutGroup)component2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)component2).childControlHeight = true; ContentSizeFitter component3 = _panel.GetComponent(); component3.horizontalFit = (FitMode)2; component3.verticalFit = (FitMode)2; DebugHUDAPI.Initialize(_panel, 14f); } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(Plugin.ToggleKeyConfig.Value)) { _panel.SetActive(!_panel.activeSelf); } if (_panel.activeSelf) { HUDTimeStopwatch.Restart(); DebugHUDAPI.RefreshAll(); HUDTimeStopwatch.Stop(); HUDTimeMs = HUDTimeStopwatch.Elapsed.TotalMilliseconds; } } } public static class DebugHUDAPI { public class CustomLineEntry { public enum State { Enabled, Frozen, Disabled } public string Label; public TextMeshProUGUI Tmp; public Func Getter; public State CurrentState; } public class Header { public string Label; internal TextMeshProUGUI Tmp; } private static readonly Header _defaultHeader = new Header(); private static readonly Dictionary> _lines = new Dictionary>(); private static readonly Dictionary _headerByLabel = new Dictionary(); private static readonly Dictionary _entryByLabel = new Dictionary(); private static GameObject _panel; private static float _fontSize; private static bool _initialized; public static void RegisterCustomLine(string label, Func getter, Header header = null) { if (header == null) { header = _defaultHeader; } Header header2 = null; if (_entryByLabel.TryGetValue(label, out var value)) { value.Getter = getter; foreach (KeyValuePair> line in _lines) { if (line.Value.Remove(value)) { header2 = line.Key; break; } } } else { value = new CustomLineEntry { Label = label, Getter = getter }; _entryByLabel[label] = value; } if (!_lines.ContainsKey(header)) { _lines[header] = new List(); } _lines[header].Add(value); if (_initialized && (Object)(object)_panel != (Object)null) { if ((Object)(object)value.Tmp == (Object)null) { value.Tmp = CreateLineInternal(_panel, label, _fontSize, isHeader: false); } else if (header2 != null && header2 != header) { Object.Destroy((Object)(object)((Component)value.Tmp).gameObject); value.Tmp = CreateLineInternal(_panel, label, _fontSize, isHeader: false); } } } public static Header RegisterHeader(string label) { if (_headerByLabel.TryGetValue(label, out var value)) { return value; } value = new Header { Label = label }; _headerByLabel[label] = value; _lines[value] = new List(); if (_initialized && (Object)(object)_panel != (Object)null) { value.Tmp = CreateLineInternal(_panel, label, _fontSize, isHeader: true); } return value; } public static void EnableLine(string label) { SetLineState(label, CustomLineEntry.State.Enabled); } public static void DisableLine(string label) { SetLineState(label, CustomLineEntry.State.Disabled); } public static void FreezeLine(string label) { SetLineState(label, CustomLineEntry.State.Frozen); } public static void SetLineState(string label, CustomLineEntry.State state) { if (_entryByLabel.TryGetValue(label, out var value)) { value.CurrentState = state; } } public static void Initialize(GameObject panel, float fontSize) { _panel = panel; _fontSize = fontSize; _initialized = true; foreach (KeyValuePair> line in _lines) { Header key = line.Key; if (key != _defaultHeader && (Object)(object)key.Tmp == (Object)null) { key.Tmp = CreateLineInternal(panel, key.Label, fontSize, isHeader: true); } foreach (CustomLineEntry item in line.Value) { if ((Object)(object)item.Tmp == (Object)null) { item.Tmp = CreateLineInternal(panel, item.Label, fontSize, isHeader: false); } } } } public static void RefreshAll() { foreach (KeyValuePair> line in _lines) { Header key = line.Key; if (key != _defaultHeader && (Object)(object)key.Tmp != (Object)null) { ((TMP_Text)key.Tmp).text = key.Label; } foreach (CustomLineEntry item in line.Value) { if ((Object)(object)item.Tmp == (Object)null) { continue; } switch (item.CurrentState) { case CustomLineEntry.State.Disabled: ((Component)item.Tmp).gameObject.SetActive(false); continue; case CustomLineEntry.State.Frozen: continue; } string text = item.Getter?.Invoke(); bool flag = text != null; if (flag) { ((TMP_Text)item.Tmp).text = text; } ((Component)item.Tmp).gameObject.SetActive(flag); } } } private static TextMeshProUGUI CreateLineInternal(GameObject parent, string name, float fontSize, bool isHeader) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(TextMeshProUGUI) }); val.transform.SetParent(parent.transform, false); TextMeshProUGUI component = val.GetComponent(); ((TMP_Text)component).text = name; ((TMP_Text)component).fontSize = fontSize; ((TMP_Text)component).fontStyle = (FontStyles)(isHeader ? 1 : 0); ((Graphic)component).color = (Color)(isHeader ? new Color(1f, 0.85f, 0.3f) : Color.white); ((Graphic)component).raycastTarget = false; val.AddComponent().minHeight = fontSize + 4f; return component; } } [BepInPlugin("com.unii.debugHud", "Debug HUD", "1.0.0")] public class Plugin : BaseUnityPlugin { public static ConfigEntry EnabledConfig; public static ConfigEntry ToggleKeyConfig; public static ConfigEntry EnableGameSectionConfig; public static ConfigEntry EnableFPSConfig; public static ConfigEntry EnableHUDFPSConfig; public static ConfigEntry EnableNetworkSectionConfig; public static ConfigEntry EnablePingConfig; public static ConfigEntry EnableMovementSectionConfig; public static ConfigEntry EnableVelocityConfig; public static ConfigEntry EnablePositionConfig; public static ConfigEntry EnablePhysicsSectionConfig; public static ConfigEntry EnableRagdollStateConfig; public static ConfigEntry EnableStatusSectionConfig; public static ConfigEntry EnableStateConfig; public static ConfigEntry EnableStatusEffectsConfig; private void Awake() { //IL_01f9: Unknown result type (might be due to invalid IL or missing references) EnabledConfig = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable or disable the Debug HUD overlay."); ToggleKeyConfig = ((BaseUnityPlugin)this).Config.Bind("General", "ToggleKey", (KeyCode)284, "Key to toggle the debug HUD on/off."); EnableGameSectionConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnableGameSection", true, "Enable the values under the Game header. Overrides EnableFPS and EnableHUDFPS."); EnableFPSConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnableFPS", true, "Enable showing FPS and frame time under the Game header."); EnableHUDFPSConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnableHUDFPS", true, "Enable showing HUD specific frame time and FPS impact under the Game header."); EnableNetworkSectionConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnableNetworkSection", true, "Enable the values under the Network header. Overrides EnablePing."); EnablePingConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnablePing", true, "Enable showing Ping under the Network header."); EnableMovementSectionConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnableMovementSection", true, "Enable the values under the Movement header. Overrides EnableVelocity and EnablePosition."); EnableVelocityConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnableVelocity", true, "Enable showing player velocity under the Movement header."); EnablePositionConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnablePosition", true, "Enable showing player coordinates under the Movement header."); EnablePhysicsSectionConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnablePhysicsSection", true, "Enable the values under the Physics header. Overrides EnableRagdollState."); EnableRagdollStateConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnableRagdollState", true, "Enable showing the player's ragdoll state under the Physics header."); EnableStatusSectionConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnableStatusSection", true, "Enable the values under the Status header. Overrides EnableState and EnableStatusEffects."); EnableStateConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnableState", true, "Enable showing the player's current state under the Status header."); EnableStatusEffectsConfig = ((BaseUnityPlugin)this).Config.Bind("DefaultLines", "EnableStatusEffects", true, "Enable showing active status effects under the Status header."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Debug HUD plugin loaded successfully!"); new Harmony("com.unii.debugHud").PatchAll(); } }