Decompiled source of Isanyonealive v1.3.1

Isanyonealive.dll

Decompiled 2 hours ago
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Isanyonealive")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Isanyonealive")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b25d8b43-3d95-4094-9170-f3523a42e5e1")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace LobbyPlayerStatus;

[BepInPlugin("hoppinhaulers_isanyonealive", "isanyonealive", "1.3.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
	private enum DisplayMode
	{
		All,
		AliveOnly,
		DeadOnly
	}

	private struct SimpleShortcut
	{
		public Key Main;

		public bool Ctrl;

		public bool Alt;

		public bool Shift;

		public static SimpleShortcut Parse(string raw)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			SimpleShortcut simpleShortcut = default(SimpleShortcut);
			simpleShortcut.Main = (Key)0;
			SimpleShortcut result = simpleShortcut;
			if (string.IsNullOrWhiteSpace(raw))
			{
				return result;
			}
			string[] array = raw.Split(new char[1] { '+' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = text.Trim();
				if (EqualsAny(text2, "Ctrl", "Control", "LeftCtrl", "RightCtrl", "LeftControl", "RightControl"))
				{
					result.Ctrl = true;
					continue;
				}
				if (EqualsAny(text2, "Alt", "LeftAlt", "RightAlt"))
				{
					result.Alt = true;
					continue;
				}
				if (EqualsAny(text2, "Shift", "LeftShift", "RightShift"))
				{
					result.Shift = true;
					continue;
				}
				string value = NormalizeKeyToken(text2);
				if (Enum.TryParse<Key>(value, ignoreCase: true, out Key result2))
				{
					result.Main = result2;
				}
			}
			return result;
		}

		public bool IsDown()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Main == 0)
			{
				return false;
			}
			Keyboard current = Keyboard.current;
			if (current == null)
			{
				return false;
			}
			if (Ctrl && !((ButtonControl)current.leftCtrlKey).isPressed && !((ButtonControl)current.rightCtrlKey).isPressed)
			{
				return false;
			}
			if (Alt && !((ButtonControl)current.leftAltKey).isPressed && !((ButtonControl)current.rightAltKey).isPressed)
			{
				return false;
			}
			if (Shift && !((ButtonControl)current.leftShiftKey).isPressed && !((ButtonControl)current.rightShiftKey).isPressed)
			{
				return false;
			}
			KeyControl val = current[Main];
			return val != null && ((ButtonControl)val).wasPressedThisFrame;
		}

		public override string ToString()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder();
			if (Ctrl)
			{
				stringBuilder.Append("Ctrl+");
			}
			if (Alt)
			{
				stringBuilder.Append("Alt+");
			}
			if (Shift)
			{
				stringBuilder.Append("Shift+");
			}
			stringBuilder.Append(Main);
			return stringBuilder.ToString();
		}

		private static bool EqualsAny(string s, params string[] vals)
		{
			foreach (string value in vals)
			{
				if (s.Equals(value, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static string NormalizeKeyToken(string token)
		{
			if (token.Length == 1 && char.IsDigit(token[0]))
			{
				return (token[0] == '0') ? "Digit0" : ("Digit" + token);
			}
			if (token.Equals("Esc", StringComparison.OrdinalIgnoreCase))
			{
				return "Escape";
			}
			if (token.Equals("Del", StringComparison.OrdinalIgnoreCase))
			{
				return "Delete";
			}
			if (token.Equals("Return", StringComparison.OrdinalIgnoreCase))
			{
				return "Enter";
			}
			return token;
		}
	}

	public const string ModGuid = "hoppinhaulers_isanyonealive";

	public const string ModName = "isanyonealive";

	public const string ModVersion = "1.3.0";

	internal static ManualLogSource Log;

	private Harmony _harmony;

	private GameObject _canvasGo;

	private TextMeshProUGUI _text;

	private RectTransform _textRect;

	private float _nextRefreshTime;

	private ConfigEntry<bool> _enabled;

	private ConfigEntry<float> _refreshInterval;

	private ConfigEntry<bool> _showEmptySlots;

	private ConfigEntry<float> _posX;

	private ConfigEntry<float> _posY;

	private ConfigEntry<int> _fontSize;

	private ConfigEntry<string> _toggleOverlayKey;

	private ConfigEntry<string> _cycleModeKey;

	private SimpleShortcut _toggleShortcut;

	private SimpleShortcut _cycleShortcut;

	private DisplayMode _mode = DisplayMode.All;

	private const bool DebugHotkeys = true;

	private void Awake()
	{
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		BindConfig();
		ParseHotkeysFromConfig();
		_toggleOverlayKey.SettingChanged += delegate
		{
			ParseHotkeysFromConfig();
		};
		_cycleModeKey.SettingChanged += delegate
		{
			ParseHotkeysFromConfig();
		};
		_posX.SettingChanged += delegate
		{
			ApplyUiLayout();
		};
		_posY.SettingChanged += delegate
		{
			ApplyUiLayout();
		};
		_fontSize.SettingChanged += delegate
		{
			ApplyUiLayout();
		};
		TryRegisterLethalConfigItems_Reflection();
		_harmony = new Harmony("hoppinhaulers_isanyonealive");
		_harmony.PatchAll(typeof(Plugin));
		EnsureUi();
		Log.LogInfo((object)"isanyonealive v1.3.0 loaded.");
	}

	private void OnDestroy()
	{
		try
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
		catch
		{
		}
		try
		{
			if ((Object)(object)_canvasGo != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasGo);
			}
		}
		catch
		{
		}
	}

	private void BindConfig()
	{
		_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable/disable the overlay entirely.");
		_refreshInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "RefreshIntervalSeconds", 0.5f, "Refresh interval (seconds).");
		_showEmptySlots = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowEmptySlots", false, "Show empty/null slots.");
		_posX = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "PositionX", 20f, "Overlay X (top-left anchor).");
		_posY = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "PositionY", 20f, "Overlay Y (top-left anchor).");
		_fontSize = ((BaseUnityPlugin)this).Config.Bind<int>("Display", "FontSize", 18, "Font size.");
		_toggleOverlayKey = ((BaseUnityPlugin)this).Config.Bind<string>("Hotkeys", "ToggleOverlay", "F8", "Toggle overlay hotkey (e.g. F8, LeftCtrl+F8).");
		_cycleModeKey = ((BaseUnityPlugin)this).Config.Bind<string>("Hotkeys", "CycleMode", "F9", "Cycle mode hotkey (e.g. F9, LeftCtrl+F9).");
	}

	private void Update()
	{
		EnsureUi();
		HandleHotkeys();
		if ((Object)(object)_text == (Object)null)
		{
			return;
		}
		if (!_enabled.Value)
		{
			((Behaviour)_text).enabled = false;
			return;
		}
		((Behaviour)_text).enabled = true;
		if (!(Time.unscaledTime < _nextRefreshTime))
		{
			_nextRefreshTime = Time.unscaledTime + Mathf.Max(0.05f, _refreshInterval.Value);
			((TMP_Text)_text).text = BuildStatusText();
		}
	}

	private void EnsureUi()
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Expected O, but got Unknown
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: 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_011b: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_canvasGo != (Object)null) || !((Object)(object)_text != (Object)null))
		{
			_canvasGo = new GameObject("LobbyPlayerStatus_Canvas");
			Object.DontDestroyOnLoad((Object)(object)_canvasGo);
			Canvas val = _canvasGo.AddComponent<Canvas>();
			val.renderMode = (RenderMode)0;
			val.sortingOrder = 9999;
			CanvasGroup val2 = _canvasGo.AddComponent<CanvasGroup>();
			val2.blocksRaycasts = false;
			val2.interactable = false;
			_canvasGo.AddComponent<CanvasScaler>();
			GameObject val3 = new GameObject("LobbyPlayerStatus_Text");
			val3.transform.SetParent(_canvasGo.transform, false);
			_textRect = val3.AddComponent<RectTransform>();
			_textRect.anchorMin = new Vector2(0f, 1f);
			_textRect.anchorMax = new Vector2(0f, 1f);
			_textRect.pivot = new Vector2(0f, 1f);
			_textRect.sizeDelta = new Vector2(900f, 900f);
			_text = val3.AddComponent<TextMeshProUGUI>();
			((TMP_Text)_text).enableWordWrapping = false;
			((TMP_Text)_text).richText = true;
			((TMP_Text)_text).alignment = (TextAlignmentOptions)257;
			((TMP_Text)_text).text = "Overlay initialized...";
			ApplyUiLayout();
			((Graphic)_text).raycastTarget = false;
			Log.LogInfo((object)"Overlay UI created (own Canvas).");
		}
	}

	private void ApplyUiLayout()
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_text == (Object)null) && !((Object)(object)_textRect == (Object)null))
		{
			_textRect.anchoredPosition = new Vector2(_posX.Value, 0f - _posY.Value);
			((TMP_Text)_text).fontSize = Mathf.Clamp(_fontSize.Value, 8, 80);
		}
	}

	private void HandleHotkeys()
	{
		if (Keyboard.current != null)
		{
			if (_toggleShortcut.IsDown())
			{
				_enabled.Value = !_enabled.Value;
				((BaseUnityPlugin)this).Config.Save();
				bool flag = true;
				Log.LogInfo((object)$"ToggleOverlay pressed. Enabled = {_enabled.Value}");
			}
			if (_cycleShortcut.IsDown())
			{
				_mode = (DisplayMode)((int)(_mode + 1) % 3);
				bool flag2 = true;
				Log.LogInfo((object)$"CycleMode pressed. Mode = {_mode}");
			}
		}
	}

	private string BuildStatusText()
	{
		StartOfRound instance = StartOfRound.Instance;
		if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null)
		{
			return "<b>Players:</b>\n(no StartOfRound yet)";
		}
		StringBuilder stringBuilder = new StringBuilder(256);
		stringBuilder.Append("<b>Players:</b>\n");
		PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
		for (int i = 0; i < allPlayerScripts.Length; i++)
		{
			PlayerControllerB val = allPlayerScripts[i];
			if ((Object)(object)val == (Object)null)
			{
				if (_showEmptySlots.Value)
				{
					stringBuilder.Append($"Slot {i + 1}: —\n");
				}
				continue;
			}
			string text = val.playerUsername;
			if (string.IsNullOrWhiteSpace(text))
			{
				text = $"Player {i + 1}";
			}
			bool isPlayerDead = val.isPlayerDead;
			bool flag = !val.isPlayerControlled && !isPlayerDead;
			if ((_mode != DisplayMode.AliveOnly || !(isPlayerDead || flag)) && (_mode != DisplayMode.DeadOnly || isPlayerDead))
			{
				if (isPlayerDead)
				{
					stringBuilder.Append(text + ": <color=#ff4d4d>DEAD</color>\n");
				}
				else if (flag)
				{
					stringBuilder.Append(text + ": <color=#ffd24d>NOT IN GAME</color>\n");
				}
				else
				{
					stringBuilder.Append(text + ": <color=#4dff88>ALIVE</color>\n");
				}
			}
		}
		stringBuilder.Append($"\n<alpha=#AA>Mode: {_mode} | Toggle: {_toggleOverlayKey.Value} | Cycle: {_cycleModeKey.Value}</alpha>");
		return stringBuilder.ToString().TrimEnd(Array.Empty<char>());
	}

	private void ParseHotkeysFromConfig()
	{
		_toggleShortcut = SimpleShortcut.Parse(_toggleOverlayKey.Value);
		_cycleShortcut = SimpleShortcut.Parse(_cycleModeKey.Value);
		Log.LogInfo((object)$"Hotkeys parsed: Toggle={_toggleShortcut}, Cycle={_cycleShortcut}");
	}

	private void TryRegisterLethalConfigItems_Reflection()
	{
		if (!Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig"))
		{
			return;
		}
		try
		{
			Assembly lcAsm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name.Equals("LethalConfig", StringComparison.OrdinalIgnoreCase));
			MethodInfo addMethod;
			if (!(lcAsm == null))
			{
				Type type = lcAsm.GetType("LethalConfig.LethalConfigManager", throwOnError: false);
				addMethod = type?.GetMethod("AddConfigItem", BindingFlags.Static | BindingFlags.Public);
				if (!(type == null) && !(addMethod == null))
				{
					object obj2 = New("LethalConfig.ConfigItems.Options.BaseOptions");
					SetProp(obj2, "RequiresRestart", false);
					object obj3 = New("LethalConfig.ConfigItems.Options.FloatSliderOptions");
					SetProp(obj3, "Min", 0.1f);
					SetProp(obj3, "Max", 2f);
					SetProp(obj3, "RequiresRestart", false);
					object obj4 = New("LethalConfig.ConfigItems.Options.FloatSliderOptions");
					SetProp(obj4, "Min", 0f);
					SetProp(obj4, "Max", 900f);
					SetProp(obj4, "RequiresRestart", false);
					object obj5 = New("LethalConfig.ConfigItems.Options.FloatSliderOptions");
					SetProp(obj5, "Min", 0f);
					SetProp(obj5, "Max", 700f);
					SetProp(obj5, "RequiresRestart", false);
					object obj6 = New("LethalConfig.ConfigItems.Options.IntSliderOptions");
					SetProp(obj6, "Min", 10);
					SetProp(obj6, "Max", 40);
					SetProp(obj6, "RequiresRestart", false);
					object obj7 = New("LethalConfig.ConfigItems.Options.TextInputFieldOptions");
					SetProp(obj7, "RequiresRestart", false);
					Add(NewItem("LethalConfig.ConfigItems.BoolCheckBoxConfigItem", _enabled, obj2));
					Add(NewItem("LethalConfig.ConfigItems.FloatSliderConfigItem", _refreshInterval, obj3));
					Add(NewItem("LethalConfig.ConfigItems.BoolCheckBoxConfigItem", _showEmptySlots, obj2));
					Add(NewItem("LethalConfig.ConfigItems.FloatSliderConfigItem", _posX, obj4));
					Add(NewItem("LethalConfig.ConfigItems.FloatSliderConfigItem", _posY, obj5));
					Add(NewItem("LethalConfig.ConfigItems.IntSliderConfigItem", _fontSize, obj6));
					Add(NewItem("LethalConfig.ConfigItems.TextInputFieldConfigItem", _toggleOverlayKey, obj7));
					Add(NewItem("LethalConfig.ConfigItems.TextInputFieldConfigItem", _cycleModeKey, obj7));
					Log.LogInfo((object)"LethalConfig UI registered (reflection).");
				}
			}
			void Add(object item)
			{
				if (item != null)
				{
					addMethod.Invoke(null, new object[1] { item });
				}
			}
			object New(string typeName)
			{
				return Activator.CreateInstance(lcAsm.GetType(typeName, throwOnError: false));
			}
			object NewItem(string typeName, object entry, object options)
			{
				return Activator.CreateInstance(lcAsm.GetType(typeName, throwOnError: false), entry, options);
			}
		}
		catch (Exception arg)
		{
			Log.LogWarning((object)$"LethalConfig UI registration failed: {arg}");
		}
		static void SetProp(object obj, string prop, object val)
		{
			if (obj != null)
			{
				PropertyInfo property = obj.GetType().GetProperty(prop, BindingFlags.Instance | BindingFlags.Public);
				if (property != null && property.CanWrite)
				{
					property.SetValue(obj, val);
				}
			}
		}
	}
}