Decompiled source of HowardSkillIssue v1.0.1

Mods/HowardSkillIssue.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using HarmonyLib;
using HowardIssue;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppRUMBLE.Environment.Howard;
using Il2CppRUMBLE.Managers;
using Il2CppRUMBLE.Players;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(HOWARD), "HowardSkillIssue", "1.0.1", "Nano", null)]
[assembly: MelonColor(127, 52, 235, 131)]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace HowardIssue
{
	public class HOWARD : MelonMod
	{
		[HarmonyPatch]
		private static class HowardSpeedrunPlayerDeathBridge
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method("HowardSpeedrun.main+Patch0:Postfix", (Type[])null, (Type[])null);
			}

			private static bool Prepare()
			{
				return TargetMethod() != null;
			}

			private static void Postfix(int step)
			{
				Instance?.OnHowardFightStateChanged(step);
			}
		}

		[HarmonyPatch]
		private static class HowardSpeedrunHowardDeathBridge
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method("HowardSpeedrun.main+Patch1:Postfix", (Type[])null, (Type[])null);
			}

			private static bool Prepare()
			{
				return TargetMethod() != null;
			}

			private static void Postfix()
			{
				Instance?.OnHowardDamageEvent(null);
			}
		}

		private const float ColumnHalfGap = 0.1f;

		private string _playerName = "Player";

		private int _playerDeaths;

		private int _howardDeaths;

		private bool _howardFightActive;

		private bool _howardDeathCountedThisFight;

		private bool _playerDeathCountedThisFight;

		private int _lastLocalPlayerHp = -1;

		private Howard _howard;

		private readonly string _saveFolder = "UserData\\HowardSkillIssue";

		private readonly string _saveFileName = "HowardSkillIssue.txt";

		private GameObject _worldUiRoot;

		private GameObject _rotationPivot;

		private TextMeshPro _playerTextMesh;

		private TextMeshPro _howardTextMesh;

		private CounterColumnEditor _playerEditor;

		private CounterColumnEditor _howardEditor;

		private TMP_FontAsset _rumbleUiFont;

		private float _nextNameRefreshTime;

		private MelonPreferences_Category _prefsCategory;

		private MelonPreferences_Entry<string> _nameOverrideEntry;

		private PlayerManager _playerManager;

		private PropertyInfo _playerManagerInstanceProperty;

		private bool _resolvedPlayerManagerInstanceProperty;

		private string _currentScene = "Loader";

		internal static HOWARD Instance { get; private set; }

		public override void OnInitializeMelon()
		{
			Instance = this;
			_prefsCategory = MelonPreferences.CreateCategory("HowardSkillIssue");
			_nameOverrideEntry = _prefsCategory.CreateEntry<string>("DisplayNameOverride", "", (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			_playerName = "Player";
			ClassInjector.RegisterTypeInIl2Cpp<CounterColumnEditor>();
			LoadCounters();
			((MelonBase)this).HarmonyInstance.PatchAll(typeof(HOWARD).Assembly);
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			_currentScene = sceneName ?? "Unknown";
			_howardFightActive = false;
			_howardDeathCountedThisFight = false;
			_lastLocalPlayerHp = -1;
			_howard = null;
			if ((Object)(object)_worldUiRoot != (Object)null)
			{
				Object.Destroy((Object)(object)_worldUiRoot);
				_worldUiRoot = null;
				_rotationPivot = null;
				_playerTextMesh = null;
				_howardTextMesh = null;
				_playerEditor = null;
				_howardEditor = null;
			}
		}

		public override void OnApplicationQuit()
		{
			SaveCounters();
			((MelonBase)this).OnApplicationQuit();
		}

		public override void OnUpdate()
		{
			if (_currentScene != "Gym")
			{
				return;
			}
			if (Time.unscaledTime >= _nextNameRefreshTime)
			{
				_nextNameRefreshTime = Time.unscaledTime + 2f;
				RefreshPlayerNameFromGame();
			}
			TrackPlayerDeathDuringHowardFight();
			if ((Object)(object)_worldUiRoot == (Object)null)
			{
				TryCreateWorldUi();
			}
			if (!((Object)(object)_worldUiRoot == (Object)null))
			{
				Camera val = FindActiveCamera();
				if ((Object)(object)val != (Object)null)
				{
					ApplyTextFacing(val);
				}
				UpdateWorldText();
			}
		}

		private void TryCreateWorldUi()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			Camera val = FindActiveCamera();
			if (!((Object)(object)val == (Object)null))
			{
				_worldUiRoot = new GameObject("HowardDeathCounterUI");
				_worldUiRoot.transform.localScale = Vector3.one * 0.05f;
				_rotationPivot = new GameObject("RotationPivot");
				_rotationPivot.transform.SetParent(_worldUiRoot.transform, false);
				_rotationPivot.transform.localPosition = Vector3.zero;
				_playerTextMesh = CreateColumnText("PlayerColumn", new Vector3(-0.1f, 0f, 0f), isLeftColumn: true);
				_howardTextMesh = CreateColumnText("HowardColumn", new Vector3(0.1f, 0f, 0f), isLeftColumn: false);
				ApplySceneAnchor(val);
				ApplySceneColumnPositions();
				UpdateWorldText();
				MelonLogger.Msg("[HowardSkillIssue] UI created for scene '" + _currentScene + "'.");
			}
		}

		private TextMeshPro CreateColumnText(string name, Vector3 localOffset, bool isLeftColumn)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_002b: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			((Object)val).name = name;
			val.transform.SetParent(_worldUiRoot.transform, false);
			val.transform.localPosition = localOffset;
			val.transform.localRotation = Quaternion.identity;
			val.transform.localScale = new Vector3(2.5f, 2.5f, 2.5f);
			Type val2 = null;
			string[] array = new string[3] { "TMPro.TextMeshPro, Unity.TextMeshPro", "TMPro.TextMeshPro, UnityEngine.TextCoreTextEngineModule", "TextMeshPro, Unity.TextMeshPro" };
			foreach (string text in array)
			{
				val2 = Type.GetType(text);
				if (val2 != (Type)null)
				{
					MelonLogger.Msg($"[HowardSkillIssue] Using TMP type '{text}' for '{name}'.");
					break;
				}
			}
			if (val2 == (Type)null)
			{
				MelonLogger.Warning("[HowardSkillIssue] Could not find TextMeshPro runtime type for '" + name + "'.");
				return null;
			}
			Component val3 = val.AddComponent(val2);
			TextMeshPro val4 = (((Object)(object)val3 != (Object)null) ? ((Il2CppObjectBase)val3).TryCast<TextMeshPro>() : null);
			if ((Object)(object)val4 == (Object)null)
			{
				MelonLogger.Warning("[HowardSkillIssue] Failed to get TextMeshPro for '" + name + "'.");
				return null;
			}
			CounterColumnEditor counterColumnEditor = val.AddComponent<CounterColumnEditor>();
			counterColumnEditor.target = val4;
			counterColumnEditor.columnName = name;
			counterColumnEditor.useCustomText = false;
			if (name == "PlayerColumn")
			{
				_playerEditor = counterColumnEditor;
			}
			else if (name == "HowardColumn")
			{
				_howardEditor = counterColumnEditor;
			}
			((TMP_Text)val4).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val4).enableWordWrapping = false;
			((TMP_Text)val4).fontSize = 5f;
			TMP_FontAsset val5 = ResolveRumbleUiFont();
			if ((Object)(object)val5 != (Object)null)
			{
				((TMP_Text)val4).font = val5;
			}
			((Graphic)val4).color = Color.white;
			((TMP_Text)val4).SetOutlineColor(new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue));
			((TMP_Text)val4).outlineWidth = 0.2f;
			MelonLogger.Msg($"[HowardSkillIssue] Created text object '{name}' at local {localOffset}.");
			return val4;
		}

		private TMP_FontAsset ResolveRumbleUiFont()
		{
			if ((Object)(object)_rumbleUiFont != (Object)null)
			{
				return _rumbleUiFont;
			}
			try
			{
				Il2CppArrayBase<TMP_FontAsset> val = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
				if (val == null || val.Length == 0)
				{
					return null;
				}
				foreach (TMP_FontAsset item in val)
				{
					if (!((Object)(object)item == (Object)null) && !string.IsNullOrWhiteSpace(((Object)item).name))
					{
						string name = ((Object)item).name;
						if (name.IndexOf("TMP_GoodDogPlain", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("GoodDogPlain", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Good Dog Plain", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							_rumbleUiFont = item;
							MelonLogger.Msg("[HowardSkillIssue] Using RUMBLE UI font '" + name + "'.");
							return _rumbleUiFont;
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private void ApplySceneAnchor(Camera cam)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_worldUiRoot == (Object)null) && !((Object)(object)cam == (Object)null))
			{
				Vector3 position = default(Vector3);
				Vector3 localScale = default(Vector3);
				if (_currentScene == "Gym")
				{
					((Vector3)(ref position))..ctor(8.858f, 2.7522f, -24.1645f);
					((Vector3)(ref localScale))..ctor(1f, 1f, 1.318f);
				}
				else if (_currentScene == "Map0")
				{
					((Vector3)(ref position))..ctor(17.951f, 2.15f, 3.2618f);
					localScale = Vector3.one * 0.1f;
				}
				else if (_currentScene == "Map1")
				{
					((Vector3)(ref position))..ctor(2.8163f, 6.1f, 10.7819f);
					localScale = Vector3.one * 0.1f;
				}
				else
				{
					Transform transform = ((Component)cam).transform;
					position = transform.position + transform.forward * 2f + transform.up * 0.2f;
					localScale = Vector3.one * 0.06f;
				}
				_worldUiRoot.transform.position = position;
				_worldUiRoot.transform.localScale = localScale;
				Quaternion val = Quaternion.LookRotation(((Component)cam).transform.position - _worldUiRoot.transform.position, Vector3.up);
				_worldUiRoot.transform.rotation = val * Quaternion.Euler(0f, 180f, 0f);
			}
		}

		private void ApplySceneColumnPositions()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_playerTextMesh == (Object)null) && !((Object)(object)_howardTextMesh == (Object)null))
			{
				if (_currentScene == "Gym")
				{
					_playerTextMesh.transform.position = new Vector3(5.7545f, 1.6522f, -24.1384f);
					_howardTextMesh.transform.position = new Vector3(13.3516f, 1.6522f, -20.4851f);
				}
				UpdateRotationPivotPosition();
			}
		}

		private void ApplyTextFacing(Camera cam)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cam == (Object)null)
			{
				return;
			}
			UpdateRotationPivotPosition();
			if (!((Object)(object)_rotationPivot == (Object)null))
			{
				Quaternion rotation = Quaternion.LookRotation(((Component)cam).transform.position - _rotationPivot.transform.position, Vector3.up) * Quaternion.Euler(0f, 180f, 0f);
				if ((Object)(object)_playerTextMesh != (Object)null && ((Object)(object)_playerEditor == (Object)null || !_playerEditor.freezeRotation))
				{
					_playerTextMesh.transform.rotation = rotation;
				}
				if ((Object)(object)_howardTextMesh != (Object)null && ((Object)(object)_howardEditor == (Object)null || !_howardEditor.freezeRotation))
				{
					_howardTextMesh.transform.rotation = rotation;
				}
			}
		}

		private void UpdateRotationPivotPosition()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_rotationPivot == (Object)null) && !((Object)(object)_playerTextMesh == (Object)null) && !((Object)(object)_howardTextMesh == (Object)null))
			{
				_rotationPivot.transform.position = (_playerTextMesh.transform.position + _howardTextMesh.transform.position) * 0.5f;
			}
		}

		private void UpdateWorldText()
		{
			if ((Object)(object)_playerTextMesh != (Object)null)
			{
				if ((Object)(object)_playerEditor != (Object)null && _playerEditor.useCustomText)
				{
					((TMP_Text)_playerTextMesh).text = _playerEditor.GetDisplayText();
				}
				else
				{
					((TMP_Text)_playerTextMesh).text = $"{_playerName} Deaths\n{_playerDeaths}";
				}
			}
			if ((Object)(object)_howardTextMesh != (Object)null)
			{
				if ((Object)(object)_howardEditor != (Object)null && _howardEditor.useCustomText)
				{
					((TMP_Text)_howardTextMesh).text = _howardEditor.GetDisplayText();
					return;
				}
				((TMP_Text)_howardTextMesh).text = $"Howard Deaths\n{_howardDeaths}";
			}
		}

		private string GetSavePath()
		{
			return Path.Combine(_saveFolder, _saveFileName);
		}

		private void LoadCounters()
		{
			try
			{
				if (!Directory.Exists(_saveFolder))
				{
					Directory.CreateDirectory(_saveFolder);
				}
				string savePath = GetSavePath();
				if (!File.Exists(savePath))
				{
					return;
				}
				string[] array = File.ReadAllLines(savePath);
				if (array != null && array.Length != 0)
				{
					if (array.Length != 0 && int.TryParse(array[0], out var result))
					{
						_playerDeaths = Mathf.Max(0, result);
					}
					if (array.Length > 1 && int.TryParse(array[1], out var result2))
					{
						_howardDeaths = Mathf.Max(0, result2);
					}
					MelonLogger.Msg($"[HowardSkillIssue] Loaded counters. Player: {_playerDeaths}, Howard: {_howardDeaths}");
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[HowardSkillIssue] Failed to load counters: " + ex.Message);
			}
		}

		private void SaveCounters()
		{
			try
			{
				if (!Directory.Exists(_saveFolder))
				{
					Directory.CreateDirectory(_saveFolder);
				}
				File.WriteAllLines(GetSavePath(), new string[2]
				{
					_playerDeaths.ToString(),
					_howardDeaths.ToString()
				});
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[HowardSkillIssue] Failed to save counters: " + ex.Message);
			}
		}

		private void RefreshPlayerNameFromGame()
		{
			string text = _nameOverrideEntry?.Value;
			if (IsPlausiblePlayerName(text))
			{
				_playerName = text.Trim();
				return;
			}
			string text2 = TryReadNameFromPlayerManager();
			if (IsPlausiblePlayerName(text2))
			{
				_playerName = text2;
				return;
			}
			string text3 = TryReadNameFromTextMeshes();
			if (IsPlausiblePlayerName(text3))
			{
				_playerName = text3;
			}
		}

		private string TryReadNameFromPlayerManager()
		{
			try
			{
				if (!EnsurePlayerManager())
				{
					return null;
				}
				List<Player> allPlayers = _playerManager.AllPlayers;
				if (allPlayers == null || allPlayers.Count <= 0)
				{
					return null;
				}
				if (allPlayers.Count == 1)
				{
					Player obj = allPlayers[0];
					object result;
					if (obj == null)
					{
						result = null;
					}
					else
					{
						PlayerData data = obj.Data;
						if (data == null)
						{
							result = null;
						}
						else
						{
							GeneralData generalData = data.GeneralData;
							result = ((generalData != null) ? generalData.PublicUsername : null);
						}
					}
					return (string)result;
				}
				for (int i = 0; i < allPlayers.Count; i++)
				{
					Player obj2 = allPlayers[i];
					object obj3;
					if (obj2 == null)
					{
						obj3 = null;
					}
					else
					{
						PlayerData data2 = obj2.Data;
						if (data2 == null)
						{
							obj3 = null;
						}
						else
						{
							GeneralData generalData2 = data2.GeneralData;
							obj3 = ((generalData2 != null) ? generalData2.PublicUsername : null);
						}
					}
					string text = (string)obj3;
					if (IsPlausiblePlayerName(text))
					{
						return text;
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private Camera FindActiveCamera()
		{
			try
			{
				if (EnsurePlayerManager() && _playerManager.localPlayer != null && (Object)(object)_playerManager.localPlayer.Controller != (Object)null && (Object)(object)_playerManager.localPlayer.Controller.PlayerCamera != (Object)null)
				{
					GameObject gameObject = ((Component)_playerManager.localPlayer.Controller.PlayerCamera).gameObject;
					if ((Object)(object)gameObject != (Object)null)
					{
						Camera component = gameObject.GetComponent<Camera>();
						if ((Object)(object)component != (Object)null)
						{
							return component;
						}
					}
				}
			}
			catch
			{
			}
			if ((Object)(object)Camera.main != (Object)null)
			{
				return Camera.main;
			}
			return null;
		}

		private static string TryReadNameFromTextMeshes()
		{
			try
			{
				Il2CppArrayBase<TextMesh> val = Resources.FindObjectsOfTypeAll<TextMesh>();
				if (val == null || val.Length == 0)
				{
					return null;
				}
				TextMesh? obj = (from t in (IEnumerable<TextMesh>)val
					where (Object)(object)t != (Object)null && IsPlausiblePlayerName(t.text)
					orderby t.fontSize descending, t.characterSize descending
					select t).FirstOrDefault();
				return (obj == null) ? null : obj.text?.Trim();
			}
			catch
			{
				return null;
			}
		}

		private static bool IsPlausiblePlayerName(string value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return false;
			}
			string text = value.Trim();
			if (text.Length < 2 || text.Length > 24)
			{
				return false;
			}
			if (text.IndexOf("death", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return false;
			}
			if (text.IndexOf("howard", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return false;
			}
			bool result = false;
			string text2 = text;
			foreach (char c in text2)
			{
				if (char.IsLetterOrDigit(c))
				{
					result = true;
				}
				else if (c != '_' && c != '-' && c != '.')
				{
					return false;
				}
			}
			return result;
		}

		private void OnHowardFightStateChanged(int step)
		{
			switch (step)
			{
			case 0:
				_howardFightActive = true;
				_howardDeathCountedThisFight = false;
				_playerDeathCountedThisFight = false;
				_lastLocalPlayerHp = TryGetLocalPlayerHp();
				MelonLogger.Msg("[HowardSkillIssue] Howard fight started.");
				break;
			case 1:
			{
				int num = TryGetLocalPlayerHp();
				if (!_howardDeathCountedThisFight)
				{
					Howard obj = TryGetHoward();
					if (!(((obj != null) ? obj.currentHp : 1f) <= 0f) && !_playerDeathCountedThisFight && (num <= 0 || num == -1))
					{
						_playerDeathCountedThisFight = true;
						_playerDeaths++;
						SaveCounters();
						UpdateWorldText();
						MelonLogger.Msg($"[HowardSkillIssue] Player death detected at fight end. Total: {_playerDeaths}");
					}
				}
				_howardFightActive = false;
				_howardDeathCountedThisFight = false;
				_playerDeathCountedThisFight = false;
				_lastLocalPlayerHp = -1;
				MelonLogger.Msg("[HowardSkillIssue] Howard fight ended.");
				break;
			}
			}
		}

		private void OnHowardDamageEvent(Howard howardFromPatch)
		{
			if (_howardFightActive && !_howardDeathCountedThisFight)
			{
				Howard val = (((Object)(object)howardFromPatch != (Object)null) ? howardFromPatch : TryGetHoward());
				if (!((Object)(object)val == (Object)null) && !(val.currentHp > 0f))
				{
					_howardDeathCountedThisFight = true;
					_howardDeaths++;
					SaveCounters();
					UpdateWorldText();
					MelonLogger.Msg($"[HowardSkillIssue] Howard death detected. Total: {_howardDeaths}");
				}
			}
		}

		private Howard TryGetHoward()
		{
			try
			{
				if ((Object)(object)_howard != (Object)null)
				{
					return _howard;
				}
				GameObject val = GameObject.Find("INTERACTABLES/Howard");
				if ((Object)(object)val == (Object)null)
				{
					val = GameObject.Find("Game Instance/INTERACTABLES/Howard");
				}
				_howard = (((Object)(object)val != (Object)null) ? val.GetComponent<Howard>() : null);
				return _howard;
			}
			catch
			{
				return null;
			}
		}

		private int TryGetLocalPlayerHp()
		{
			try
			{
				if (!EnsurePlayerManager())
				{
					return -1;
				}
				if (_playerManager.localPlayer == null || _playerManager.localPlayer.Data == null)
				{
					return -1;
				}
				return _playerManager.localPlayer.Data.HealthPoints;
			}
			catch
			{
				return -1;
			}
		}

		private bool EnsurePlayerManager()
		{
			if ((Object)(object)_playerManager != (Object)null)
			{
				return true;
			}
			try
			{
				if (!_resolvedPlayerManagerInstanceProperty)
				{
					_playerManagerInstanceProperty = typeof(PlayerManager).GetProperty("instance", BindingFlags.Static | BindingFlags.Public);
					_resolvedPlayerManagerInstanceProperty = true;
				}
				if (_playerManagerInstanceProperty != null)
				{
					ref PlayerManager playerManager = ref _playerManager;
					object? value = _playerManagerInstanceProperty.GetValue(null, null);
					playerManager = (PlayerManager)((value is PlayerManager) ? value : null);
					if ((Object)(object)_playerManager != (Object)null)
					{
						return true;
					}
				}
			}
			catch
			{
			}
			GameObject val = GameObject.Find("Game Instance/Initializable/PlayerManager");
			_playerManager = (((Object)(object)val != (Object)null) ? val.GetComponent<PlayerManager>() : null);
			return (Object)(object)_playerManager != (Object)null;
		}

		private void TrackPlayerDeathDuringHowardFight()
		{
			if (!_howardFightActive)
			{
				return;
			}
			int num = TryGetLocalPlayerHp();
			if (num < 0)
			{
				return;
			}
			if (_lastLocalPlayerHp < 0)
			{
				_lastLocalPlayerHp = num;
				return;
			}
			if (_lastLocalPlayerHp > 0 && num <= 0)
			{
				_playerDeathCountedThisFight = true;
				_playerDeaths++;
				SaveCounters();
				UpdateWorldText();
				MelonLogger.Msg($"[HowardSkillIssue] Player death detected. Total: {_playerDeaths}");
			}
			_lastLocalPlayerHp = num;
		}
	}
	public class CounterColumnEditor : MonoBehaviour
	{
		public TextMeshPro target;

		public string columnName = "Column";

		public bool useCustomText;

		public string customHeader = "Header";

		public string customValue = "0";

		public bool freezeRotation;

		public CounterColumnEditor(IntPtr ptr)
			: base(ptr)
		{
		}

		public CounterColumnEditor()
			: base(ClassInjector.DerivedConstructorPointer<CounterColumnEditor>())
		{
			ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this);
		}

		public string GetDisplayText()
		{
			return customHeader + "\n" + customValue;
		}
	}
}